在Python中,对象是否具有自己的类变量副本? [英] In Python, do objects have their own copies of class variables?

查看:113
本文介绍了在Python中,对象是否具有自己的类变量副本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

This is a question which confuses every Python Intermediate learner, so please give a brief (and idiot-friendly) answer.

我想创建一个变量,该变量会增加变量人口在创建新对象时减1。

I wanted to create a variable which increments the variable population by 1 when a new object is created.

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 ?变量人口 init ()方法内部的变量有什么区别?

So both the object and the class has the variable population? What is the difference between the variable population and the variables inside the init() method?

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

I know that only instance variables are inside the init() method.

推荐答案

这有点复杂比起那个来说。类变量和实例变量都存在,但是在您的示例中发生的事情是类变量被实例变量覆盖

It's a bit more complex than that. There are both class variables and instance variables, but what's happening in your example is that the class variable is being overridden by the instance variable.

请考虑以下内容:

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

您可以看到 Foobar 类和 foo 实例在此处共享变量。因此,不,实例化一个类不会复制代码。所有的类变量。但是,请考虑以下因素:

As you can see the Foobar class and foo instance share a variable here. So no, instantiating a class does not "copy" all the class variables. Consider this, however:

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

现在我们有两个变量,一个是类变量,另一个是实例变量。它们不再相同。

Now we have two variables, one that's a class variable, the other that's an instance variable. They are no longer the same.

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

If you wanted to always use class variables, the most elegant thing would be to use class methods. Eg,

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 是一个类方法,它将始终对类而不是实例进行操作。但是, population 属性将对实例可用,只要它们不覆盖它,它将与类变量相同

Now because increment_pop is a class method, it will always operate on the class, not the instance. However, the population attribute will be available to instances and as long as they don't overwrite it, it will be the same as the class variable.

需要记住的一些重要事项:

A few important things to keep in mind:


  1. 原语是整数和字符串,一成不变的。当您执行 foo + = 1 时,您将创建一个新的整数实例并替换旧的实例。

  1. Primitives, like integers and strings, are immutable. When you do foo += 1, you're creating a new instance of an integer and replacing the old one. You're not modifying it in place.

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

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

Class methods can be called from instances, similarly, like self.class_method().


有关Python变量的其他说明


让我们回到这里,考虑一下Python如何解决对 my_human.population之类的请求。 / em实例上的/ code>:

Other notes on Python variables

Let's back up here and consider how Python resolves a request for something like my_human.population on the instance:


  1. 首先,Python查找名为的实例属性人口。如果存在,那就是您获得的价值。

  2. 第二,Python查找名为 population 。如果存在,那就是您得到的价值。

  1. First, Python looks for an instance attribute named population. If it exists, that's the value you get.
  2. Second, Python looks for a class attribute named population. If that exists, that's the value you get.

因此,当您没有分配人口时在您的实例上,然后访问 self.population ,因为不存在具有该名称的实例属性,您将获得类属性。

So, when you have no assigned population on your instance, and you access self.population, since no instance attribute exists with that name, you get the class attribute.

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

However, once you assign an instance attribute to your object, that second step above never happens.

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

You can inspect this at runtime, too:

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

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

So population only exists on the Human class, not on the instance. When we access Human.population, it finds the class attribute:

>>> my_human.population
0

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

But what happens if I create an instance attribute?

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

现在,因为实例具有与名称匹配的属性人口,当您访问 my_human.population 时,它永远不会查找班级上的内容。

Now, because the instance has an attribute matching the name population, when you access my_human.population, it never looks up what's on the class.

这篇关于在Python中,对象是否具有自己的类变量副本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆