Создание функции из члена экземпляра для другого экземпляра в python - PullRequest
3 голосов
/ 14 сентября 2011

Представьте, что у меня есть f, который является функцией члена экземпляра класса:

class A:
    def b(self):
        print 'hey'

a = A()
f = a.b

Если у меня есть другой экземпляр того же класса, скажем c = A() как я могу восстановить новый ff только с использованием f и c, поэтому вызов ff() приведет к c.b() вместо a.b()

c = A()
ff = some_python_kungfu(f,c)
ff() #it is calling c.b()

Ответы [ 3 ]

4 голосов
/ 15 сентября 2011

Можете ли вы использовать ссылку на метод для класса вместо ссылки на экземпляр?

class A:
    def whoami(self):
        print 'I am %s' % id(self)

a = A()
c = A()

func = A.whoami

func(a)
func(c)
3 голосов
/ 14 сентября 2011

Итак, вы хотите знать, как привязать уже связанный метод к другому экземпляру, используя только связанный метод и другой экземпляр. Это можно сделать так:

def some_python_kungfu(meth, obj):
    return type(meth)(meth.__func__, obj, obj.__class__)

Атрибут __func__ действительно совпадает с с Недом Батчелдерсом im_func, но __func__ совместим с Python 3.

В одном случае это не сработает: методы встроенных классов. Атрибуты __func__ и im_func доступны только для пользовательских классов. Следовательно, это не удастся:

a = "that's no ordinary rabbit"
b = "consult the book of armaments"
b_split = some_python_kungfu(a.split, b)

Небольшая модификация решения Неда будет работать как со встроенными, так и с пользовательскими классами:

def some_python_kungfu(meth, obj):
    return getattr(obj, meth.__name__)

Так будет ли это работать всегда? Ну ... нет, но камень преткновения довольно неясная и (я думаю) редко встречающаяся проблема: если имя метода (meth.__name__) не совпадает с именем в словаре классов ('b') ), то getattr либо вернет неправильный атрибут, либо выдаст AttributeError. Например:

def external(self):
   pass
class A(object):
   b = external

Здесь A.b.__name__ == 'external' вместо 'b', поэтому вместо getattr(obj, 'b') будет вызываться getattr(obj, 'external').

Хотя оба предыдущих подхода имеют проблемы: один со встроенными классами и один с соединенными классами , обе проблемы не возникают одновременно ни при каких обстоятельствах. Поэтому комбинация будет работать во всех случаях:

def some_python_kungfu(meth, obj):
    try:
        return type(meth)(meth.__func__, obj, obj.__class__)
    except AttributeError:
        # meth is a built-in method, so meth.__name__ is always correct
        return getattr(obj, meth.__name__)

Как объяснено в другом месте на этой странице, лучше всего было бы проигнорировать весь этот беспорядок и сделать это более чистым способом, например, используя методы unbound и передавая первый аргумент (self) вручную, как в ответе Cixates. Но кто знает, это может оказаться полезным для некоторых из вас когда-нибудь, возможно, в несколько странных обстоятельствах. ;)

3 голосов
/ 14 сентября 2011

Я не уверен, что это будет работать во всех случаях, но:

def some_python_kungfu(meth, obj):
    """Get a bound method on `obj` corresponding to the method `meth`."""
    return getattr(obj, meth.im_func.__name__)
...