如何在Python中将方法作为参数传递

问题:如何在Python中将方法作为参数传递

是否可以将方法作为参数传递给方法?

self.method2(self.method1)

def method1(self):
    return 'hello world'

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

Is it possible to pass a method as a parameter to a method?

self.method2(self.method1)

def method1(self):
    return 'hello world'

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

回答 0

是的,只需使用您编写的方法名称即可。方法/函数是Python中的对象,就像其他任何对象一样,您可以在执行变量的过程中传递它们。实际上,您可以将方法(或函数)视为变量,其值是实际的可调用代码对象。

仅供参考,没有call方法-我认为它叫做__call__,但是您不必显式调用它:

def method1():
    return 'hello world'

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

method2(method1)

如果您想method1使用参数来调用,那么事情会变得有些复杂。method2必须写一些有关如何将参数传递给的信息method1,并且它需要从某个地方获取这些参数的值。例如,if 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_argumentskeyword_arguments(例如,添加或删除某些参数或更改值)method1

Yes it is, just use the name of the method, as you have written. Methods and functions are objects in Python, just like anything else, and you can pass them around the way you do variables. In fact, you can think about a method (or function) as a variable whose value is the actual callable code object.

Since you asked about methods, I’m using methods in the following examples, but note that everything below applies identically to functions (except without the self parameter).

To call a passed method or function, you just use the name it’s bound to in the same way you would use the method’s (or function’s) regular name:

def method1(self):
    return 'hello world'

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

obj.method2(obj.method1)

Note: I believe a __call__() method does exist, i.e. you could technically do methodToRun.__call__(), but you probably should never do so explicitly. __call__() is meant to be implemented, not to be invoked from your own code.

If you wanted method1 to be called with arguments, then things get a little bit more complicated. method2 has to be written with a bit of information about how to pass arguments to method1, and it needs to get values for those arguments from somewhere. For instance, if method1 is supposed to take one argument:

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

then you could write method2 to call it with one argument that gets passed in:

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

or with an argument that it computes itself:

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

You can expand this to other combinations of values passed in and values computed, like

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

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

or even with keyword arguments

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

If you don’t know, when writing method2, what arguments methodToRun is going to take, you can also use argument unpacking to call it in a generic way:

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

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

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

In this case positional_arguments needs to be a list or tuple or similar, and keyword_arguments is a dict or similar. In method2 you can modify positional_arguments and keyword_arguments (e.g. to add or remove certain arguments or change the values) before you call method1.


回答 1

是的,有可能。只是称呼它:

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

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

Yes it is possible. Just call it:

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

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

回答 2

这是重写您的示例以显示一个独立的工作示例:

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

Here is your example re-written to show a stand-alone working example:

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

回答 3

是; 函数(和方法)是Python中的一流对象。以下作品:

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

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

foo(bar)

输出:

Running parameter f().
In bar().

使用Python解释器或IPython shell (对于更多功能)可以轻松回答这些问题。

Yes; functions (and methods) are first class objects in Python. The following works:

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

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

foo(bar)

Outputs:

Running parameter f().
In bar().

These sorts of questions are trivial to answer using the Python interpreter or, for more features, the IPython shell.


回答 4

如果您想将类的方法作为参数传递,但是还没有要调用的对象,则只需将对象作为第一个参数(即“自身”)传递即可论据)。

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”

If you want to pass a method of a class as an argument but don’t yet have the object on which you are going to call it, you can simply pass the object once you have it as the first argument (i.e. the “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)

This will print “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

然后,您可以简单地调用method2as method2(lambda: method1('world'))

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

我发现这里的答案比这里提到的其他答案要干净得多。

Lots of good answers but strange that no one has mentioned using a lambda function.
So if you have no arguments, things become pretty trivial:

def method1():
    return 'hello world'

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

method2(method1)

But say you have one (or more) arguments in method1:

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

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

Then you can simply invoke method2 as method2(lambda: method1('world')).

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

I find this much cleaner than the other answers mentioned here.


回答 6

方法是任何其他对象。因此,您可以将它们传递出去,将它们存储在列表和字典中,并随心所欲地对其进行操作。关于它们的特殊之处在于它们是可调用对象,因此您可以__call__在它们上调用。__call__当您调用带有或不带有参数的方法时,会被自动调用,因此您只需要编写即可methodToRun()

Methods are objects like any other. So you can pass them around, store them in lists and dicts, do whatever you like with them. The special thing about them is they are callable objects so you can invoke __call__ on them. __call__ gets called automatically when you invoke the method with or without arguments so you just need to write methodToRun().


回答 7

并非完全符合您的需要,但一个相关的有用工具是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')()

Not exactly what you want, but a related useful tool is getattr(), to use method’s name as a parameter.

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