【问题标题】:What is the most pythonic way to make a bound method act like a function?使绑定方法像函数一样的最pythonic方法是什么?
【发布时间】:2010-10-04 04:13:16
【问题描述】:

我正在使用一个 Python API,它希望我向它传递一个函数。但是,由于各种原因,我想向它传递一个方法,因为我希望函数根据它所属的实例表现出不同的行为。如果我向它传递一个方法,API 将不会使用正确的“self”参数调用它,所以我想知道如何将一个方法变成一个知道它属于什么“self”的函数。

我可以想到几种方法来做到这一点,包括使用 lambda 和闭包。我在下面提供了一些示例,但我想知道是否有实现相同效果的标准机制。

class A(object):
    def hello(self, salutation):
        print('%s, my name is %s' % (salutation, str(self)))

    def bind_hello1(self):
        return lambda x: self.hello(x)

    def bind_hello2(self):
        def hello2(*args):
            self.hello(*args)
        return hello2


>>> a1, a2 = A(), A()
>>> a1.hello('Greetings'); a2.hello('Greetings')
Greetings, my name is <__main__.A object at 0x71570>
Greetings, my name is <__main__.A object at 0x71590>

>>> f1, f2 = a1.bind_hello1(), a2.bind_hello1()
>>> f1('Salutations'); f2('Salutations')
Salutations, my name is <__main__.A object at 0x71570>
Salutations, my name is <__main__.A object at 0x71590>

>>> f1, f2 = a1.bind_hello2(), a2.bind_hello2()
>>> f1('Aloha'); f2('Aloha')
Aloha, my name is <__main__.A object at 0x71570>
Aloha, my name is <__main__.A object at 0x71590>

【问题讨论】:

    标签: python function methods closures


    【解决方案1】:

    传递绑定到实例的方法会起作用吗?如果是这样,你不必做任何特别的事情。

    In [2]: class C(object):
       ...:     def method(self, a, b, c):
       ...:         print a, b, c
       ...:
       ...:
    
    In [3]: def api_function(a_func):
       ...:     a_func("One Fish", "Two Fish", "Blue Fish")
       ...:
       ...:
    
    In [4]: c = C()
    
    In [5]: api_function(c.method)
    One Fish Two Fish Blue Fish
    

    【讨论】:

      【解决方案2】:

      您可能想澄清您的问题。正如 Ryan 指出的那样,

      def callback(fn):
          fn('Welcome')
      callback(a1.hello)
      callback(a2.hello)
      

      将导致hello 以正确的self 绑定、a1a2 调用。如果您没有遇到这种情况,那就是大错特错了,因为 Python 就是这样工作的。

      从你写的内容来看,你似乎想要的是绑定参数——换句话说,currying。您可以在各处找到示例,但根据我的口味,Recipe 52549 具有最好的 Pythonic 外观。

      class curry:
          def __init__(self, fun, *args, **kwargs):
              self.fun = fun
              self.pending = args[:]
              self.kwargs = kwargs.copy()
      
          def __call__(self, *args, **kwargs):
              if kwargs and self.kwargs:
                  kw = self.kwargs.copy()
                  kw.update(kwargs)
              else:
                  kw = kwargs or self.kwargs
      
              return self.fun(*(self.pending + args), **kw)
      
      f1 = curry(a1.hello, 'Salutations')
      f1()  #  == a1.hello('Salutations')
      

      【讨论】:

      • 维基百科称它们为同一事物。 en.wikipedia.org/wiki/Currying "柯里化的实际动机是,通常通过向柯里化函数提供部分但不是全部参数来获得函数(通常称为部分应用)"
      猜你喜欢
      • 2014-09-06
      • 2015-09-11
      • 2020-11-20
      • 2022-12-15
      • 1970-01-01
      • 1970-01-01
      • 2014-05-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多