Reference to self not passed to member function

Bengt Richter bokr at oz.net
Fri May 6 23:00:54 EDT 2005


On Sat, 7 May 2005 01:06:31 +0200, "Fredrik Lundh" <fredrik at pythonware.com> wrote:

>James Stroud wrote:
>
>> I did this:
>>
>> py> class bob(object):
>> ...   def __init__(self,**kwargs):
>> ...     for fname,func in kwargs.items():
>> ...       setattr(self, fname, lambda *args : func(*args))
>> ...
>> py> def doit():
>> ...   print "wuzzup?"
>> ...
>> py> abob = bob(doit=doit)
>> py>
>> py> abob.doit()
>> wuzzup?
>>
>> Much to my surprise, this works fine.
>
>why is that surprising?  "doit" is a callable, you wrap it in another
>callable, and then you store it in an attribute.
>
>that's no different from storing a integer as an attribute, and it
>sure doesn't turn your callable into an instance method.
>
>> 1. What exactly is going on?
>
>see above.
>
>> 2. How can I get ref to self passed to doit() if I want it to?
>
>try using this bob instead:
>
>    import new
>
>    class bob(object):
>        def __init__(self, **kwargs):
>            for fname, func in kwargs.items():
>                setattr(self, fname, new.instancemethod(func, self, bob))
>
ISTM "instancemethod" doesn't really tell the story of what that usage means, which is actually
storing a bound method as an attribute of the instance it _happens_ to be bound to.
I.e., this "instancemethod" is a bound method that could be stored as an attribute of _anything_
and if used as a callable the function would see the same bound "self" no matter where the bound
method was picked up from (well, unless someone perversely interfered with some hack ;-)

I am wondering whether anyone mistakenly thinks that there is a dynamic binding process
involved at the time of the attribute access for the instancemethod, as there is for
an ordinary method. Of course I know you know how to mess with the class to make function
attributes of instances get dynamically bound as if they were class attributes accessed
via the instance, but I wonder if others appreciate this distinction, or would be surprised by e.g.,

 >>> import new
 >>>
 >>> class bob(object):
 ...     def __init__(self, **kwargs):
 ...         for fname, func in kwargs.items():
 ...             setattr(self, fname, new.instancemethod(func, self, bob))
 ...
 >>> def m(self, *args):
 ...     return self, args
 ...
 >>> b = bob(bm=m)
 >>> vars(b)
 {'bm': <bound method bob.m of <__main__.bob object at 0x02EF16EC>>}
 >>> b.bm('hi')
 (<__main__.bob object at 0x02EF16EC>, ('hi',))
 >>> bmg = b.bm
 >>> bmg('hello')
 (<__main__.bob object at 0x02EF16EC>, ('hello',))
 >>> class C: pass
 ...
 >>> c=C()
 >>> c.m = b.bm
 >>> c.m('greets')
 (<__main__.bob object at 0x02EF16EC>, ('greets',))
 >>> C.M = b.bm
 >>> C.M('saludos')
 (<__main__.bob object at 0x02EF16EC>, ('saludos',))
 >>> c.M('amigos')
 (<__main__.bob object at 0x02EF16EC>, ('amigos',))

Obviously "self" has nothing to do with c or C etc.

Regards,
Bengt Richter



More information about the Python-list mailing list