Iterating Through a List of Functions in Python [duplicate] - python

This question already has answers here:
Creating a list of methods to be executed in Python
(4 answers)
Closed 4 months ago.
Let's say I have the following code:
string = "XxXxXx"
print(string.lower())
print(string.upper())
How could I use a list instead along the lines of:
string = "XxXxXx"
list = [lower(), upper()]
for i in list:
print(string.i)
Obviously the code above does not work at all and the problem I'm working on is way more complicated. But if I could make the example above work, it would really take care of my problem!

Functions (and methods) are first class objects in python. You can therefore store them in a list just like you would anything else.
If you want to be able to apply the functions to arbitrary strings, use the unbound function objects in the class:
string = "XxXxXx"
func_list = [str.lower, str.upper]
for i in func_list:
print(i(string))
If you want to only apply the functions to your special string, you can store the bound methods in a list instead:
string = "XxXxXx"
func_list = [string.lower, string.upper]
for i in func_list:
print(i())
In both cases, the () operator is what calls the function. The function name by itself is a reference to the object. In the first case, the . operator does not do anything surprising. In the second case, since you invoke it on an instance of a class, it binds the function object in the class to the instance, creating a bound method that has an implicit self argument.

Related

How can I add methods to floats and integers? [duplicate]

This question already has answers here:
What does it mean when the parentheses are omitted from a function or method call?
(6 answers)
Closed 2 years ago.
I'm a beginner to Python and programming in general. Right now, I'm having trouble understanding the function of empty parentheses at the end of method names, built-in or user-created. For example, if I write:
print "This string will now be uppercase".upper()
...why is there an empty pair of parentheses after "upper?" Does it do anything? Is there a situation in which one would put something in there? Thanks!
Because without those you are only referencing the method object. With them you tell Python you wanted to call the method.
In Python, functions and methods are first-order objects. You can store the method for later use without calling it, for example:
>>> "This string will now be uppercase".upper
<built-in method upper of str object at 0x1046c4270>
>>> get_uppercase = "This string will now be uppercase".upper
>>> get_uppercase()
'THIS STRING WILL NOW BE UPPERCASE'
Here get_uppercase stores a reference to the bound str.upper method of your string. Only when we then add () after the reference is the method actually called.
That the method takes no arguments here makes no difference. You still need to tell Python to do the actual call.
The (...) part then, is called a Call expression, listed explicitly as a separate type of expression in the Python documentation:
A call calls a callable object (e.g., a function) with a possibly empty series of arguments.
the parentheses indicate that you want to call the method
upper() returns the value of the method applied to the string
if you simply say upper, then it returns a method, not the value you get when the method is applied
>>> print "This string will now be uppercase".upper
<built-in method upper of str object at 0x7ff41585fe40>
>>>
upper() is a command asking the upper method to run, while upper is a reference to the method itself. For example,
upper2 = 'Michael'.upper
upper2() # does the same thing as 'Michael'.upper() !

How to dynamically access a class and its methods from an input? [duplicate]

This question already has answers here:
How to get class object from class name string in the same module?
(3 answers)
Closed last year.
I am creating a python CLI, where user can provide an operation they want to perform, for eg:
sum 10 15
In my code, I have defined my classes as follows:
class Operation:
# common stuff
pass
class Sum(Operation):
identifier = "sum"
def perform(a, b):
return a + b
class Difference(Operation):
identifier = "diff"
def perform(a, b):
return a - b
Now, in my CLI, if I type sum 10 15 I want to return the result of Sum.perform(10, 15) and similarly if I type diff 10 15, I return the result of Difference.perform(10, 15), as sum is the identifier of class Sum and diff is the identifier of class Difference.
How do I dynamically access the class and its perform method, when I get the input directly from user input?
Classes in Python are first-class citizens, meaning they can be used as standard objects. In particular we can simply store them in a dictionary:
my_dict = {
'sum': Sum,
'diff': Difference,
}
and so on. Then when you get the operation name as string from command line you simply do
my_dict[op_name].perform(a, b)
Note that this is a very basic (and you will soon see problematic, e.g. not all operators accept two arguments) approach to what is known as parsing and abstract syntax trees. This is a huge topic, a bit hard but also very interesting. I encourage you to read about it.
// EDIT: If you want to keep identifier on the class, then you can apply a simple class decorator:
my_dict = {}
def autoregister(cls):
# It would be good idea to check whether we
# overwrite an entry here, to avoid errors.
my_dict[cls.identifier] = cls
return cls
#autoregister
class Sum(Operation):
identifier = "sum"
def perform(a, b):
return a + b
print(my_dict)
You have to remember though to import all classes before you use my_dict. In my opinion an explicit dict is easier to maintain.
Reading your comment, I think you need to interpret the input. The way I would go about this is splitting the input by spaces (based on your example), and then checking that list. For example:
# This is the place you called the input:
input_unsplit = input("Enter your command and args")
input_list = input_unsplit.split(" ")
# Check the first word to see what function we're calling
if("sum") in input_list[0].lower():
result = Sum.perform(input_list[1], input_list[2])
print(result)
# this logic can be applied to other functions as well.
This is a simple solution that could be hard to scale.
=== EDITED ===
I have more to add.
If used correctly, dir() can make a list of defined classes up to a certain point in the code. I wrote a calculator for my precal class, and in it I chose to use dir after defining all the math classes, and then if the name met certain conditions (i.e not main), it would be appended to a list of valid args to pass. You can modify your classes to include some kind of operator name property:
def class Addition:
self.op_name = "sum"
and then perform to take in an array:
def perform(numbers):
return numbers[0] + numbers [1]
To solve many of your scalability issues. Then, after declaring your classes, use dir() in a for loop to append to that valid array, like so:
valid_names = []
defined_names = dir()
for name in defined_names:
if '_' not in name:
if name not in ("sys","argparse","<any other imported module/defined var>"):
valid_names.append(name)
Note that making this step work for you is all in the placement in the script. it's a bit tedious, but works flawlessly if handled correctly (in my experience).
Then, you can use eval (safe in this context) to call the method you want:
# get input here
for name in defined_names:
if eval(name).op_name == input_list[0].lower():
eval(name).perform(input_list)
This should be a fairly easy-to-scale solution. Just watch that you keep the dir check up to date, and everything else just... works.

Class variable in `for`...`if` expression fails in python [duplicate]

This question already has answers here:
Accessing class variables from a list comprehension in the class definition
(8 answers)
Closed 3 years ago.
Take this simple code:
class A(object):
numbers = [1, 2, 3]
numberscopy = numbers[:]
print(*(a for a in numberscopy))
print(*(a for a in numberscopy if a in numbers))
I define the numbers variable inside the class. I can then use it to do other things, like make a copy, iterate over it, and print its contents.
But the last line, with the for-if statement, fails with NameError: global name 'numbers' is not defined. Not numberscopy, just numbers.
I tried on both python 2.7.14+ (with print_function imported) and 3.7.0, with the same result.
Why does this happen? Is it intended to work this way?
The code inside class-bodies is somewhat messed in Python. It is not so much a bug, but an "implementation problem that got weird".
The problem being that: code usually runs at module level, or inside functions - when inside functions, there are well-defined "local" variables.
Code inside class bodies also run with a "local" scope - but if one creates functions that are run while the class body is being processed, these do not
"see" the outer-level variables. And generator expressions, as do comprehensions (in Python 3, Python 2 is another language, which is on its way out, let's not complicate stuff). The expression used to create the iterator to the for inside the generator is run in a scope where it "sees" the outer variables. The main expression and if expressions themselves are inside the generator, and can't "see" those variables.
So, a workaround, if comprehensions are needed inside a class body is to have an intermediary function inside the class body, just to generate the values and variables you need, and have line to call that and update the class's own variables with the local namespace of that inner function:
class A:
def create_vals():
numbers = [1, 2, 3]
numbers_copy = numbers[:]
values = list(a for a in numbers if a in numbers_copy)
return locals()
locals().update(create_vals())
del create_vals
So, inside the temporary create_vals function (it is not a method), usual scope-nesting rules apply - and with the last two lines we copy the created variables to the class itself, and remove the temporary function.

Is it possible to empty a string using functions in python?

Is it possible to empty a string using functions in python?
For example:
otherText="hello"
def foo(text):
text=""
foo(otherText)
print(otherText)
prints
hello
instead of an empty string. Is there a way to empty the string without assigning it a return value or using global variables?
It's not possible. There are 2 reasons for that
Python strings are immutable
Python implements a so called "call by sharing" evaluation strategy:
The semantics of call by sharing differ from call by reference in that assignments to function arguments within the function aren't visible to the caller
As noted by zerkms, it is strictly not possible, python does not pass argument by reference.
There are a few tricks that can be used as workarounds, such as passing a list or object, containing your string.
otherText=["hello"]
def foo(text):
text[0]="Goodbye string"
foo(otherText)
print(otherText) //Goodbye string

passing object to object [duplicate]

This question already has answers here:
Can you explain closures (as they relate to Python)?
(13 answers)
Closed 6 years ago.
I am trying to understand the background of why the following works:
def part_string(items):
if len(items) == 1:
item = items[0]
def g(obj):
return obj[item]
else:
def g(obj):
return tuple(obj[item] for item in items)
return g
my_indexes = (2,1)
my_string = 'ABCDEFG'
function_instance = part_string(my_indexes)
print(function_instance(my_string))
# also works: print(part_string(my_indexes)(my_string))
how come I can pass my_string to function_instance object even though I already passed my_indexes attributes to part_string() when creating function_instance? why Python accepts my_string implicitly?
I guess it has something to do with the following, so more questions here:
what is obj in g(obj)? can this be something other e.g. g(stuff) (like with self which is just a convention)?
what if I want to pass 2 objects to function_instance? how do I refer to them in g(obj)?
Can You recommend some reading on this?
What you're encountering is a closure.
When you write part_string(my_indexes) you're creating a new function, and upon calling it, you use the old variables you gave to part_string together with the new variables given to function_instance.
You may name the inner function whatever you want, and there is no convention. (obj is used in here but it can be pie. There are no conventions for this except func for function closures (decorators).
If you wish to pass two variables to the function, you may define two variables to the g(obj) function:
def g(var1, var2):
...
Here's some more info regarding closures in python.

Categories