I'm confused about this scope behavior:
class Bar:
def __init__(self):
for fn in ["open","openW","remove","mkdir","exists","isdir","listdir"]:
print "register", fn
def func_wrapper(filename):
print "called func wrapper", fn, filename
setattr(self, fn, func_wrapper)
bar = Bar()
bar.open("a")
bar.remove("b")
bar.listdir("c")
This gives the output:
register open
register openW
register remove
register mkdir
register exists
register isdir
register listdir
called func wrapper listdir a
called func wrapper listdir b
called func wrapper listdir c
But I would have expected that func_wrapper
would always be the correct function. I know that the scope of func_wrapper
is to the whole function but I redefine it in every loop iteration and the last instance got saved away in the attrib. I also tried to add func_wrapper = None
below the setattr
but that doesn't help (would also have wondered me...).
Am I blind? I don't even really see how to work around / fix this.
Local (or function) scope is the code block or body of any Python function or lambda expression. This Python scope contains the names that you define inside the function. These names will only be visible from the code of the function.
this error occurs when the interpreter fails to find that specific variable(x in this case) because of its scope.
You will learn about the four different scopes with the help of examples: local, enclosing, global, and built-in. These scopes together form the basis for the LEGB rule used by the Python interpreter when working with variables.
In Python, just as in SML, or (modern) Lisp, the body of a function is evaluated in the environment where it was defined. So, all three languages are lexically scoped.
Either with
class Bar:
def __init__(self):
for fn in ["open","openW","remove","mkdir","exists","isdir","listdir"]:
print "register", fn
def func_wrapper(filename, fn=fn):
print "called func wrapper", fn, filename
setattr(self, fn, func_wrapper)
or, more robustly, with
def mkwrapper(fn):
def func_wrapper(filename):
print "called func wrapper", fn, filename
func_wrapper.__name__ = fn
return func_wrapper
class Bar:
def __init__(self):
for fn in ["open","openW","remove","mkdir","exists","isdir","listdir"]:
print "register", fn
func_wrapper = mkwrapper(fn)
setattr(self, fn, func_wrapper)
In your original example, all generated functions access the same outer variable fn
, which changes in every loop run. In the corrected examples, this is prevented.
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