I have this following block of code and I am getting this message in the shell...
"function word_switch at 0x102b67a70"
What does this mean and why does Python print this instead of returning the function?
Thanks
D= ['foo', 'bar', 'OMG']
def word_switch (D: list) -> list:
for i in D:
reversed(i)
return word_switch
print(word_switch(D))
You need to generate the reversed list and return it, not the function itself. You can do this
D = ['foo', 'bar', 'OMG']
def word_switch (D: list) -> list:
return ["".join(reversed(i)) for i in D]
#return [i[::-1] for i in D] # Using slicing
print(word_switch(D))
Output
['oof', 'rab', 'GMO']
What does it mean? The output means that the function word_switch lives in that memory position.
Why are you getting it? Because you asked for it. Beware that in the way your function is defined, when you call it you get the function object itself and then you print it.
It happens the very same thing every time you print a function object, for instance:
>>> def f(x):
... x
>>> print f
<function f at 0xb72eda3c>
>>>
If what you want is just reverse a list you can simply use the reverse method of lists objects as suggested in the comments to the OP. It is not necessary to create you own function. If , for some reason, you need your own function then you can write it in the way suggested by #thefourtheye in his answer.
Related
When you define a function in Python with an array parameter, what is the scope of that parameter?
This example is taken from the Python tutorial:
def f(a, L=[]):
L.append(a)
return L
print f(1)
print f(2)
print f(3)
Prints:
[1]
[1, 2]
[1, 2, 3]
I'm not quite sure if I understand what's happening here. Does this mean that the scope of the array is outside of the function? Why does the array remember its values from call to call? Coming from other languages, I would expect this behavior only if the variable was static. Otherwise it seems it should be reset each time. And actually, when I tried the following:
def f(a):
L = []
L.append(a)
return L
I got the behavior I expected (the array was reset on each call).
So it seems to me that I just need the line def f(a, L=[]): explained - what is the scope of the L variable?
The scope is as you would expect.
The perhaps surprising thing is that the default value is only calculated once and reused, so each time you call the function you get the same list, not a new list initialized to [].
The list is stored in f.__defaults__ (or f.func_defaults in Python 2.)
def f(a, L=[]):
L.append(a)
return L
print f(1)
print f(2)
print f(3)
print f.__defaults__
f.__defaults__ = (['foo'],) # Don't do this!
print f(4)
Result:
[1]
[1, 2]
[1, 2, 3]
([1, 2, 3],)
['foo', 4]
The scope of the L variable is behaving as you expect.
The "problem" is with the list you're creating with []. Python does not create a new list each time you call the function. L gets assigned the same list each time you call which is why the function "remembers" previous calls.
So in effect this is what you have:
mylist = []
def f(a, L=mylist):
L.append(a)
return L
The Python Tutorial puts it this way:
The default value is evaluated only once. This makes a difference when the default is a mutable object such as a list, dictionary, or instances of most classes.
and suggests the following way to code the expected behaviour:
def f(a, L=None):
if L is None:
L = []
L.append(a)
return L
There's even less "magic" than you might suspect. This is equivalent to
m = []
def f(a, L=m):
L.append(a)
return L
print f(1)
print f(2)
print f(3)
m is only created once.
Say you have the following code:
def func(a=[]):
a.append(1)
print("A:", a)
func()
func()
func()
You can use python's indentation to help you understand what's going on. Everything that is flush to the left margin is executed when the file gets executed. Everything that's indented is compiled into a code object which gets executed when func() is called. So the function is defined and its default arguments set once, when the program gets executed (because the def statement is flush left).
What it does with the default arguments is an interesting issue. In python 3, it puts most of the information about a function in two places: func.__code__ and func.__defaults__. In python 2, func.__code__ was func.func_code func.__defaults__ was func.func_defaults. Later versions of python 2, including 2.6 have both sets of names, to aid the transition from python 2 to python 3. I will use the more modern __code__ and __defaults__. If you're stuck on an older python, the concepts are the same; just the names differ.
The default values are stored in func.__defaults__, and retrieved each time the function is called.
Thus when you define the function above, the body of the function gets compiled and stored in variables under __code__, to be executed later, and the default arguments get stored in __defaults__. When you call the function, it uses the values in __defaults__. If those values get modified for any reason, it only has the modified version available to use.
Play around defining different functions in the interactive interpreter, and see what you can figure out about how python creates and uses functions.
The explaination is given in answers to this question. To sum it up here:
Functions in Python are a kind of object. Because they are a kind of object, they act like objects when instantiated. A function, if defined with a mutable attribute as a default argument, is exactly the same as a class with a static attribute that is a mutable list.
Lennart Regebro has a good explanation and the answer to the question by Roberto Liffredo is excellent.
To adapt Lennart's answer ... if I have a BananaBunch class:
class BananaBunch:
bananas = []
def addBanana(self, banana):
self.bananas.append(banana)
bunch = BananaBunch()
>>> bunch
<__main__.BananaBunch instance at 0x011A7FA8>
>>> bunch.addBanana(1)
>>> bunch.bananas
[1]
>>> for i in range(6):
bunch.addBanana("Banana #" + i)
>>> for i in range(6):
bunch.addBanana("Banana #" + str(i))
>>> bunch.bananas
[1, 'Banana #0', 'Banana #1', 'Banana #2', 'Banana #3', 'Banana #4', 'Banana #5']
// And for review ...
//If I then add something to the BananaBunch class ...
>>> BananaBunch.bananas.append("A mutated banana")
//My own bunch is suddenly corrupted. :-)
>>> bunch.bananas
[1, 'Banana #0', 'Banana #1', 'Banana #2', 'Banana #3', 'Banana #4', 'Banana #5', 'A mutated banana']
How does this apply to functions? Functions in Python are objects. This bears repeating. Functions in Python are objects.
So when you create a function, you are creating an object. When you give a function a mutable default value, you are populating that object's attribute with a mutable value, and every time you call that function you are operating on the same attribute. So if you are using a mutable call (like append), then you are modifying the same object, just as if you were adding bananas to the bunch object.
The "problem" here is that L=[] is only evaluated once, that is, when the file is compiled. Python steps through each line of the file and compiles it. By the time it reaches the def with the default parameter, it creates that list instance once.
If you put L = [] inside the function code, the instance is not created at "compile time" (actually compile time can also be called part of the run time) because Python compiles the function's code but does not call it. So you will get a new list instance because the creation is done every time you call the function (instead of once during compilation).
A solution for that problem is not to use mutable objects as default parameters, or only fixed instances like None:
def f(a, L = None):
if l == None:
l = []
L.append(a)
return L
Note that in both cases you described, the scope of L is the function scope.
You have to keep in mind that python is an interpreted language. What is happening here is when the function "f" is defined, it creates the list and assigns it to the default parameter "L" of function "f". Later, when you call this function, the same list is used as the default parameter. In short, the code on the "def" line, only gets executed once when the function is defined. This is a common python pitfall, of which I have fallen in myself.
def f(a, L=[]):
L.append(a)
return L
print f(1)
print f(2)
print f(3)
There have been suggestions for idioms in other answers here to fix this issue. The one I would suggest is as follows:
def f(a, L=None):
L = L or []
L.append(a)
return L
This uses the or short circuit to either take the "L" that was passed, or create a new list.
The answer to your scope question is the "L" only has a scope within the function "f", but because the default parameters are only assigned once to a single list instead of every time you call the function it behaves as if the default parameter "L" has a global scope.
I am trying to figure out a way to modify the order of a list of tuples within a function without returning the list.
For example:
L = [(2,4),(8,5),(1,3),(9,4)]
def sort_ratios(L):
L = sorted(L, key=lambda x: float(x[0])/float(x[1]))
return L
Thus, calling sort_ratios() outputs:
>>>sort_ratios(L)
[(1,3),(2,4),(8,5),(9,4)]
But L would still be [(2,4),(8,5),(1,3),(9,4)]
Instead, I would like to simply modify the value of L without returning anything so that sort_ratios() operates as follows:
>>>sort_ratios(L)
>>>L
[(1,3),(2,4),(8,5),(9,4)]
It seems trivial, but I just can't seem to get the function to operate this way.
Try L.sort(key=lambda x: float(x[0])/float(x[1])) for an in-place sort.
primes = [2,3,5,7..] (prime numbers)
map(lambda x:print(x),primes)
It does not print anything.
Why is that?
I've tried
sys.stdout.write(x)
too, but doesn't work either.
Since lambda x: print(x) is a syntax error in Python < 3, I'm assuming Python 3. That means map returns a generator, meaning to get map to actually call the function on every element of a list, you need to iterate through the resultant generator.
Fortunately, this can be done easily:
list(map(lambda x:print(x),primes))
Oh, and you can get rid of the lambda too, if you like:
list(map(print,primes))
But, at that point you are better off with letting print handle it:
print(*primes, sep='\n')
NOTE: I said earlier that '\n'.join would be a good idea. That is only true for a list of str's.
This works for me:
>>> from __future__ import print_function
>>> map(lambda x: print(x), primes)
2
3
5
7
17: [None, None, None, None]
Are you using Python 2.x where print is a statement, not a function?
Alternatively, you can unpack it by putting * before map(...) like the following
[*map(...)]
or
{*map(...)}
Choose the output you desire, a list or a dictionary.
Another reason why you could be seeing this is that you're not evaluating the results of the map function. It returns a generator (an iterable) that evaluates your function lazily and not an actual list.
primes = [2,3,5,7]
map(print, primes) # no output, because it returns a generator
primes = [2,3,5,7]
for i in map(print, primes):
pass # prints 2,3,5,7
Alternately, you can do list(map(print, primes)) which will also force the generator to be evaluated and call the print function on each member of your list.
I am wondering if there is there is a simple Pythonic way (maybe using generators) to run a function over each item in a list and result in a list of returns?
Example:
def square_it(x):
return x*x
x_set = [0,1,2,3,4]
squared_set = square_it(x for x in x_set)
I notice that when I do a line by line debug on this, the object that gets passed into the function is a generator.
Because of this, I get an error:
TypeError: unsupported operand type(s) for *: 'generator' and 'generator'
I understand that this generator expression created a generator to be passed into the function, but I am wondering if there is a cool way to accomplish running the function multiple times only by specifying an iterable as the argument? (without modifying the function to expect an iterable).
It seems to me that this ability would be really useful to cut down on lines of code because you would not need to create a loop to fun the function and a variable to save the output in a list.
Thanks!
You want a list comprehension:
squared_set = [square_it(x) for x in x_set]
There's a builtin function, map(), for this common problem.
>>> map(square_it, x_set)
[0,1,4,9,16] # On Python 3, a generator is returned.
Alternatively, one can use a generator expression, which is memory-efficient but lazy (meaning the values will not be computed now, only when needed):
>>> (square_it(x) for x in x_set)
<generator object <genexpr> at ...>
Similarly, one can also use a list comprehension, which computes all the values upon creation, returning a list.
Additionally, here's a comparison of generator expressions and list comprehensions.
You want to call the square_it function inside the generator, not on the generator.
squared_set = (square_it(x) for x in x_set)
As the other answers have suggested, I think it is best (most "pythonic") to call your function explicitly on each element, using a list or generator comprehension.
To actually answer the question though, you can wrap your function that operates over scalers with a function that sniffs the input, and has different behavior depending on what it sees. For example:
>>> import types
>>> def scaler_over_generator(f):
... def wrapper(x):
... if isinstance(x, types.GeneratorType):
... return [f(i) for i in x]
... return f(x)
... return wrapper
>>> def square_it(x):
... return x * x
>>> square_it_maybe_over = scaler_over_generator(square_it)
>>> square_it_maybe_over(10)
100
>>> square_it_maybe_over(x for x in range(5))
[0, 1, 4, 9, 16]
I wouldn't use this idiom in my code, but it is possible to do.
You could also code it up with a decorator, like so:
>>> #scaler_over_generator
... def square_it(x):
... return x * x
>>> square_it(x for x in range(5))
[0, 1, 4, 9, 16]
If you didn't want/need a handle to the original function.
Note that there is a difference between list comprehension returning a list
squared_set = [square_it(x) for x in x_set]
and returning a generator that you can iterate over it:
squared_set = (square_it(x) for x in x_set)
I need to write a function that cuts the first 2 items from the list that is passed as argument and change it. Not return the modified list
So if a call:
fruits = ['apple','orange','grape','banana']
print fruits # prints ['apple','orange','grape','banana']
f1(fruits)
print fruits # prints ['grape','banana']
I tried:
def f1(a):
a[:] = a[2:] # throws TypeError: 'str' object does not support item assignment
def f1(a):
a = a[2:] # doesn't change the value of fruits
Neither f1(*a) seems to work. I searched StackOverflow but I can't seem to find an answer.
Please don't tell me to return the value of a from f1.
The slice operator ( [x:y] ) creates another list, what you have to do instead is to delete the elements that are already in the list like this:
def f1(a):
del a[0:2]
Try the below function! You have to mutate a itself, not creating another list.
def f(a):
del a[0]
del a[0]
You could use pop method of the list to change input list inplace:
def f(a):
a.pop(0)
a.pop(0)