【问题标题】:Python - function as class attribute becomes a bound methodPython - 作为类属性的函数成为绑定方法
【发布时间】:2016-05-21 04:35:02
【问题描述】:

我注意到,如果我在创建该类的实例时定义了与函数相等的类属性,则该属性将成为绑定方法。有人可以解释一下这种行为的原因吗?

In [9]: def func():
   ...:     pass
   ...: 

In [10]: class A(object):
   ....:     f = func
   ....:     

In [11]: a = A()

In [12]: a.f
Out[12]: <bound method A.func of <__main__.A object at 0x104add190>>

In [13]: a.f()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-13-19134f1ad9a8> in <module>()
----> 1 a.f()
    global a.f = <bound method A.func of <__main__.A object at 0x104add190>>

TypeError: func() takes no arguments (1 given)

【问题讨论】:

    标签: python methods class-attributes


    【解决方案1】:

    晚了一点,但另一个可行的解决方案是将函数存储为字典,这是类的一个属性。

    # Some arbitrary function
    def f(x):
      return x
    
    # A class, which will wrap the function as a dictionary object, which is a class attr
    class Test:
      def __init__(self,f):
        self.f = {'f':f}
      
      def func(self,x):
        return self.f['f'](x)
    
    # Now let's test the Test object
    t = Test(f=f)
    t.func(3)
    
    >>>
    3
    

    这种方法比公认的答案更冗长,但是,它不涉及静态方法、装饰器或其他高级主题。因此,如果您被另一种首选方法吓倒,这将在紧要关头起作用。

    编辑:如果您希望它足够强大以处理关键字参数:

    class Test:
      def __init__(self,f):
        self.f = {'f':f}
      
      def func(self,p):
        return self.f['f'](**p)
    
    def f(**p):
      return p['x'] * p['y']
    
    t = Test(f=f)
    t.func({'x':2,'y':3})
    
    >>>
    6
    

    【讨论】:

      【解决方案2】:

      您为属性A.f(A 类的属性f)分配了一个函数。属性A.f 被定义为类的一部分。它是一个函数,因此默认情况下它是该类的实例方法。

      创建类A 的实例(名为a)会导致该实例具有属性f,并且您可以通过名称a.f 访问它。这是一个绑定方法(因为它绑定到对象a;further explanation here)。

      每个实例方法在被调用时都会自动接收实例作为其第一个参数(通常命名为self)。其他类型的方法也是可能的:- 参见class methods and static methods。

      由于这个原因,错误提示 func 不接受任何参数(因为它被定义为 def func():)但收到了 1 (self)。

      要做你想做的事,你应该告诉python你正在使用static method

      def func():
          pass
      
      class A(object):
          f = staticmethod(func)
      

      【讨论】:

        【解决方案3】:

        Python 不是基于消息的 OO 系统1。相反,类似于 JavaScript,属性被解析为一等函数,然后被调用;如发现的那样,这种行为的机制略有不同。

        在 Python 中,要求方法至少有一个参数,通常称为 self,该参数将自动提供给关联的实例当作为方法调用时。

        此外(也许是问题的重点),Python 在建立实例成员绑定时不区分使用def f.. 或f = some_func();可以说这匹配了类之外的行为。

        在示例中,将函数分配给实例“使其期望被视为实例方法”。在这两种情况下调用的函数完全相同 - 无参数 - 函数;只有此类的未来使用是相关的。

        现在,与 JavaScript 不同,Python 通过绑定方法的概念处理方法和对象关联 - 解析为方法的函数始终是“绑定”的。

        a.f 返回绑定方法的行为 - 将自动将绑定对象作为 self 提供给第一个参数的函数 - 独立于函数的源完成。在这种情况下,这意味着无参数函数在“绑定”时无法使用,因为它不接受 self 参数。

        作为演示,以下内容将以相同的方式失败,因为源底层方法确实不满足接受实例作为参数的最低要求:

        g = a.f
        g()
        

        在这种情况下,调用g() 等同于调用func(a)。


        1 为了比较,Java、C#、Ruby 和 SmallTalk 是基于消息的 OO 系统 - 在这些系统中,对象被告知通过“名称”调用方法,而不是解析方法(或函数)作为可以调用的值。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-04-09
          • 1970-01-01
          • 2020-12-25
          • 1970-01-01
          • 1970-01-01
          • 2021-02-04
          • 1970-01-01
          相关资源
          最近更新 更多