Come faccio a passare un metodo come parametro in Python


191

È possibile passare un metodo come parametro a un metodo?

self.method2(self.method1)

def method1(self):
    return 'hello world'

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

Risposte:


263

Sì, basta usare il nome del metodo, come hai scritto. I metodi / le funzioni sono oggetti in Python, proprio come qualsiasi altra cosa, e puoi passarli nel modo in cui fai le variabili. In effetti, puoi pensare a un metodo (o funzione) come una variabile il cui valore è l'oggetto di codice richiamabile effettivo.

Cordiali saluti, non esiste un callmetodo - penso che sia chiamato __call__, ma non è necessario invocarlo esplicitamente:

def method1():
    return 'hello world'

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

method2(method1)

Se vuoi method1essere chiamato con argomenti, le cose diventano un po 'più complicate. method2deve essere scritto con un po 'di informazioni su come passare argomenti method1, e deve ottenere valori per tali argomenti da qualche parte. Ad esempio, se method1si suppone che prenda un argomento:

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

allora potresti scrivere method2per chiamarlo con un argomento che viene passato:

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

o con un argomento che si calcola da solo:

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

È possibile espandere questo ad altre combinazioni di valori passati e valori calcolati, come

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)

o anche con argomenti di parole chiave

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

Se non sai, durante la scrittura method2, quali argomenti methodToRunprenderanno, puoi anche utilizzare l'argomento unpacking per chiamarlo in modo generico:

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'})

In questo caso positional_argumentsdeve essere un elenco o una tupla o simile, ed keyword_argumentsè un dettato o simile. In method2è possibile modificare positional_argumentse keyword_arguments(ad esempio per aggiungere o rimuovere determinati argomenti o modificare i valori) prima di chiamare method1.


34

Sì, è possibile. Basta chiamarlo:

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

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

1
cosa succede se non c'è istanza foo?
Lei Yang,

1
Quindi semplicemente non hai bisogno di foo, ad esempio: def method1(): pass def method2(method) return method() method2(method1)
Tom

14

Ecco il tuo esempio riscritto per mostrare un esempio di lavoro autonomo:

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()

6

Sì; funzioni (e metodi) sono oggetti di prima classe in Python. Le seguenti opere:

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

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

foo(bar)

Uscite:

Running parameter f().
In bar().

Questi tipi di domande sono banali a cui rispondere utilizzando l'interprete Python o, per ulteriori funzioni, la shell IPython .


5

Se vuoi passare un metodo di una classe come argomento ma non hai ancora l'oggetto su cui lo chiamerai, puoi semplicemente passare l'oggetto una volta che lo hai come primo argomento (cioè il "sé" discussione).

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)

Questo stamperà "Hello World"


5

Molte buone risposte ma strane che nessuno ha menzionato usando una lambdafunzione.
Quindi se non hai argomenti, le cose diventano piuttosto banali:

def method1():
    return 'hello world'

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

method2(method1)

Ma supponiamo che tu abbia uno (o più) argomenti in method1:

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

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

Quindi puoi semplicemente invocare method2come method2(lambda: method1('world')).

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

Lo trovo molto più pulito rispetto alle altre risposte menzionate qui.


Se questo fosse un valore in un dizionario, come potrei eseguirlo anziché restituire un oggetto funzione? Modifica: Ho appena realizzato che posso semplicemente mettere ()alla fine dell'oggetto nella mia chiamata di ritorno, duh.
vaponteblizzard,

3

I metodi sono oggetti come gli altri. Quindi puoi passarli in giro, archiviarli in liste e dadi, fare quello che vuoi con loro. La cosa speciale su di loro è che sono oggetti richiamabili in modo da poterli invocare __call__. __call__viene chiamato automaticamente quando invochi il metodo con o senza argomenti, quindi devi solo scrivere methodToRun().


0

Non esattamente quello che vuoi, ma è uno strumento utile correlato getattr(), usare il nome del metodo come parametro.

class MyClass:
   def __init__(self):
      pass
   def MyMethod(self):
      print("Method ran")

# Create an object
object = MyClass()
# Get all the methods of a class
method_list = [func for func in dir(MyClass) if callable(getattr(MyClass, func))]
# You can use any of the methods in method_list
# "MyMethod" is the one we want to use right now

# This is the same as running "object.MyMethod()"
getattr(object,'MyMethod')()
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.