gpt4 book ai didi

python - 不同类型的类变量有什么区别?

转载 作者:太空狗 更新时间:2023-10-30 01:23:10 27 4
gpt4 key购买 nike

首先,类 A 有两个类变量和两个实例变量:

In [1]: def fun(x, y): return x + y

In [2]: class A:
...: cvar = 1
...: cfun = fun
...: def __init__(self):
...: self.ivar = 100
...: self.ifun = fun

我们可以看到类变量和int类型的实例变量都可以正常工作:

In [3]: a = A()

In [4]: a.ivar, a.cvar
Out[4]: (100, 1)

但是,如果我们检查函数类型变量,情况就会发生变化:

In [5]: a.ifun, a.cfun
Out[5]:
(<function __main__.fun>,
<bound method A.fun of <__main__.A instance at 0x25f90e0>>)

In [6]: a.ifun(1,2)
Out[6]: 3

In [7]: a.cfun(1,2)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/home/future/<ipython-input-7-39aa8db2389e> in <module>()
----> 1 a.cfun(1,2)

TypeError: fun() takes exactly 2 arguments (3 given)

我知道 python 已将 a.cfun(1,2) 转换为 A.cfun(a,1,2) 然后出现错误。

我的问题是:因为cvarcfun 都是类变量,为什么python 以不同的方式对待它们?

最佳答案

实际上,分配给类成员的函数仍然是函数:

def x():pass

class A:
f = x
e = None
g = None

print(A.__dict__['f'])
# <function x at 0x10e0a6e60>

当您从实例中检索它时,它会即时转换为方法对象:

print(A().f)
# <bound method A.x of <__main__.A instance at 0x1101ddea8>>

http://docs.python.org/2/reference/datamodel.html#the-standard-type-hierarchy “用户定义的方法”:

User-defined method objects may be created when getting an attribute of a class (perhaps via an instance of that class), if that attribute is a user-defined function object, an unbound user-defined method object, or a class method object... Note that the transformation from function object to (unbound or bound) method object happens each time the attribute is retrieved from the class or instance.

这种转换只发生在分配给类的函数上,不会发生在实例上。请注意,这在 Python 3 中已更改,其中 Class.fun 返回普通函数,而不是“未绑定(bind)方法”。

关于您的问题,为什么需要这样做,方法对象本质上是一个包含函数及其执行上下文(“self”)的闭包。想象一下你有一个对象并在某处使用它的方法作为回调。在许多其他语言中,您必须同时传递对象和方法指针或手动创建闭包。例如,在 javascript 中:

  myListener = new Listener()
something.onSomeEvent = myListener.listen // won't work!
something.onSomeEvent = function() { myListener.listen() } // works

Python 在幕后为我们管理:

  myListener = Listener()
something.onSomeEvent = myListener.listen // works

另一方面,有时在类中使用“裸”函数或“外来”方法是可行的:

  def __init__(..., dir, ..):
self.strip = str.lstrip if dir == 'ltr' else str.rstrip
...
def foo(self, arg):
self.strip(arg)

上述约定(类变量 => 方法,实例变量 => 函数)提供了一种同时拥有两者的便捷方式。

无需添加,就像 python 中的其他所有内容一样,可以更改此行为,即编写一个不将其函数转换为方法并按原样返回它们的类。

关于python - 不同类型的类变量有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16140052/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com