2

オブジェクトの特別なメソッドを検索したい場合は、オブジェクトまたはその型に対して実行できます。ただし、どちらのオプションも正しくないようです。

def lookup_add(o):
    return o.__add__
def lookup_sub(o):
    return type(o).__sub__

class Foo(type):
    def __add__(self, other):
        return NotImplemented
    def __sub__(self, other):
        return NotImplemented

class Bar(object):
    __metaclass__ = Foo

    def __add__(self, other):
        return NotImplemented

baz = Bar()

lookup_add(Bar) # Produces wrong method
lookup_sub(baz) # Should raise an error. Instead, produces wrong method.

lookup_addオブジェクトで調べます。に対しては正しく機能し、 のlookup_add(baz)メソッドに対してバインドされたメソッド オブジェクトを返しますが、 に対してbazは間違った結果を生成しlookup_add(Bar)ます。

lookup_subタイプで調べます。に対しては正しく機能し、 のlookup_sub(Bar)メソッドに対してバインドされていないメソッド オブジェクトを返しますBarが、 に対しては間違った結果を生成しlookup_sub(baz)ます。

を試すこともできますが、実際にはのメソッドfunctools.partial(operator.add, o)を検索しません。が実際に実装されていないo場合、この試みは私が望むエラーを生成しません。o__add__

インタープリターの特別なメソッド検索動作を再現する良い方法はありますか?

4

2 に答える 2

0

わかりました、私はそれを手に入れたと思います。秘訣は、常に型の (バインドされていない) メソッドを取得してバインドすることです。

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'
于 2013-09-24T04:00:33.673 に答える
0

を使用して2つを組み合わせることができると思いますisinstance

def lookup_method(obj, method):
    if not isinstance(obj, type):
        return getattr(obj, method, None)
    return getattr(type(obj), method, None)

>>> print(lookup_method(Bar, '__add__'))
<unbound method Foo.__add__>
>>> print(lookup_method(baz, '__add__'))
<bound method Bar.__add__ of <__main__.Bar object at 0x23f27d0>>
>>> print(lookup_method(baz, '__sub__'))
None
于 2013-09-24T03:49:30.053 に答える