Як передати метод як параметр у Python


190

Чи можна передати метод як параметр методу?

self.method2(self.method1)

def method1(self):
    return 'hello world'

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

Відповіді:


263

Так, просто використовуйте назву методу, як ви написали. Методи / функції - це об'єкти в Python, як і будь-що інше, і ви можете передавати їх навколо того, як ви робите змінні. Насправді, ви можете думати про метод (або функцію) як про змінну, значенням якої є фактичний об'єкт коду, що дзвониться.

FYI, 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це диктант чи подібний. У 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"


4

Дуже багато хороших відповідей, але дивних, що ніхто не згадав про використання 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.