繁体   English   中英

Python - 作为类属性的函数成为绑定方法

[英]Python - function as class attribute becomes a bound method

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

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)

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

创建类A的实例(名为a )会导致该实例具有属性f ,您可以通过名称af访问该属性。 这是一个绑定方法(因为它绑定到对象a这里a 进一步的解释)。

每个实例方法在调用时都会自动接收实例作为其第一个参数(通常命名为self )。 其他类型的方法也是可能的: - 请参阅类方法和静态方法

出于这个原因,错误说func没有参数(因为它被定义为def func(): )但收到了 1 ( self )。

要做你想做的事,你应该告诉 python 你正在使用 静态方法

def func():
    pass

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

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

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

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

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

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

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

作为示范,下面将用同样的方法失败,因为该源底层方法符合接受实例作为参数的最低要求:

g = a.f
g()

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


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

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

# 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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM