python中cls与self与类调用

2024-10-04 01:32:03 发布

您现在位置:Python中文网/ 问答频道 /正文

我是Python的初学者,使用Lutz的书来理解classmethodstaticmethod和{}。此代码的目标是通过计算创建的实例数来了解clsself和直接类调用(Spam1.numInstances)之间的区别。在

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

我的代码是:

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显示“no reference”。由于沮丧,我读了一些这样的帖子:What does cls() function do inside a class method?What is the 'cls' variable used for in Python classes?,和{a3},但我不明白到底发生了什么。在

具体来说,我的问题是:

a)为什么在创建de和{}时,Spam1.numInstances没有增加?

我想回答这个问题:

我的理解是cls用于访问类属性。对于de,使用self.numInstances访问实例属性,因为Sub1Spam1继承的属性numInstances的值归零。cls访问Sub1的class属性,这与Sub1类的属性相同。因此,我们在输出中看到的self和{}值分别是Sub1实例和类。我的理解正确吗?

a.ii)fSpam1继承{}。因此,self.numInstances和{}取Spam1中的值。它们的值是递增的,但不是Spam1,因为cls引用Other1,因为{}引用{},这是{}的对象。因此,Spam1numInstances永远不会被触摸。

b)我对self.numInstancescls.numInstances和{}之间的差异的理解正确吗?如果没有,有人能解释一下吗?

我认为我的问题很基本。我希望有人能帮我。我迷路了。在


Tags: 实例代码selfoutput属性countclasscls
2条回答

你有几个误解:

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

当您使用Sub1的实例时,Spam1numInstances属性是不可访问的(除了显式地写入Spam1.numInstances);count()中的cls引用{},并且该属性位于该类中,因此无需进一步查找继承链。在

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

在您的代码中有三个不同的类属性,名为numInstances:两个在类Spam1和{}定义后立即存在,另一个在{}的第一个实例创建后存在。在

相关问题 更多 >