在 Python 中,对象是否有自己的 class 变量副本?

In Python, do objects have their own copies of class variables?

这是一个让每个Python中级学习者都感到困惑的问题,所以请给出一个简短的(白痴友好的)答案。

我想创建一个变量,它在创建新对象时将变量 population 递增 1。

class Human:

    population = 0

    # initialization.
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

    
    def increment_pop(self):
        self.population += 1

# class Human ends.

person = Human('Tom', 22, 'M')
person.increment_pop()
person.increment_pop()
print('Population : ', person.population)

person2 = Human('Anna', 24, 'F')
person2.increment_pop()
print('Population : ', person2.population)

print(Human.population)

输出:

Population :  2
Population :  1
0

所以对象和 class 都有变量 population?变量populationinit()方法里面的变量有什么区别?

我知道 init() 方法中只有实例变量。

self 引用了 class 的特定实例。当您调用 increment_pop 时,您正在使用 self.population,这只会导致该实例的增量。因为在 python 中不需要调用初始值设定项,所以 increment_pop 创建了一个名为 self.population 的新变量,其中 class 变量 population 应该是全局的。

将 increment_pop 更改为 cls.population 而不是 self.population,它应该会按预期工作。请注意,在函数定义中,您需要装饰器 @class 方法和参数 cls.

比那要复杂一点。有 class 变量和实例变量,但在您的示例中发生的是 class 变量被实例变量 覆盖

考虑以下几点:

>>> class Foobar:
...     my_list = []
... 
>>> foo = Foobar()
>>> Foobar.my_list.append('hello')
>>> foo.my_list.append('world')
>>> foo.my_list
['hello', 'world']

如您所见,Foobar class 和 foo 实例 在此处共享一个变量 。所以不,实例化 class 不会“复制”所有 class 变量。然而,考虑一下:

>>> foo.my_list = ['spam', 'eggs']
>>> foo.my_list
['spam', 'eggs']
>>> Foobar.my_list
['hello', 'world']

现在我们有 两个变量,一个是 class 变量,另一个是实例变量。他们不再一样了。

如果您想始终使用 class 变量,最优雅的方法是使用 class 方法。例如,

class Human:

    population = 0

    # initialization.
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

    @classmethod
    def increment_pop(cls):
        cls.population += 1

现在因为 increment_pop 是一个 class 方法,它总是在 class 上操作,而不是实例。但是,population 属性将对实例可用,只要它们不覆盖它,它将与 class 变量相同

需要牢记的几件重要事情:

  1. 基元,如整数和字符串,是不可变的。当您执行 foo += 1 时,您正在创建整数的新实例并替换旧实例。您没有就地修改它。

  2. 实例可以使用 self.whatnot 访问 class 变量和 class 方法。但是如果你想明确一点,你也可以将它们引用为 ClassName.whatnot.

  3. Class 方法可以从实例中调用,类似地,像 self.class_method().

关于 Python 变量的其他说明

让我们回到这里并考虑 Python 如何在 实例 :

上解决对类似 my_human.population 的请求
  1. 首先,Python 查找名为 population 的实例属性。如果它存在,那就是你得到的值。
  2. Second,Python 查找名为 population 的 class 属性。如果存在,那就是你得到的值。

因此,当您的实例上没有分配 population 并且您访问 self.population 时,由于不存在具有该名称的实例属性,您将获得 class 属性。

但是,一旦您将实例属性分配给您的对象,上述第二步就不会发生。

您也可以在运行时检查它:

>>> class Human:
...     population = 0
...
>>> my_human = Human()
>>> 'population' in Human.__dict__
True
>>> 'population' in my_human.__dict__
False

所以 population 只存在于 人类 class 上,而不存在于实例上。当我们访问Human.population时,它找到了class属性:

>>> my_human.population
0

但是如果我创建实例 属性会怎样?

>>> Human.population = 100
>>> my_human.population = 50
>>> Human.population
100
>>> my_human.population
50

现在,因为实例有一个与名称 population 匹配的属性,当您访问 my_human.population 时,它永远不会查找 class.

上的内容