Understanding Python Closure

I always thought that Python 2.7 functions belong to the area in which they were defined. Consider the following code. Why doesn't the second output "calculate: sin"?

Is there a way to change the code so that it works as expected?

import math mymath = dict() for fun in ["sin", "cos"]: def _impl(val): print "calculating: %s" % fun return getattr(math, fun)(val) mymath[fun] = _impl # calculating: cos print mymath["cos"](math.pi) # calculating: cos <- why? print mymath["sin"](math.pi) 
+6
source share
3 answers

The value of fun is evaluated when the function is called.

In the above example, fun is a global variable, and after the for loop, this value is "cos".

I think you expect the value of fun be replaced when the function is created, but that is not the case. A function evaluates the value of a variable when it works as intended.

This is not the namespace in which you define the function, but the namespace in which you run the function.

 import math mymath = dict() for fun in ["sin", "cos"]: def _impl(val): print "calculating: %s" % fun return getattr(math, fun)(val) mymath[fun] = _impl fun = 'tan' # will print and calculate tan print mymath["cos"](math.pi) 
+7
source

From this code (which works as you see fit)

 my = {} def makefun(fun): def _impl(x): print fun, x return _impl for fun in ["cos", "sin"]: my[fun] = makefun(fun) # will print 'cos' my['cos'](1) fun = 'tan' # will print 'cos' my['cos'](2) 

it seems that this is not the namespace of the function definition that decides on the nature of the closure, but instead the namespace of the variables used. Additional tests:

 my = dict() fun = '' def makefun(): global fun #This line is switched on or off fun = 'sin' def _impl(x): print fun, x return _impl test = makefun() #gives sin 1 test(1) fun = 'cos' #gives sin 2 if line global fun is used #gives cos 2 if line global fun is NOT used test(2) 

So, the correct explanation is that the closure keeps a reference to its arguments, not the value.

+2
source

I think you are trying to complicate the situation: Here is how you can do it with closure:

 import math mymath = dict() def funcmaker(fun): print "creating %s function" % fun def calculate(val): print "calculating: %s" % fun return getattr(math, fun)(val) return calculate print funcmaker("sin")(math.pi) print funcmaker("cos")(math.pi) 

Above code gives the following result:

 creating sin function calculating: sin 1.22464679915e-16 creating cos function calculating: cos -1.0 
0
source

Source: https://habr.com/ru/post/987402/


All Articles