【问题标题】:cls vs. self vs. Class call in pythoncls vs. self vs. python中的类调用
【发布时间】:2018-12-22 08:58:28
【问题描述】:

我是 Python 初学者,通过 Lutz 的书了解classmethodstaticmethodinstancemethod。这段代码的目的是通过计算创建的实例数来了解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 的“无参考”。感到沮丧,我阅读了一些 SO 主题:What does cls() function do inside a class method?What is the 'cls' variable used for in Python classes?Python - self, no self and cls,但我无法理解发生了什么。

具体来说,这是我的问题:

a) 为什么在创建defSpam1.numInstances 没有增加?

这是我试图回答这个问题的尝试:

a.i) 据我了解,cls 用于访问类属性。对于deself.numInstances 用于访问实例属性,该属性为零,因为Sub1 将来自Spam1 的继承属性numInstances 的值归零。 cls 访问Sub1 的类属性,这也与Sub1 类的属性相同。因此,我们在输出中看到的selfcls 值分别是Sub1 实例和类。我的理解正确吗?

a.ii) fSpam1 继承 numInstances。因此,fself.numInstancescls.numInstances 采用来自 Spam1 的值。它们的值是递增的,但不是 Spam1,因为 cls 引用 Other1 并且因为 self 引用 f,这是 Other1 的对象。因此,Spam1numInstances 永远不会被触及。

b) 我对self.numInstancescls.numInstancesSpam1.numInstances 之间差异的理解是否正确?如果不是,有人可以解释一下吗?

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

【问题讨论】:

  • 重要的是要了解selfcls 在这里只是常规名称。他们可能是foobanana。它们的特别之处在于它们是第一个参数,因此当在实例上调用时它们会隐式传递给实例(以及当您使用 classmethod 装饰器时的类)

标签: python class object self


【解决方案1】:

这里有几个误解:

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

【讨论】:

    【解决方案2】:

    当您使用Sub1 的实例时,Spam1numInstances 属性不可访问(除非通过显式写入Spam1.numInstances); count()中的cls指的是Sub1,属性在那个类中,所以不需要再往继承链上找。

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

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

    【讨论】:

      猜你喜欢
      • 2019-02-17
      • 1970-01-01
      • 2011-06-04
      • 1970-01-01
      • 1970-01-01
      • 2011-06-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多