可变的类变量和super()的行为。__init __

时间:2019-08-19 01:04:54

标签: python

我试图理解为什么我的代码表现得如此。基本上,我以两种方式创建了父类和子类。我想发生的是,在为两个类创建的每个实例上, init 方法将更新每个类的num_of_emps计数。所以,如果我有类似的东西:

class Employee:

    num_of_emps = 0

    def __init__(self, first, last, pay, division):
        self.first = first
        self.last = last
        self.pay = pay
        self.division = division
        Employee.num_of_emps += 1

class Manager(Employee):

    num_of_emps = 0

    def __init__(self, first, last, pay, division):
        self.first = first
        self.last = last
        self.pay = pay
        self.division = division
        Manager.num_of_emps += 1

emp1 = Employee("Dallas", "Mat", 100000, "Sales")
emp2 = Employee("Mark", "Doe", 50000, "Marketing")
emp3 = Employee("Jane", "Doe", 50000, "Advertisement")
man1 = Manager("Bob", "Ben", 200000, "Marketing")
man2 = Manager("Ryan", "DS", 200000, "Advertisement")

# Employee.num_of_emps returns 3
# Manager.num_of_emps returns 2

这就是我想要的。但是,如果我添加super。 init ()方法,而不是对Manager类的属性进行硬编码,则会发生其他事情:

class Employee:

    num_of_emps = 0

    def __init__(self, first, last, pay, division):
        self.first = first
        self.last = last
        self.pay = pay
        self.division = division
        Employee.num_of_emps += 1

class Manager(Employee):

    num_of_emps = 0

    def __init__(self, first, last, pay, division):
        super().__init__(first, last, pay, division)
        Manager.num_of_emps += 1

emp1 = Employee("Dallas", "Mat", 100000, "Sales")
emp2 = Employee("Mark", "Doe", 50000, "Marketing")
emp3 = Employee("Jane", "Doe", 50000, "Advertisement")
man1 = Manager("Bob", "Ben", 200000, "Marketing")
man2 = Manager("Ryan", "DS", 200000, "Advertisement")

# Employee.num_of_emps returns 5
# Manager.num_of_emps returns 2

让我感到困惑的是,每次创建管理器实例时,父类的num_of_emps也会更新。我知道super()。 init 方法是造成这种情况的原因,但是有人可以解释原因吗?

2 个答案:

答案 0 :(得分:1)

这是因为super()。 init ()调用了super init方法。然后用这种方法增加Manager的数量。这是继承的问题。更好的方法可能是更好地细分您的课程。

another answer中还给出了另外两个建议,这些建议的结构比我提供的代码示例更好,它们旨在尝试展示如何尽可能简单地划分您的问题。

class Person:

    def __init__(self):
        # Some stuff
        pass


class Employee(Person):

    counter = 0

    def __init__(self):
        super().__init__()
        # Some stuff
        Employee.counter += 1
        pass


class Manager(Person):

    counter = 0

    def __init__(self):
        super().__init__()
        # Some stuff
        Manager.counter += 1
        pass

这将避免在基类上多次触发counter属性。

答案 1 :(得分:1)

您已经对“为什么”部分有了答案,所以我不再重复。

对于您而言,对于该解决方案,只需避免对类名进行硬编码(使用type(self)来获取当前实例的类)就可以解决此问题(nb:如果您考虑更新Employee计数器是一个问题):

>>> class Base(object):
...     counter = 0
...     def __init__(self):
...         print("base.__init__")
...         type(self).counter += 1
... 
>>> class Child(Base):
...     pass
... 
>>> c = Child()
base.__init__
>>> Base.counter
0
>>> Child.counter
1

一种更清洁的解决方案是在类方法中排除计数器增量,以便您既可以拥有预期的默认值,又可以在需要时覆盖它,即:

>>> class Base(object):
...     counter = 0
...     def __init__(self):
...         self.inc_counter()
...     @classmethod
...     def inc_counter(cls):
...         cls.counter += 1
... 
>>> class Child(Base):
...     pass
... 
>>> c = Child()
>>> Child.counter
1
>>> Base.counter
0