Python - 作为 class 属性成为绑定方法的功能
Python - function as class attribute becomes a bound method
我注意到,如果我在创建 class 的实例时将 class 属性定义为一个函数,该属性将成为绑定方法。有人可以向我解释这种行为的原因吗?
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 不是 基于消息的面向对象系统1。相反,类似于 JavaScript,属性被解析为 first-class 函数,然后被调用;正如所发现的那样,这种行为在机制上略有不同。
在 Python 中,要求方法至少有一个参数,通常称为 self
,当 它时,将自动提供关联实例 作为方法调用。
此外(也许是问题的重点),Python 在建立实例成员绑定时不区分使用 def f..
或 f = some_func()
;可以说这符合 classes.
之外的行为
在示例中,将函数分配给实例'makes it expect to be treated like an instance method'。在这两种情况下调用的函数完全相同——无参数;只有这样的未来用法才相关。
现在,与 JavaScript 不同,Python 通过绑定方法的概念处理方法和对象关联 - 作为方法解析的函数总是 'bound'。
a.f
返回绑定方法的行为 - 将自动将绑定对象作为 self
提供给第一个参数的函数 - 独立于函数源完成。在这种情况下,这意味着无参数函数在 'bound' 时不能使用,因为它不接受 self
参数。
作为演示,以下将以相同的方式失败,因为源底层方法不满足接受实例作为参数的最低要求:
g = a.f
g()
在这种情况下调用 g()
等同于调用 func(a)
.
1 作为比较,Java、C#、Ruby 和 SmallTalk 是基于消息的 OO 系统——在这些系统中,一个对象被告知调用一个'name' 的方法,而不是将方法(或函数)解析为可以调用的值。
您为属性 A.f
(class A
的属性 f
)分配了一个函数。属性 A.f
被定义为 class 的一部分。它是一个函数,因此默认情况下它是 class.
的 实例方法
创建 class A
的实例(名为 a
)会导致该实例具有属性 f
,并且您可以通过名称 [=18] 访问它=].这是一个绑定方法(因为它绑定到对象 a
;)。
每个实例方法在调用时都会自动接收实例作为其第一个参数(通常命名为 self
)。其他类型的方法也是可能的:- 参见 class methods and static methods.
由于这个原因,错误说 func
没有参数(因为它被定义为 def func():
)但是收到了 1 (self
).
要执行您想要的操作,您应该告诉 python 您正在使用 static method
def func():
pass
class A(object):
f = staticmethod(func)
派对有点晚了,但另一个可行的解决方案是将函数存储为字典,这是 class.
的一个属性
# 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
我注意到,如果我在创建 class 的实例时将 class 属性定义为一个函数,该属性将成为绑定方法。有人可以向我解释这种行为的原因吗?
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 不是 基于消息的面向对象系统1。相反,类似于 JavaScript,属性被解析为 first-class 函数,然后被调用;正如所发现的那样,这种行为在机制上略有不同。
在 Python 中,要求方法至少有一个参数,通常称为 self
,当 它时,将自动提供关联实例 作为方法调用。
此外(也许是问题的重点),Python 在建立实例成员绑定时不区分使用 def f..
或 f = some_func()
;可以说这符合 classes.
在示例中,将函数分配给实例'makes it expect to be treated like an instance method'。在这两种情况下调用的函数完全相同——无参数;只有这样的未来用法才相关。
现在,与 JavaScript 不同,Python 通过绑定方法的概念处理方法和对象关联 - 作为方法解析的函数总是 'bound'。
a.f
返回绑定方法的行为 - 将自动将绑定对象作为 self
提供给第一个参数的函数 - 独立于函数源完成。在这种情况下,这意味着无参数函数在 'bound' 时不能使用,因为它不接受 self
参数。
作为演示,以下将以相同的方式失败,因为源底层方法不满足接受实例作为参数的最低要求:
g = a.f
g()
在这种情况下调用 g()
等同于调用 func(a)
.
1 作为比较,Java、C#、Ruby 和 SmallTalk 是基于消息的 OO 系统——在这些系统中,一个对象被告知调用一个'name' 的方法,而不是将方法(或函数)解析为可以调用的值。
您为属性 A.f
(class A
的属性 f
)分配了一个函数。属性 A.f
被定义为 class 的一部分。它是一个函数,因此默认情况下它是 class.
创建 class A
的实例(名为 a
)会导致该实例具有属性 f
,并且您可以通过名称 [=18] 访问它=].这是一个绑定方法(因为它绑定到对象 a
;
每个实例方法在调用时都会自动接收实例作为其第一个参数(通常命名为 self
)。其他类型的方法也是可能的:- 参见 class methods and static methods.
由于这个原因,错误说 func
没有参数(因为它被定义为 def func():
)但是收到了 1 (self
).
要执行您想要的操作,您应该告诉 python 您正在使用 static method
def func():
pass
class A(object):
f = staticmethod(func)
派对有点晚了,但另一个可行的解决方案是将函数存储为字典,这是 class.
的一个属性# 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