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

时间:2016-02-10 17:17:56

标签: python methods class-attributes

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

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)

3 个答案:

答案 0 :(得分:9)

您将一个函数赋予了属性f。因为函数现在在一个类中,它成为一个方法,特别是一个绑定方法(因为它与对象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)

答案 1 :(得分:1)

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系统 - 在这些系统中,一个对象被告知通过'name'调用方法,而不是解析方法(或函数)作为可以调用的值。

答案 2 :(得分:0)

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

# 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