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.

Albert
  • 65,406
  • 61
  • 242
  • 386

1 Answers1

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.

glglgl
  • 89,107
  • 13
  • 149
  • 217
  • Ah yes, I thought sth like this... :) – Albert Jun 22 '12 at 22:34
  • 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. – Lauritz V. Thaulow Jun 22 '12 at 22:39
  • I really wish people would stop recommending that default parameter hack. – Karl Knechtel Jun 22 '12 at 23:28