Какой самый питонный способ заставить связанный метод действовать как функция? - PullRequest
3 голосов
/ 29 января 2009

Я использую Python API, который ожидает, что я передам ему функцию. Однако по разным причинам я хочу передать ему метод, потому что я хочу, чтобы функция вела себя по-разному в зависимости от экземпляра, которому она принадлежит. Если я передам ему метод, API не будет вызывать его с правильным аргументом «self», поэтому мне интересно, как превратить метод в функцию, которая знает, какому «self» он принадлежит.

Есть несколько способов сделать это, включая использование лямбды и замыкания. Ниже я привел несколько примеров этого, но мне интересно, существует ли стандартный механизм для достижения того же эффекта.

class A(object):
    def hello(self, salutation):
        print('%s, my name is %s' % (salutation, str(self)))

    def bind_hello1(self):
        return lambda x: self.hello(x)

    def bind_hello2(self):
        def hello2(*args):
            self.hello(*args)
        return hello2


>>> a1, a2 = A(), A()
>>> a1.hello('Greetings'); a2.hello('Greetings')
Greetings, my name is <__main__.A object at 0x71570>
Greetings, my name is <__main__.A object at 0x71590>

>>> f1, f2 = a1.bind_hello1(), a2.bind_hello1()
>>> f1('Salutations'); f2('Salutations')
Salutations, my name is <__main__.A object at 0x71570>
Salutations, my name is <__main__.A object at 0x71590>

>>> f1, f2 = a1.bind_hello2(), a2.bind_hello2()
>>> f1('Aloha'); f2('Aloha')
Aloha, my name is <__main__.A object at 0x71570>
Aloha, my name is <__main__.A object at 0x71590>

Ответы [ 2 ]

8 голосов
/ 29 января 2009

Будет ли работать метод, связанный с экземпляром? Если это так, вам не нужно делать ничего особенного.

In [2]: class C(object):
   ...:     def method(self, a, b, c):
   ...:         print a, b, c
   ...:
   ...:

In [3]: def api_function(a_func):
   ...:     a_func("One Fish", "Two Fish", "Blue Fish")
   ...:
   ...:

In [4]: c = C()

In [5]: api_function(c.method)
One Fish Two Fish Blue Fish
0 голосов
/ 29 января 2009

Вы можете уточнить свой вопрос. Как указывает Райан,

def callback(fn):
    fn('Welcome')
callback(a1.hello)
callback(a2.hello)

приведет к вызову hello с правильной привязкой self, a1 или a2. Если вы не испытываете этого, что-то глубоко не так, потому что именно так работает Python.

Судя по тому, что вы написали, вам кажется, что вы хотите связать аргументы - другими словами, curry Вы можете найти примеры повсюду, но Рецепт 52549 имеет лучший Pythonic внешний вид, на мой вкус.

class curry:
    def __init__(self, fun, *args, **kwargs):
        self.fun = fun
        self.pending = args[:]
        self.kwargs = kwargs.copy()

    def __call__(self, *args, **kwargs):
        if kwargs and self.kwargs:
            kw = self.kwargs.copy()
            kw.update(kwargs)
        else:
            kw = kwargs or self.kwargs

        return self.fun(*(self.pending + args), **kw)

f1 = curry(a1.hello, 'Salutations')
f1()  #  == a1.hello('Salutations')
...