好吧,我想我得到了它。關鍵是要始終獲得該類型的(未綁定)方法,並將其綁定:
import types
def special_lookup_mimic(obj, name):
if not hasattr(obj, name):
raise TypeError("No method of that name")
meth = getattr(obj, name)
if not isinstance(meth, types.MethodType):
raise TypeError("Expected method")
#always look-up the type's method
cls = obj.__class__
return getattr(cls, name).__get__(obj, cls)
演示:
class Foo(type):
def __add__(cls, other):
print 'Foo().__add__'
return 999
class Bar(object):
__metaclass__ = Foo
def __init__(self, id):
self.id = id
def __add__(self, other):
print 'Bar(%d).__add__' % (self.id,)
return self.id
b1 = Bar(1)
b2 = Bar(2)
b1 + 10; special_lookup_mimic(b1, '__add__')(10)
b2 + 10; special_lookup_mimic(b2, '__add__')(10)
b1.__add__ = b2.__add__
b1 + 10; special_lookup_mimic(b1, '__add__')(10)
b2 + 10; special_lookup_mimic(b2, '__add__')(10)
Bar + 10; special_lookup_mimic(Bar, '__add__')(10)
def patched_add(num):
def patch_add(cls, other):
print "Patched add '%d'" % (num,)
return num
return patch_add
print "Patching Bar.__add__..."
Bar.__add__ = patched_add(1337)
b1 + 10; special_lookup_mimic(b1, '__add__')(10)
b2 + 10; special_lookup_mimic(b2, '__add__')(10)
Bar + 10; special_lookup_mimic(Bar, '__add__')(10)
print "Patching Foo.__add__..."
Foo.__add__ = patched_add(10000)
b1 + 10; special_lookup_mimic(b1, '__add__')(10)
b2 + 10; special_lookup_mimic(b2, '__add__')(10)
Bar + 10; special_lookup_mimic(Bar, '__add__')(10)
輸出:
Bar(1).__add__
Bar(1).__add__
Bar(2).__add__
Bar(2).__add__
Bar(1).__add__
Bar(1).__add__
Bar(2).__add__
Bar(2).__add__
Foo().__add__
Foo().__add__
Patching Bar.__add__...
Patched add '1337'
Patched add '1337'
Patched add '1337'
Patched add '1337'
Foo().__add__
Foo().__add__
Patching Foo.__add__...
Patched add '1337'
Patched add '1337'
Patched add '1337'
Patched add '1337'
Patched add '10000'
Patched add '10000'
什麼是正確的行爲?我沒有看到'lookup_add(Bar)'如何從類對象中獲得一個綁定的方法。 –
非常有趣...好奇如何解決這個問題。 – Claudiu
@ li.davidm:我想要一個函數,它爲任何對象'o'生成一個返回值,該值代表'__add__'方法,當您執行'o + whatever'時被調用,或者如果不存在這樣的方法則產生一個錯誤。結果是綁定還是未綁定的方法並不重要。 (請注意,我知道'__radd__'和'__iadd__';我特別想查找'__add__'。例如,選擇'__pos__'或'__neg__'這樣的方法可能會更好。) – user2357112