can't rebind magic methods

Alex Martelli aleaxit at yahoo.com
Tue Mar 21 03:51:50 CET 2006


Michael Tobis <mtobis at gmail.com> wrote:

> Still a bit confused actually. Any explanation of the following?

I believe the problem you're having is with WHEN a name is looked up --
which tends to be 'as late as possible, but no later'.

> def getf(method,name):
>     def f(self, *a, **k): return method(self.val, *a, **k)
>     f.func_name = name
>     return f

Here, 'method' is looked up at each execution of f -- but each instance
of f is separate and has a separate closure, so 'method' is what it's
worth in THAT call to getf (as desired).


> for spec in 'str repr hash hex oct pow add'.split():
>     name =  '__%s__' % spec
>     method = getattr(int, name)

Here, we're rebinding method in the same scope at each pass; in the end,
it's left bound to the last value it had -- the getaddr of 'add' in int.

>     # comment this out to get the non-working case
> 
>     setattr(myint,name,getf(method,name)) # works
> 
>     # uncomment three lines to get the non-working case
>     # raises TypeError: "expected 1 arguments, got 0" at method
> invocation
>     # why isn't this equivalent to the setattr above?

Because it's looking up 'method' in the scope of the "def f" -- and in
that scope, at the time f executes, the loop is over, so name 'method'
is always bound to 'getattr(int, "add")'.
 
>     # def f(self, *a, **k): return method(self.val, *a, **k)
> 
>     # f.func_name = name
> 
>     # setattr(myint,name,f) # doesn't work

HTH...


Alex



More information about the Python-list mailing list