I just learned python @ decorator, it's cool, but soon I found my modified code coming out weird problems.
def with_wrapper(param1):
def dummy_wrapper(fn):
print param1
param1 = 'new'
fn(param1)
return dummy_wrapper
def dummy():
@with_wrapper('param1')
def implementation(param2):
print param2
dummy()
I debug it, it throws out exception at print param1
UnboundLocalError: local variable 'param1' referenced before assignment
If I remove param1 = 'new'
this line, without any modify operation (link to new object) on variables from outer scope, this routine might working.
Is it meaning I only have made one copy of outer scope variables, then make modification?
Thanks Delnan, it's essential to closure. Likely answer from here: What limitations have closures in Python compared to language X closures?
Similar code as:
def e(a):
def f():
print a
a = '1'
f()
e('2')
And also this seems previous annoying global variable:
a = '1'
def b():
#global a
print a
a = '2'
b()
This is fixed by add global symbol. But for closure, no such symbol found. Thanks unutbu, Python 3 gave us nonlocal.
I know from above directly accessing to outer variable is read-only. but it's kind of uncomfortable to see preceded reading variable(print var) is also affected.
When Python parses a function, it notes whenever it finds a variable used on the left-hand side of an assignment, such as
param1 = 'new'
It assumes that all such variables are local to the function. So when you precede this assignment with
print param1
an error occurs because Python does not have a value for this local variable at the time the print statement is executed.
In Python3 you can fix this by declaring that param1
is nonlocal:
def with_wrapper(param1):
def dummy_wrapper(fn):
nonlocal param1
print param1
param1 = 'new'
fn(param1)
return dummy_wrapper
In Python2 you have to resort to a trick, such as passing param1 inside a list (or some other mutable object):
def with_wrapper(param1_list):
def dummy_wrapper(fn):
print param1_list[0]
param1_list[0] = 'new' # mutate the value inside the list
fn(param1_list[0])
return dummy_wrapper
def dummy():
@with_wrapper(['param1']) # <--- Note we pass a list here
def implementation(param2):
print param2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With