python中的cls vs.self vs.Class调用

python中的cls vs.self vs.Class调用,python,class,object,self,Python,Class,Object,Self,我是Python的初学者,使用Lutz的书来理解classmethod、staticmethod和instancemethod。本代码的目的是通过计算创建的实例数来了解cls、self和直接类调用(Spam1.numInstances)之间的差异 这里有一个从这本书中衍生出来的例子。我不确定为什么父类(Spam1)属性(numInstances)在通过子类Sub1和Other1调用时不递增 这是我的密码: class Spam1: numInstances = 0 def cou

我是Python的初学者,使用Lutz的书来理解
classmethod
staticmethod
instancemethod
。本代码的目的是通过计算创建的实例数来了解
cls
self
和直接类调用(
Spam1.numInstances
)之间的差异

这里有一个从这本书中衍生出来的例子。我不确定为什么父类(
Spam1
)属性(
numInstances
)在通过子类
Sub1
Other1
调用时不递增

这是我的密码:

class Spam1:
    numInstances = 0
    def count(cls):
        cls.numInstances += 1
        print("In count -> number of instances: cls, Spam", cls.numInstances, Spam1.numInstances)

    def __init__(self):
        print("-----")
        print("In init, before -> number of instances: self, Spam",self.numInstances,Spam1.numInstances )
        self.count()
        print("In init, after -> number of instances: self, Spam",self.numInstances,Spam1.numInstances )
        print("-----")

    count=classmethod(count)


class Sub1(Spam1):
    numInstances = 0

class Other1(Spam1):
    pass

a=Spam1() #Output after increment: 1,1,1 (self, cls, Spam1)
b=Spam1() #Output after increment: 2,2,2 (self, cls, Spam1)
c=Spam1() #Output after increment: 3,3,3 (self, cls, Spam1)
d=Sub1()  #Output after increment: 1,1,3 (self, cls, Spam1)
e=Sub1()  #Output after increment: 2,2,3 (self, cls, Spam1)
f=Other1() #Output after increment: 4,4,3 (self, cls, Spam1)
我花了一天的时间试图调试这段代码,但我无法理解
cls.numInstances
是如何工作的,因为PyCharm在调试模式下会显示
cls.numInstances
的“无参考”。我很沮丧,读了几篇文章:,和,但我不明白发生了什么

具体来说,我的问题如下:

a)为什么创建
d
e
f
Spam1.numInstances
没有增加?

以下是我试图回答的问题:

a、 i)据我所知,
cls
用于访问类属性。对于
d
e
self.numInstances
用于访问实例属性,该属性为零,因为
Sub1
将继承属性
numInstances
的值从
Spam1
归零
cls
访问
Sub1
的class属性,该属性与
Sub1
类的属性相同。因此,我们在输出中看到的
self
cls
值分别是
Sub1
实例和类的值。我的理解正确吗

a、 ii)
f
Spam1
继承
numInstances
。因此,
f的
self.numInstances
cls.numInstances
Spam1
获取值。由于
cls
指的是
Other1
,而
self
指的是
f
,它是
Other1
的对象,因此它们的值是递增的,但不是
Spam1
。因此,
Spam1
numInstances
从未被触碰过

b)我对
self.numInstances
cls.numInstances
Spam1.numInstances
之间差异的理解是否正确?如果没有,有人能解释一下吗?


我相信我的问题很基本。我希望有人能帮助我。我迷路了。

当您处理
Sub1
的实例时,
Spam1
numInstances
属性是不可访问的(除了显式写入
Spam1.numInstances
)<
count()
中的code>cls
指的是
Sub1
,该属性在该类中找到,因此无需进一步查找继承链


当您处理
Other1
的实例时,对
numInstances
的初始读取确实来自
Spam1
——但一旦您分配了一个值,它就会进入
Other1
(因为
cls
现在是
Other1
),现在,所有对该名称的进一步引用都会发现它取代了Spam1的版本


代码中有三个名为
numInstances
的不同类属性:两个在定义类
Spam1
Sub1
后立即存在,另一个在创建
Other1
的第一个实例后存在,
Spam1
numInstances
属性不可访问(除了显式写入
Spam1.numInstances
)<
count()
中的code>cls指的是
Sub1
,该属性在该类中找到,因此无需进一步查找继承链


当您处理
Other1
的实例时,对
numInstances
的初始读取确实来自
Spam1
——但一旦您分配了一个值,它就会进入
Other1
(因为
cls
现在是
Other1
),现在,所有对该名称的进一步引用都会发现它取代了Spam1的版本


在您的代码中有三个名为
numInstances
的不同类属性:两个在定义类
Spam1
Sub1
时就存在,另一个在创建
Other1
的第一个实例后就存在。

您在这里有一些误解:

  • 在这段代码的任何一点上都没有名为
    numInstances
    的实例属性
    self.numInstances
    检查实例属性,但由于没有为
    self.numInstances
    赋值,因此没有要读取的实例属性,因此对
    self.numInstances
    的访问最终读取类属性
  • f
    并不完全“继承”父类的值。当执行
    cls.numInstances+=1
    时,它尝试查找
    Other1.numInstances
    ,发现它不存在,并检查超类,最终找到
    Spam1.numInstances
    。它增加该值,然后将其分配回
    其他1。numInstances
    (Python中的
    +=
    总是重新分配,即使它在适当的位置执行工作,对于不可变的
    int
    ,工作也不在适当的位置);将来,对
    Other1.numInstances
    的访问将不会检查
    Spam1.numInstances
    ,因为
    Other1
    的属性现在已经存在

  • 你有一些误解:

  • 在这段代码的任何一点上都没有名为
    numInstances
    的实例属性
    self.numInstances
    检查实例属性,但因为没有为