6

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.

2
  • @heltonbiker: Can you elaborate? How should I use a dict instead here? And why? Commented Jun 22, 2012 at 22:45
  • I've read more thoroughly, and deleted the previous comment. Commented Jun 23, 2012 at 0:55

1 Answer 1

6

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Ah yes, I thought sth like this... :)
I always thought there was something special about lambda with regards to late binding, but now I understand that regular functions really have the same problem, it's just that they're not so often used the same way lambda functions are. +1 to question and answer.
I really wish people would stop recommending that default parameter hack.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.