web-dev-qa-db-fra.com

Comment passer une méthode en tant que paramètre dans Python

Est-il possible de passer une méthode en tant que paramètre à une méthode?

self.method2(self.method1)

def method1(self):
    return 'hello world'

def method2(self, methodToRun):
    result = methodToRun.call()
    return result
152
Dan

Oui, utilisez simplement le nom de la méthode, comme vous l'avez écrit. Les méthodes/fonctions sont des objets en Python, comme n'importe quoi d'autre, et vous pouvez les transmettre à votre façon de traiter les variables. En fait, vous pouvez considérer une méthode (ou une fonction) comme une variable dont la valeur est l'objet de code appelable réel.

Pour votre information, il n’ya pas de méthode call - je crois qu’elle s’appelle __call__, mais vous n'êtes pas obligé de l'invoquer explicitement:

def method1():
    return 'hello world'

def method2(methodToRun):
    result = methodToRun()
    return result

method2(method1)

Si tu voulais method1 être appelé avec des arguments, alors les choses se compliquent un peu. method2 _ doit être écrit avec un peu d’information sur la manière de passer des arguments à method1, et il doit obtenir des valeurs pour ces arguments quelque part. Par exemple, si method1 est supposé prendre un argument:

def method1(spam):
    return 'hello ' + str(spam)

alors vous pourriez écrire method2 pour l'appeler avec un argument qui est transmis:

def method2(methodToRun, spam_value):
    return methodToRun(spam_value)

ou avec un argument qu'il se calcule lui-même:

def method2(methodToRun):
    spam_value = compute_some_value()
    return methodToRun(spam_value)

Vous pouvez élargir cela à d’autres combinaisons de valeurs transmises et calculées, comme

def method1(spam, ham):
    return 'hello ' + str(spam) + ' and ' + str(ham)

def method2(methodToRun, ham_value):
    spam_value = compute_some_value()
    return methodToRun(spam_value, ham_value)

ou même avec des arguments de mots clés

def method2(methodToRun, ham_value):
    spam_value = compute_some_value()
    return methodToRun(spam_value, ham=ham_value)

Si vous ne savez pas, en écrivant method2, quels arguments methodToRun va prendre, vous pouvez également utiliser le décompactage d'argument pour l'appeler de manière générique:

def method1(spam, ham):
    return 'hello ' + str(spam) + ' and ' + str(ham)

def method2(methodToRun, positional_arguments, keyword_arguments):
    return methodToRun(*positional_arguments, **keyword_arguments)

method2(method1, ['spam'], {'ham': 'ham'})

Dans ce cas positional_arguments doit être une liste ou un tuple ou similaire, et keyword_arguments est un dict ou similaire. Dans method2 vous pouvez modifier positional_arguments et keyword_arguments (par exemple, pour ajouter ou supprimer certains arguments ou modifier les valeurs) avant d'appeler method1.

217
David Z

Oui c'est possible. Il suffit d'appeler ça:

class Foo(object):
    def method1(self):
        pass
    def method2(self, method):
        return method()

foo = Foo()
foo.method2(foo.method1)
33
unbeknown

Voici votre exemple réécrit pour montrer un exemple de travail autonome:

class Test:
    def method1(self):
        return 'hello world'

    def method2(self, methodToRun):
        result = methodToRun()
        return result

    def method3(self):
        return self.method2(self.method1)

test = Test()

print test.method3()
12
Trent

Oui; les fonctions (et méthodes) sont des objets de première classe en Python. Les oeuvres suivantes:

def foo(f):
    print "Running parameter f()."
    f()

def bar():
    print "In bar()."

foo(bar)

Les sorties:

Running parameter f().
In bar().

Il est facile de répondre à ces questions en utilisant l’interprète Python ou, pour plus de fonctionnalités, le shell IPython .

5
lt_kije

Si vous voulez passer une méthode d'une classe en tant qu'argument mais que vous n'avez pas encore l'objet sur lequel vous allez l'appeler, vous pouvez simplement passer l'objet une fois que vous l'avez comme premier argument (c'est-à-dire le "self" argument).

class FooBar:

    def __init__(self, prefix):
        self.prefix = prefix

    def foo(self, name):
        print "%s %s" % (self.prefix, name)


def bar(some_method):
    foobar = FooBar("Hello")
    some_method(foobar, "World")

bar(FooBar.foo)

Cela imprimera "Bonjour le monde"

3
FrontSide

Beaucoup de bonnes réponses mais étrange que personne n'ait mentionné l'utilisation d'une fonction lambda.
Donc, si vous n’avez pas d’arguments, les choses deviennent assez triviales:

def method1():
    return 'hello world'

def method2(methodToRun):
    result = methodToRun()
    return result

method2(method1)

Mais disons que vous avez un (ou plusieurs) arguments dans method1:

def method1(spam):
    return 'hello ' + str(spam)

def method2(methodToRun):
    result = methodToRun()
    return result

Ensuite, vous pouvez simplement invoquer method2 Comme method2(lambda: method1('world')).

method2(lambda: method1('world'))
>>> hello world
method2(lambda: method1('reader'))
>>> hello reader

Je trouve cela beaucoup plus propre que les autres réponses mentionnées ici.

2
Scrotch

Les méthodes sont des objets comme les autres. Ainsi, vous pouvez les faire circuler, les stocker dans des listes et des dictionnaires, faire ce que vous voulez avec eux. La particularité d’eux est qu’ils sont des objets appelables afin que vous puissiez invoquer __call__ Dessus. __call__ Est appelé automatiquement lorsque vous appelez la méthode avec ou sans arguments, il vous suffit donc d'écrire methodToRun().

2
Vasil