Как передать метод в качестве параметра в Python


191

Можно ли передать метод в качестве параметра метода?

self.method2(self.method1)

def method1(self):
    return 'hello world'

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

Ответы:


263

Да, просто используйте имя метода, как вы написали. Методы / функции являются объектами в Python, как и все остальное, и вы можете передавать их так же, как вы делаете переменные. Фактически, вы можете думать о методе (или функции) как о переменной, значение которой является фактическим вызываемым объектом кода.

К вашему сведению, callметода нет - я думаю, что он __call__вызывается, но вам не нужно вызывать его явно:

def method1():
    return 'hello world'

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

method2(method1)

Если вы хотите, method1чтобы вас вызывали с аргументами, то все немного сложнее. method2должен быть написан с небольшим количеством информации о том, как передавать аргументы method1, и он должен получить значения для этих аргументов откуда-то. Например, если method1предполагается принять один аргумент:

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

тогда вы могли бы написать method2для вызова его с одним аргументом, который передается в:

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

или с аргументом, что он вычисляет сам:

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

Вы можете расширить это для других комбинаций значений, переданных и значений, вычисленных, как

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)

или даже с аргументами ключевых слов

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

Если вы не знаете, при написании method2 , какие аргументы methodToRunбудут принимать, вы можете также использовать распаковку аргументов, чтобы вызвать его обобщенным способом:

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

В этом случае positional_argumentsдолжен быть список или кортеж или подобное, и keyword_argumentsявляется dict или подобным. В method2вы можете изменить positional_argumentsи keyword_arguments(например , добавлять или удалять определенные аргументы или изменить значение) перед вызовом method1.


34

Да, это возможно. Просто назовите это:

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

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

1
что если нет экземпляра foo?
Лей Ян

1
Тогда вам просто не нужен foo, например: def method1(): pass def method2(method) return method() method2(method1)
Том

14

Вот ваш пример переписан, чтобы показать автономный рабочий пример:

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

Да; функции (и методы) являются объектами первого класса в Python. Следующие работы:

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

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

foo(bar)

Выходы:

Running parameter f().
In bar().

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


5

Если вы хотите передать метод класса в качестве аргумента, но у вас еще нет объекта, для которого вы собираетесь его вызывать, вы можете просто передать объект, как только он у вас появится в качестве первого аргумента (то есть «я») аргумент).

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)

Это напечатает "Hello World"


5

Много хороших ответов, но странно, что никто не упомянул об использовании lambdaфункции.
Поэтому, если у вас нет аргументов, все становится довольно тривиально:

def method1():
    return 'hello world'

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

method2(method1)

Но скажем, у вас есть один (или несколько) аргументов в method1:

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

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

Тогда вы можете просто вызвать method2как method2(lambda: method1('world')).

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

Я считаю, что это намного чище, чем другие ответы, упомянутые здесь.


Если бы это было значение в словаре, как я мог бы выполнить его, а не возвращать объект функции? Изменить: Просто понял, что я могу просто положить ()в конце объекта в моем обратном вызове, дух.
vaponteblizzard

3

Методы являются объектами, как и любые другие. Таким образом, вы можете передавать их, хранить их в списках и диктовках, делать с ними все, что угодно. Особенность их в том, что они являются вызываемыми объектами, поэтому вы можете вызывать __call__их. __call__вызывается автоматически, когда вы вызываете метод с аргументами или без них, поэтому вам просто нужно написать methodToRun().


0

Не совсем то, что вы хотите, но связанный полезный инструмент - getattr()использовать имя метода в качестве параметра.

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')()
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.