Jak przekazać metodę jako parametr w Pythonie


190

Czy można przekazać metodę jako parametr do metody?

self.method2(self.method1)

def method1(self):
    return 'hello world'

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

Odpowiedzi:


263

Tak, po prostu użyj nazwy metody, tak jak napisałeś. Metody / funkcje są obiektami w Pythonie, tak jak wszystko inne, i możesz przekazywać je w sposób, w jaki robisz zmienne. W rzeczywistości można myśleć o metodzie (lub funkcji) jako zmiennej, której wartością jest rzeczywisty obiekt kodu, który można wywołać.

Do Twojej wiadomości, nie ma callmetody - myślę, że się nazywa __call__, ale nie musisz jej jawnie wywoływać:

def method1():
    return 'hello world'

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

method2(method1)

Jeśli chcesz method1zostać wywołany argumentami, sprawy stają się nieco bardziej skomplikowane. method2musi być napisany z odrobiną informacji o tym, jak przekazywać argumenty method1, i musi skądś uzyskać wartości dla tych argumentów. Na przykład, jeśli method1ma przyjąć jeden argument:

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

wtedy możesz napisać, method2aby to wywołać z jednym argumentem, który zostanie przekazany:

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

lub z argumentem, że oblicza się:

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

Możesz rozwinąć to do innych kombinacji przekazywanych wartości i obliczanych wartości, takich jak

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)

lub nawet z argumentami słów kluczowych

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

Jeśli nie wiesz, podczas pisania method2, jakie argumenty methodToRunchcesz wziąć, możesz również użyć rozpakowywania argumentów, aby wywołać je w ogólny sposób:

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

W takim przypadku positional_argumentsmusi to być lista, krotka lub podobne i keyword_argumentsjest to dykt lub podobne. W method2możesz zmodyfikować positional_argumentsi keyword_arguments(np. Dodać lub usunąć niektóre argumenty lub zmienić wartości) przed wywołaniem method1.


34

Tak to mozliwe. Po prostu nazwij to:

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

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

1
co jeśli nie ma instancji foo?
Lei Yang

1
Wtedy po prostu nie potrzebujesz foo, np .: def method1(): pass def method2(method) return method() method2(method1)
Tom

14

Oto Twój przykład przepisany od nowa, aby pokazać samodzielny przykład działania:

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

Tak; funkcje (i metody) są obiektami pierwszej klasy w Pythonie. Następujące prace:

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

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

foo(bar)

Wyjścia:

Running parameter f().
In bar().

Na tego rodzaju pytania można łatwo odpowiedzieć za pomocą interpretera języka Python lub, w celu uzyskania większej liczby funkcji, powłoki IPython .


5

Jeśli chcesz przekazać metodę klasy jako argument, ale nie masz jeszcze obiektu, do którego chcesz ją wywołać, możesz po prostu przekazać obiekt, gdy masz go jako pierwszy argument (tzn. „Ja” 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)

Spowoduje to wydrukowanie „Hello World”


4

Wiele dobrych odpowiedzi, ale dziwne, że nikt nie wspomniał o użyciu lambdafunkcji.
Więc jeśli nie masz argumentów, sprawy stają się dość trywialne:

def method1():
    return 'hello world'

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

method2(method1)

Ale powiedz, że masz jeden (lub więcej) argumentów w method1:

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

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

Następnie możesz po prostu wywołać method2jako method2(lambda: method1('world')).

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

Uważam, że jest to o wiele czystsze niż inne odpowiedzi tutaj wymienione.


Gdyby była to wartość w słowniku, jak mógłbym ją wykonać zamiast zwracać obiekt funkcji? Edycja: Właśnie zdałem sobie sprawę, że mogę po prostu umieścić ()na końcu obiektu w swoim wywołaniu zwrotnym, duh.
vaponteblizzard

3

Metody są obiektami jak każdy inny. Możesz je przekazywać, przechowywać na listach i dyktandach, robić z nimi co tylko zechcesz. Szczególną rzeczą w nich jest to, że są obiektami, które można wywoływać, więc możesz je wywoływać __call__. __call__jest wywoływany automatycznie, gdy wywołujesz metodę z argumentami lub bez, więc wystarczy napisać methodToRun().


0

Nie do końca to, czego chcesz, ale pokrewnym przydatnym narzędziem jest getattr()użycie nazwy metody jako parametru.

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')()
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.