I could not decipher how this function is working, could somebody explain what the brackets after the curly braces mean?
def max(a,b):
f = {a >= b : lambda: a, b >= a: lambda: b}[True]
return f()
This is very convoluted (strange) definition for max, basically it creates a dictionary where the keys are the boolean True and False and the values are either a or b depending which one is the maximum. For example max(1,2) creates the following dictionary:
{ False: lambda: 1, True: lambda: 2}
Then f is assigned the function of the True value in the above example lambda: 2, which is a function that returns the constant value 2. Finally the function returns the call of f(), i.e. the value 2.
To answer your question more specifically, the brackets after the curly braces means get the value of the dictionary for the True key.
f = {a >= b : lambda: a, b >= a: lambda: b}[True]
Above statement will always get evaluated as either one of the following:
case 1: a > b
f = {True : lambda: a, False: lambda: b}[True]
which means f = lambda: a
which means f() is a
case 2: b > a
f = {False: lambda: a, True: lambda: b}[True]
which means f = lambda: b
which means f() is b
case 3: a = b
f = {True : lambda: a, True: lambda: b}[True]
which means f = lambda: a or it could be f = lambda: b
which means f() is a or b
If you don't know the clusters and the lambda function, it's hard to understand!
But this example teaches something:
{"name": "Jundullah", "age": 18}["name"] #ouput: "Jundullah"
Related
In Python, I can return multiple values from a function like this:
def myfunc():
return 1, 2, 3
When I call this function, I need to unpack the values like this:
a, b, c = myfunc()
# a = 1, b = 2, c = 3
If I try this, I'll get the whole tuple:
a = myfunc()
# a = (1, 2, 3)
Is there anyway I can make the code above make a = 1 without changing the way the function is called? I realize I can do something like a, _, _ = myfunc(), but I don't want to change the way the function is called. I can only change the function definition.
In other words I want something like this:
a, b, c = myfunc()
# a = 1, b = 2, c = 3
a, b = myfunc()
# a = 1, b = 2
a = myfunc()
# a = 1
Thanks for your help!
You can use the star notation:
a, *_ = myfunc()
This assigns 1 to a and the rest of the tuple to the
"anonymous" variable _.
This question already has answers here:
What do lambda function closures capture?
(7 answers)
Creating functions (or lambdas) in a loop (or comprehension)
(6 answers)
Closed 2 years ago.
Considering the following code snippet:
# directorys == {'login': <object at ...>, 'home': <object at ...>}
for d in directorys:
self.command["cd " + d] = (lambda : self.root.change_directory(d))
I expect to create a dictionary of two function as following :
# Expected :
self.command == {
"cd login": lambda: self.root.change_directory("login"),
"cd home": lambda: self.root.change_directory("home")
}
but it looks like the two lambda function generated are exactly the same :
# Result :
self.command == {
"cd login": lambda: self.root.change_directory("login"),
"cd home": lambda: self.root.change_directory("login") # <- Why login ?
}
I really don't understand why. Do you have any suggestions ?
You need to bind d for each function created. One way to do that is to pass it as a parameter with a default value:
lambda d=d: self.root.change_directory(d)
Now the d inside the function uses the parameter, even though it has the same name, and the default value for that is evaluated when the function is created. To help you see this:
lambda bound_d=d: self.root.change_directory(bound_d)
Remember how default values work, such as for mutable objects like lists and dicts, because you are binding an object.
This idiom of parameters with default values is common enough, but may fail if you introspect function parameters and determine what to do based on their presence. You can avoid the parameter with another closure:
(lambda d=d: lambda: self.root.change_directory(d))()
# or
(lambda d: lambda: self.root.change_directory(d))(d)
This is due to the point at which d is being bound. The lambda functions all point at the variable d rather than the current value of it, so when you update d in the next iteration, this update is seen across all your functions.
For a simpler example:
funcs = []
for x in [1,2,3]:
funcs.append(lambda: x)
for f in funcs:
print f()
# output:
3
3
3
You can get around this by adding an additional function, like so:
def makeFunc(x):
return lambda: x
funcs = []
for x in [1,2,3]:
funcs.append(makeFunc(x))
for f in funcs:
print f()
# output:
1
2
3
You can also fix the scoping inside the lambda expression
lambda bound_x=x: bound_x
However in general this is not good practice as you have changed the signature of your function.
Alternatively, instead of lambda, you can use functools.partial which, in my opinion, has a cleaner syntax.
Instead of:
for d in directorys:
self.command["cd " + d] = (lambda d=d: self.root.change_directory(d))
it will be:
for d in directorys:
self.command["cd " + d] = partial(self.root.change_directory, d)
Or, here is another simple example:
numbers = [1, 2, 3]
lambdas = [lambda: print(number)
for number in numbers]
lambdas_with_binding = [lambda number=number: print(number)
for number in numbers]
partials = [partial(print, number)
for number in numbers]
for function in lambdas:
function()
# 3 3 3
for function in lambdas_with_binding:
function()
# 1 2 3
for function in partials:
function()
# 1 2 3
I met the same problem. The selected solution helped me a lot, but I consider necessary to add a precision to make functional the code of the question: define the lambda function outside of the loop. By the way, default value is not necessary.
foo = lambda d: lambda : self.root.change_directory(d)
for d in directorys:
self.command["cd " + d] = (foo(d))
In this example test_function1 has 4 varibles that need to be used in test_funtion2.I would not like using global variables becouse the actual code i'm writing is more complex and it would break it.
def test_function1():
a = input("Type aaa:")
b = "bbb"
c = "ccc"
d = "ddd"
test_funtion1()
def test_function2():
if a == "aaa"
print(b)
print(c)
print(d)
test_function2()
I have a solution, but I am not sure if it is good or not.Could you tell me if this would work or if there is any other alternative.Thanks!
Sorry for my grammar , english is not my main language.
def test_function1():
a = input("Type aaa:")
b = "bbb"
c = "ccc"
d = "ddd"
return (a, b, c, d)
def test_function2():
if (test_funtion1()[0]) == "aaa"
print(test_funtion1()[1])
print(test_funtion1()[2])
print(test_funtion1()[3])
I think what you're looking for are classes.
a, b,c, d is your state, and an instantiation of such a class forms a state, which is basically the values referenced by these 4. Your first function is the "constructor" (called __init__) and the second function is then able to access these "instance variables".
I edited the solution that best fits me:
def test_function1():
a = input("Type aaa:")
b = "bbb"
c = "ccc"
d = "ddd"
return a, b, c, d
def test_function2():
x = test_function1()
if x[0] == "aaa":
print(x[1])
print(x[2])
print(x[3])
test_funtion2()
Passing arguments to functions and returning values from functions is indeed the first and most obvious way to avoid global state - but wrt/ to your snippet, you should avoid calling test_function1 four times, which is done by keeping the result in a local variable:
def test_function2():
result = test_funtion1()
if result[0] == "aaa"
print(result[1])
print(result[2])
print(result[3])
or in this specific case (when the function returns a tuple or ny sequence of known length) you could use tuple unpacking:
def test_function2():
a, b, c, d = test_funtion1()
if a == "aaa"
print(b)
print(c)
print(d)
Also, if you have a set of functions working on the same set of (related) variables, you may want to have a look at classes and objects.
You can also use this
def test_function1():
a = input("Type aaa:")
b = "bbb"
c = "ccc"
d = "ddd"
t = a, b, c, d
return t
def test_function2():
x = test_function1()
if x[0] == "aaa":
print(x[1])
print(x[2])
print(x[3])
test_function2()
If I write this:
c = []
def cf(n):
c = range (5)
print c
if any((i>3) for i in c) is True:
print 'hello'
cf(1)
print c
Then I get:
[1, 2, 3, 4]
hello
[]
I'm really new to programming, so please explain it really simply, but how do I stop Python from forgetting what c is after the function has ended? I thought I could fix it by defining c before the function, but obviously that c is different to the one created just for the function loop.
In my example, I could obviously just write:
c = range (5)
def cf(n)
But the program I'm trying to write is more like this:
b = [blah]
c = []
def cf(n):
c = [transformation of b]
if (blah) is True:
'loop' cf
else:
cf(1)
g = [transformation of c that produces errors if c is empty or if c = b]
So I can't define c outside the function.
In python you can read global variables in functions, but you cant assigned to them by default. the reason is that whenever python finds c = it will create a local variable. Thus to assign to global one, you need explicitly specify that you are assigning to global variable.
So this will work, e.g.:
c = [1,2,3]
def cf():
print(c) # it prints [1,2,3], it reads global c
However, this does not as you would expect:
c = [1,2,3]
def cf():
c = 1 # c is local here.
print(c) # it prints 1
cf()
print(c) # it prints [1,2,3], as its value not changed inside cf()
So to make c be same, you need:
c = [1,2,3]
def cf():
global c
c = 1 # c is global here. it overwrites [1,2,3]
print(c) # prints 1
cf()
print(c) # prints 1. c value was changed inside cf()
To summarise a few of these answers, you have 3 basic options:
Declare the variable as global at the top of your function
Return the local instance of the variable at the end of your function
Pass the variable as an argument to your function
You can also pass the array c into the function after declaring it. As the array is a function argument the c passed in will be modified as long as we don't use an = statement. This can be achieved like this:
def cf(n, c):
c.extend(range(5))
print c
if any((i>3) for i in c) is True:
print 'hello'
if __name__ == '__main__':
c = []
cf(1, c)
print c
For an explanation of this see this
This is preferable to introducing global variables into your code (which is generally considered bad practice). ref
Try this
c = []
def cf(n):
global c
c = range (5)
print c
if any((i>3) for i in c) is True:
print 'hello'
cf(1)
print c
If you want your function to modify c then make it explicit, i.e. your function should return the new value of c. This way you avoid unwanted side effects:
def cf(n, b):
"""Given b loops n times ...
Returns
------
c: The modified value
"""
c = [transformation of b]
...
return c # <<<<------- This
c = cf(1)
e.g. so that these would both work - is it possible?
(val,VAL2) = func(args)
val = func(args)
Where val is not a tuple
For example I'd like these to work for my custom object something
for item in something:
do_item(item) #where again item - is not a tuple
for (item,key) in something:
do_more(key,item)
I thought that I need to implement next() function in two different ways...
edit: as follows from the answers below, this should not really be done.
If you mean, can the function act differently based on the return types the caller is expecting, the answer is no (bar seriously nasty bytecode inspection). In this case, you should provide two different iterators on your object, and write something like:
for item in something: # Default iterator: returns non-tuple objects
do_something(item)
for (item,key) in something.iter_pairs(): # iter_pairs returns different iterator
do_something_else(item, key)
eg. see the dictionary object, which uses this pattern. for key in mydict iterates over the dictionary keys. for k,v in mydict.iteritems() iterates over (key, value) pairs.
[Edit] Just in case anyone wants to see what I mean by "seriously nasty bytecode inspection", here's a quick implementation:
import inspect, opcode
def num_expected_results():
"""Return the number of items the caller is expecting in a tuple.
Returns None if a single value is expected, rather than a tuple.
"""
f = inspect.currentframe(2)
code = map(ord, f.f_code.co_code)
pos = f.f_lasti
if code[pos] == opcode.opmap['GET_ITER']: pos += 1 # Skip this and the FOR_ITER
if code[pos] > opcode.EXTENDED_ARG: pos +=5
elif code[pos] > opcode.HAVE_ARGUMENT: pos +=3
else: pos += 1
if code[pos] == opcode.opmap['UNPACK_SEQUENCE']:
return code[pos+1] + (code[pos+2] << 8)
return None
Usable something like:
class MagicDict(dict):
def __iter__(self):
if num_expected_results() == 2:
for k,v in self.iteritems():
yield k,v
else:
for k in self.iterkeys():
yield k
d=MagicDict(foo=1, bar=2)
print "Keys:"
for key in d:
print " ", key
print "Values"
for k,v in d:
print " ",k,v
Disclaimer: This is incredibly hacky, insanely bad practice, and will cause other programmers to hunt you down and kill you if they ever see it in real code. Only works on cpython (if that). Never use this in production code (or for that matter, probably any code).
Have you tried that? It works.
def myfunction(data):
datalen = len(data)
result1 = data[:datalen/2]
result2 = data[datalen/2:]
return result1, result2
a, b = myfunction('stuff')
print a
print b
c = myfunction('other stuff')
print c
In fact there is no such thing as "return signature". All functions return a single object. It seems that you are returning more than one, but in fact you wrap them into a container tuple object.
Yes it's doable:
def a(b):
if b < 5:
return ("o", "k")
else:
return "ko"
and the result:
>>> b = a(4)
>>> b
('o', 'k')
>>> b = a(6)
>>> b
'ko'
I think the thing after is to be careful when you will use the values returned...
>>> def func(a,b):
return (a,b)
>>> x = func(1,2)
>>> x
(1, 2)
>>> (y,z) = func(1,2)
>>> y
1
>>> z
2
That doesn't really answer your question. The real answer is that the left side of the assignment doesn't affect the returned type of the function and can't be used to distinguish between functions with different return types. As noted in other answers, the function can return different types from different return statements but it doesn't know what's on the other side of the equals sign.
In the case of this function, it returns a tuple. If you assign it to x, x has the value of the tuple. (y, z) on the left side of the assignment is "tuple unpacking". The tuple returned by func() is unpacked into y and z.
Update:
Given the example use case, I'd write different generators to handle the cases:
class Something(object):
def __init__(self):
self.d = {'a' : 1,
'b' : 2,
'c' : 3}
def items(self):
for i in self.d.values():
yield i
def items_keys(self):
for k,i in self.d.items():
yield i,k
something = Something()
for item in something.items():
....: print item
....:
1
3
2
for item,key in something.items_keys():
....: print key, " : ", item
....:
a : 1
b : 2
c : 3
Or
You can return a tuple:
In [1]: def func(n):
...: return (n, n+1)
...:
In [2]: a,b = func(1)
In [3]: a
Out[3]: 1
In [4]: b
Out[4]: 2
In [5]: x = func(1)
In [6]: x
Out[6]: (1, 2)
Yes, both would work. In the first example, val1 and val2 would have the two values. In the second example, val would have a tuple. You can try this in your python interpreter:
>>> def foo():
... return ( 1, 2 )
...
>>> x = foo()
>>> (y,z) = foo()
>>> x
(1, 2)
>>> y
1
>>> z
2
It's possible only if you're happy for val to be a 2-item tuple (or if args need not be the same in the two cases). The former is what would happen if the function just ended with something like return 23, 45. Here's an example of the latter idea:
def weirdfunc(how_many_returns):
assert 1 <= how_many_returns <= 4
return 'fee fie foo fum'.split()[:how_many_returns]
var1, var2 = weirdfunc(2) # var1 gets 'fee', var2 gets 'fie'
var, = weirdfunc(1) # var gets 'fee'
This is asking for major confusion. Instead you can follow dict with separate keys, values, items, etc. methods, or you can use a convention of naming unused variables with a single underscore. Examples:
for k in mydict.keys(): pass
for k, v in mydict.items(): pass
for a, b in myobj.foo(): pass
for a, _ in myobj.foo(): pass
for _, b in myobj.foo(): pass
for _, _, _, d in [("even", "multiple", "underscores", "works")]:
print(d)
for item in something: # or something.keys(), etc.
do_item(item)
for item, key in something.items():
do_more(key, item)
If this doesn't fit your function, you should refactor it as two or more functions, because it's clearly trying to fulfill two or more different goals.