【问题标题】:How do I pass a method as a parameter in Python如何在 Python 中将方法作为参数传递
【发布时间】:2010-10-16 22:38:05
【问题描述】:

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

self.method2(self.method1)

def method1(self):
    return 'hello world'

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

【问题讨论】:

    标签: python parameter-passing


    【解决方案1】:

    是的,只需使用您所写的方法名称即可。方法和函数是 Python 中的对象,就像其他任何东西一样,您可以像处理变量一样传递它们。实际上,您可以将方法(或函数)视为一个变量,其值为实际可调用的代码对象。

    由于您询问了方法,因此我在以下示例中使用了方法,但请注意,以下所有内容都同样适用于函数(除了没有 self 参数)。

    要调用传递的方法或函数,只需使用绑定的名称,就像使用方法(或函数)的常规名称一样:

    def method1(self):
        return 'hello world'
    
    def method2(self, methodToRun):
        result = methodToRun()
        return result
    
    obj.method2(obj.method1)
    

    注意:我相信__call__() 方法确实存在,即您可以在技术上执行methodToRun.__call__(),但您可能永远不应该明确这样做。 __call__() 旨在实现,而不是从您自己的代码中调用。

    如果您希望使用参数调用 method1,那么事情会变得有点复杂。 method2 必须包含一些关于如何将参数传递给method1 的信息,并且它需要从某个地方获取这些参数的值。例如,如果 method1 应该接受一个参数:

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

    然后你可以写method2 来调用它,并使用一个传入的参数:

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

    或使用它自己计算的参数:

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

    您可以将此扩展为传入的值和计算的值的其他组合,例如

    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)
    

    甚至使用关键字参数

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

    如果你不知道,在写method2的时候,methodToRun要取什么参数,你也可以用参数解包的方式来通用调用它:

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

    在这种情况下,positional_arguments 需要是一个列表或元组或类似的,keyword_arguments 是一个字典或类似的。在method2 中,您可以在调用method1 之前修改positional_argumentskeyword_arguments(例如添加或删除某些参数或更改值)。

    【讨论】:

    • 我对你明显将 methodfunction 混为一谈感到困惑。 def method1(spam): 是函数定义,不是方法定义。
    • @MichaelDorst 是的,据我所知,我使用“方法”来与问题中使用的术语保持一致,即使这些在技术上是功能。我认为方法和函数之间的区别会分散我试图提出的主要观点。虽然我想我可以通过编辑来清除它......但我不确定它是否值得。
    • 您回答的问题与被问到的不同。 OP询问您是否可以将方法作为参数传递,例如func(obj.method)。您解释了如何将函数作为参数传递,例如func(other_func),但同时将函数称为方法。我觉得这很令人困惑。
    • @MichaelDorst 哦,我明白你的意思了。我没有意识到有人会如此纠结于方法/功能的区别。让我做一个澄清的编辑。
    【解决方案2】:

    是的,这是可能的。就叫它吧:

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

    【讨论】:

    • 如果没有实例foo怎么办?
    • 那你根本不需要 foo,例如:def method1(): pass def method2(method) return method() method2(method1)
    【解决方案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 可以轻松回答这类问题。

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

        方法和其他对象一样。所以你可以传递它们,将它们存储在列表和字典中,对它们做任何你喜欢的事情。它们的特殊之处在于它们是可调用对象,因此您可以在它们上调用__call____call__ 会在您调用带有或不带参数的方法时自动调用,因此您只需编写 methodToRun()

        【讨论】:

          【解决方案6】:

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

          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”

          【讨论】:

            【解决方案7】:

            使用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
            

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

            【讨论】:

            • 如果这是字典中的一个值,我怎么能执行它而不是返回一个函数对象?编辑:刚刚意识到我可以将() 放在我的回叫中对象的末尾,呵呵。
            【解决方案8】:

            不完全是你想要的,但一个相关的有用工具是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')()
            

            【讨论】:

              【解决方案9】:

              示例:一个简单的函数调用包装器:

              def measure_cpu_time(f, *args):
                  t_start = time.process_time()
                  ret = f(*args)
                  t_end = time.process_time()
                  return t_end - t_start, ret
              

              【讨论】:

                猜你喜欢
                • 2017-07-29
                • 1970-01-01
                • 2017-10-12
                • 2019-02-11
                • 2011-10-14
                • 2015-08-19
                • 2013-08-10
                相关资源
                最近更新 更多