不同类型的类变量之间有什么区别?

Eas*_*sun 5 python variables class instance

首先,有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
Run Code Online (Sandbox Code Playgroud)

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

In [3]: a = A()

In [4]: a.ivar, a.cvar
Out[4]: (100, 1)
Run Code Online (Sandbox Code Playgroud)

但是,如果检查函数类型变量,情况就会改变:

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)
Run Code Online (Sandbox Code Playgroud)

我知道python已经转换a.cfun(1,2)A.cfun(a,1,2)然后出错了.

我的问题是:由于这两个cvarcfun是类变量,为什么蟒蛇对待他们的区别呢?

geo*_*org 3

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

def x():pass

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

print(A.__dict__['f'])
# <function x at 0x10e0a6e60>
Run Code Online (Sandbox Code Playgroud)

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

print(A().f)
# <bound method A.x of <__main__.A instance at 0x1101ddea8>>
Run Code Online (Sandbox Code Playgroud)

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

当获取类的属性(可能通过该类的实例)时,如果该属性是用户定义的函数对象、未绑定的用户定义的方法对象或类方法对象,则可以创建用户定义的方法对象。 .. 请注意,每次从类或实例检索属性时,都会发生从函数对象到(未绑定或绑定)方法对象的转换。

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

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

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

Python 在幕后为我们管理这个:

  myListener = Listener()
  something.onSomeEvent = myListener.listen // works
Run Code Online (Sandbox Code Playgroud)

另一方面,有时在类中拥有“裸”函数或“外部”方法是很实用的:

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

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

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