python2 срещу python3 функция за обвързване на метод

Уважаеми експерти по python 3,

с python2 човек може да направи следното (знам, че това е малко странно, но не това е целта тук :p):

class A(object):
  def method(self, other):
    print self, other

class B(object): pass

B.method = types.MethodType(A().method, None, B)
B.method() # print both A and B instances

с python3 няма повече необвързани методи, само функции. Ако искам същото поведение, изглежда, че трябва да въведа персонализиран дескриптор като:

class UnboundMethod:
    """unbound method wrapper necessary for python3 where we can't turn
    arbitrary object into a method (no more unbound method and only function
    are turned automatically to method when accessed through an instance)
    """
    def __init__(self, callable):
        self.callable = callable

    def __get__(self, instance, objtype):
        if instance is None:
            return self.callable
        return types.MethodType(self.callable, instance)

така че мога да направя:

B.method = UnboundMethodType(A().method)
B.method() # print both A and B instances

Има ли друг начин да направите това, без да напишете такъв дескриптор?

TIA


person sthenault    schedule 29.08.2012    source източник
comment
Бърз коментар извън темата: Няма нужда да се извлича от обект в Py3. Винаги се прави имплицитно. За да проверите, просто print(anyobject.__mro__) (=Ред на разрешаване на метода)   -  person cfi    schedule 29.08.2012
comment
Вярвам, че това е дублиране на [stackoverflow.com/questions/10729909/. Този въпрос обаче вероятно е по-лесен за намиране. Освен това е по-ясно (поне за мен), така че бих гласувал да запазя този...   -  person cfi    schedule 29.08.2012
comment
@cfi, вярно относно наследяването на обекти, коригиран примерен код на UnboundMethod. Също така сте прав, че това е подобен въпрос като за обвързване на компилирана/вградена функция (което между другото няма задоволителен отговор)   -  person sthenault    schedule 29.08.2012
comment
Липсва ви ред: B.method = types.MethodType(A().method, None, B); b=B(); b.method() # отпечатва както A, така и B екземпляри   -  person Sheena    schedule 18.09.2012


Отговори (2)


B.method = lambda o: A.method(o,A())

b = B()
b.method()

редът b.method() след това извиква A.method(b,A()). Това означава, че A се инициализира всеки път. За да избегнете това:

a = A()
B.method = lambda o: A.method(o,a)

сега всеки път, когато извикате b.method() на който и да е екземпляр на B, същият екземпляр на A се предава като втори аргумент.

person Sheena    schedule 07.11.2012

Е, вашият код също не работи в Python 2, но разбирам какво се опитвате да направите. И можете да използвате ламбда, както в отговора на Шийна, или functools.partial.

>>> import types
>>> from functools import partial

>>> class A(object):
...   def method(self, other):
...     print self, other
... 
>>> class B(object): pass
... 
>>> B.method = partial(A().method, A())
>>> B().method()
<__main__.A object at 0x112f590> <__main__.A object at 0x1132190>
person Lennart Regebro    schedule 12.05.2015