代码之家  ›  专栏  ›  技术社区  ›  cindy50633

在创建新实例时,python中的类变量是否会再次声明?

  •  2
  • cindy50633  · 技术社区  · 7 年前

    我正在练习以下代码:

    class MITPerson(Person): # a subclass of class Person
    
        nextIdNum = 0 # identification number
    
        def __init__(self, name):
            Person.__init__(self, name)
            self.idNum = MITPerson.nextIdNum 
            MITPerson.nextIdNum += 1 
    
        def getIdNum(self):
            return self.idNum
    

    作为参考,以下是超类:

    class Person(object):  # superclass
    
        def __init__(self, name):
            """Create a person"""
            self.name = name
    

    我想我已经知道了这个问题的答案,因为我尝试了以下实例:

    p1 = MITPerson('Mark Guttag')
    p2 = MITPerson('Billy Bob Beaver')
    p3 = MITPerson('Billy Bob Beaver')
    

    毫不奇怪,当我在控制台中键入以下内容时:

    [12]中:p1。getIdNum()

    Out[12]:0

    在[13]中:p3。getIdNum()

    Out[13]:2

    我已经阅读了这篇文章,并在这里检查了所有优秀的答案: Static class variables in Python

    我觉得奇怪的是,为什么p2和p3不能再次将nextIdNum绑定到0? 在我的想象中,一旦创建了一个类MITPerson,就应该将该类变量重新分配为0,而不调用该方法。

    我错过什么了吗?

    顺便说一下,我也在这里阅读了教程: https://docs.python.org/3.6/tutorial/classes.html#class-objects

    然而,恐怕它没有给出答案:(

    2 回复  |  直到 7 年前
        1
  •  9
  •   Daniel    7 年前

    我看到,在创建第一个实例p1时,nextIdNum被指定为0。

    这是错误的。 nextIdNum 定义类时,将分配给0。

        2
  •  2
  •   chepner    7 年前

    A. class 语句是对 type 。对正文中的语句进行求值,然后将其添加到 dict 已传递给 类型

    你的大致相当于

    def _init_(self, name):
        Person.__init__(self, name)
        self.idNum = MITPerson.nextIdNum
        MITPerson.nextIDNum += 1
    
    def _getIdNum(self):
        return self.idNum
    
    MITPerson = type(
        'MITPerson',
        (Person,),
        {
            '__init__': _init,
            'getIdNum': _getIdNum,
            'nextIdNum': 0
        }
    )
    
    del _init, _getIdNum
    

    你可以看到 nextIdNum 在的任何实例之前立即初始化为0 MITPerson 都是创建的,就像 __init__ getIdNum


    1. MITPerson('Mark Guttag') 决定 type.__call__(MITPerson, 'Mark Guttag')
    2. __call__ 调用 MITPerson.__new__('Mark Guttag') ,它将创建的新实例 MITPONER公司
    3. 新值传递给 MITPerson.__init__ ,此时 MITPerson.nextIdNum 在递增类变量之前使用。
    4. 一旦 __初始化__ 退货, __new__ 返回指定给该值的点 p1

    请注意 语句再次执行,但函数 __初始化__ 定义有。