views:

351

answers:

3

In following example I am trying to bind a method object via types.MethodType(...). It does not seem to work. Any suggestions? Thanks in advance.

import types

class Base:
    def payload(self, *args): 
        print "Base:payload"

class Drvd(Base):
    def iter(self, func):
        derived_func = types.MethodType(func, self, Drvd) # bind
        print "drvd_func:", derived_func 
        derived_func() # result:  calls Base:payload 
                       # expected:calls Drvd:payload; why???
    def payload(self, *args):
        print "Drvd:payload"

derived   = Drvd()           
base_func = Base.payload      
print "base_func:", base_func
derived.iter(base_func)  # pass unbound method object

The output shows:

base_func: <unbound method Base.payload>
drvd_func: <bound method Drvd.payload of <main.Drvd instance at 0x00B51648>>
Base:payload

+1  A: 

Because you passed Base's payload (not Drvd's) to iter!

Hint:

print "%s: Base:payload"%repr(self)

Kudos for creating an accursed chimera of a thing, though!

Jonathan Feinberg
+1 for "accursed chimera"! :)
thrope
A: 

I don't really understand what you're trying to do - but to me it's working as I'd expect. You are binding Base.payload to Drvd - from your print out you can see it is binding correctly to your Drvd instance. I'm not sure why you are then expecting it to call Drvd.payload - you have bound the function object Base.payload. It is always going to be that function.

[edit: just to add - it might be helpful if you say what your trying to do in general terms. What you're doing at the moment doesn't make much sense - Python has inheritence so if you want to override the payload method you can just do it - you don't need to do any manual binding.]

thrope
I am trying to reduce coding effort on tarversing a treelike structure of nodes compared to a visitor-pattern or multimethod approach. It seems to become a hack though on bending pythons underlying method signatures.
pi
+2  A: 

You're specifically requesting the use of the underlying function (im_func) of Base.payload, with a fake im_class of Drvd. Add after the existing print in iter:

    print "w/class:", derived_func.im_class
    print "w/func:", derived_func.im_func

and you'll see the total output as:

$ python bou.py 
base_func: <unbound method Base.payload>
drvd_func: <bound method Drvd.payload of <__main__.Drvd instance at 0x24a918>>
w/class: __main__.Drvd
w/func: <unbound method Base.payload>
Base:payload

i.e., as you've asked, the underlying code being used is indeed Base.payload -- which is also what you observe in the call.

From Base.payload there is no direct way to get to Drvd.payload except by getting the name and using it to do a getattr on self (a Drvd instance), or equivalent.

Alex Martelli
Thanks for your clarification. The name of the passed unbound function is indeed the only link amongst Base and Drvd implementations.
pi