2009-01-29 18 views
3

J'utilise une API Python qui s'attend à ce que je lui transmette une fonction. Cependant, pour diverses raisons, je veux lui passer une méthode, car je veux que la fonction se comporte différemment selon l'instance à laquelle elle appartient. Si je lui passe une méthode, l'API ne l'appellera pas avec le bon argument 'self', donc je me demande comment transformer une méthode en une fonction qui sait à quoi elle appartient.Quelle est la manière la plus pythonique de faire agir une méthode liée comme une fonction?

Il y a plusieurs façons de faire cela, y compris l'utilisation d'un lambda et d'une fermeture. J'ai inclus quelques exemples ci-dessous, mais je me demande s'il existe un mécanisme standard pour obtenir le même effet.

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> 

Répondre

8

La transmission de la méthode liée à une instance va-t-elle fonctionner? Si c'est le cas, vous n'avez rien de spécial à faire.

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 
+1

Um ... Je suis un idiot. Ça marche. – Nick

0

Vous voudrez peut-être clarifier votre question. Comme Ryan souligne,

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

se traduira par hello être appelé avec la self correcte lié, a1 ou a2. Si vous ne rencontrez pas cela, quelque chose ne va pas du tout, car c'est ainsi que fonctionne Python. Ce que vous semble vouloir, à en juger par ce que vous avez écrit, est de lier des arguments - en d'autres termes, currying. Vous pouvez trouver des exemples partout, mais Recipe 52549 a le meilleur aspect Pythonien, par mes goûts.

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') 
+0

Ce que vous montrez n'est pas en cours - c'est une application partielle. –

+0

Wikipedia les appelle la même chose. http://en.wikipedia.org/wiki/Currying "La motivation pratique pour la curry est que très souvent les fonctions obtenues en fournissant certains mais pas tous les arguments à une fonction curry (souvent appelée application partielle)" – recursive