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

在Python中,对象是否有自己的类变量副本?,python,class,object,variables,copy,Python,Class,Object,Variables,Copy,这是一个让每一个Python中级学习者都感到困惑的问题,所以请给出一个简短的(对白痴友好的)答案 我想创建一个变量,该变量在创建新对象时将变量population增加1 class Human: population = 0 # initialization. def __init__(self, name, age, gender): self.name = name self.age = age self.gende

这是一个让每一个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
所以对象和类都有变量
population
?变量
population
init()方法中的变量之间有什么区别


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

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


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

比这要复杂一些。类变量和实例变量都有,但在您的示例中发生的情况是,类变量被实例变量覆盖

考虑以下几点:

>>类Foobar:
...     我的清单=[]
... 
>>>foo=Foobar()
>>>Foobar.my_list.append('hello')
>>>foo.my_list.append('world'))
>>>foo.my_列表
[“你好”,“世界”]
正如您所看到的,
Foobar
类和
foo
实例在这里共享一个变量。因此,实例化一个类不会“复制”所有的类变量。然而,考虑一下:

>>> foo.my_list = ['spam', 'eggs']
>>> foo.my_list
['spam', 'eggs']
>>> Foobar.my_list
['hello', 'world']
现在我们有两个变量,一个是类变量,另一个是实例变量。他们已经不一样了

如果您希望始终使用类变量,最优雅的做法是使用类方法。例如

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\u pop
是一个类方法,所以它总是在类上操作,而不是在实例上。但是,
population
属性将对实例可用,只要它们不覆盖它,它将与类变量相同

要记住几件重要的事情:

  • 原语,如整数和字符串,是不可变的。当您执行
    foo+=1
    时,您正在创建一个整数的新实例并替换旧实例。您没有在适当的位置修改它

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

  • 类方法可以从实例中调用,类似地,如
    self.Class\u method()

  • 关于Python变量的其他注释

    让我们回到这里,考虑Python如何解决对像<代码> MySufman之类的请求。实例上的人口< /代码>:

  • 首先,Python查找名为
    population
    的实例属性。如果它存在,那就是你得到的值
  • Second,Python查找名为
    population
    的类属性。如果存在,那就是你得到的价值
  • 因此,当您的实例上没有指定的
    population
    ,并且您访问了
    self.population
    ,因为不存在具有该名称的实例属性,所以您将获得class属性

    但是,一旦将实例属性指定给对象,上述第二步就永远不会发生

    您也可以在运行时对此进行检查:

    >>类人:
    ...     人口=0
    ...
    >>>我的人
    >>>人类的“人口”__
    真的
    >>>“人口”在我的字典里__
    假的
    
    因此,
    population
    只存在于人类类上,而不存在于实例上。当我们访问
    Human.population
    时,它会找到class属性:

    >>我的人口
    0
    
    但是如果我创建一个实例属性会发生什么呢

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

    现在,由于实例的属性与名称
    population
    匹配,因此当您访问
    my_human.population
    时,它从不查找类中的内容。

    self.population+=1
    将分配给
    self.population
    ,而不是分配给
    human.population
    ,所以它创建了一个独立于类变量的实例变量。我的意思是,你回答了你自己的问题。一个是类变量(在其他语言中有时称为静态变量),另一个是实例变量,它与类的每个实例不同。为了获得所需的效果,您应该增加
    Human.population
    ,而不是
    self.population
    。如果我调用
    self.population
    ,并且它正在创建一个单独的实例变量,它如何在自身增加之前初始化?也就是说,它是如何选择要初始化的特定值的?我将一点一点地提出我的新疑问:(01)在您的第一个代码示例中,对象
    foo
    中的
    my_list
    变量是否只是类
    Foobar
    中存在的变量的副本(我们将其作为
    Foobar.my_list
    访问)?也就是说,对象中的变量
    my_list
    是否只是类中变量的反映?(02)如上所述,在实例方法中调用类方法是否不可靠,因为它只会更改类变量的副本?好的,我在第二个问题的“关于Python变量的其他注释”中进一步解释了它,它不是不可靠的。因为classmethod只修改cls对象,所以它的行为是可预测的。话虽如此,除非有充分的理由,否则最好不要用实例变量来隐藏类变量(以帮助代码可读)