当我实例化一个python子类,它覆盖基类的属性 [英] When I instantiate a python subclass it overwrites base class' attribute

查看:484
本文介绍了当我实例化一个python子类,它覆盖基类的属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

代码如下:

class A(object):
    x = 0
    y = 0
    z = []
    def __init__(self):
        super(A, self).__init__()
        if not self.y:
            self.y = self.x
        if not self.z:
            self.z.append(self.x)

class B(A):
    x = 1

class C(A):
    x = 2

print C().y, C().z
print B().y, B().z

输出为

2 [2]
1 [2]

z 覆盖,但不是 y ?是因为它不是一个不可变类型?我看了python的文档,没有找到解释。

Why is z overwritten but not y? Is it because it's not a immutable type? I looked on python's documentation and didn't find an explanation.

推荐答案

是的,这是因为一个是不可变的, 。或者更确切地说,这是你正在改变一个而不是另一个。 (重要的不是对象是否是可变的,重要的是你是否真的改变它)。这也是因为你使用类变量而不是实例变量(参见此问题)。

Yes, it's because one is immutable and one isn't. Or rather, it's that you are mutating one and not the other. (What matters isn't whether the object "is mutable", what matters is whether you actually mutate it.) It's also because you're using class variables instead of instance variables (see this question).

类定义,您创建三个类变量,在类的所有实例之间共享。创建类的实例后,如果在该实例上 self.x ,它将不会找到 x 一个实例上的属性,但会在类上查找它。同样, self.z 将查找类,并找到类上的一个。请注意,因为您创建了 z 类变量,所以只有一个列表在类的所有实例之间共享子类,除非它们覆盖 z )。

In your class definition, you create three class variables, shared among all instances of the class. After creating an instance of your class, if you do self.x on that instance, it will not find x as an attribute on the instance, but will look it up on the class. Likewise self.z will look up on the class and find the one on the class. Note that because you made z a class variable, there is only one list that is shared among all instances of the class (including all instances of all subclasses, unless they override z).

当你执行 self.y = self .x ,您只能在实例上创建属性和实例属性。

When you do self.y = self.x, you create a new attribute, an instance attribute, on only the instance.

但是,当你执行 self.z.append(...)时,不会创建一个新的实例变量。相反, self.z 查找存储在类上的列表,然后 append 改变该列表。没有覆盖。只有一个列表,当您执行追加时,您正在更改其内容。 (只有一个项目被附加,因为你有如果不是self.z ,所以在你追加一个,那是假,后续调用不追加任何更多。)

However, when you do self.z.append(...), you do not create a new instance variable. Rather, self.z looks up the list stored on the class, and then append mutates that list. There is no "overwriting". There is only one list, and when you do the append you are changing its contents. (Only one item is appended, because you have if not self.z, so after you append one, that is false and subsequent calls do not append anything more.)

结果是读取属性的值不等于分配给它。当您读取 self.x 的值时,您可能正在检索存储在类上并在所有实例之间共享的值。但是,如果为 self.x 分配一个值,则始终分配给一个实例属性;如果已经有一个具有相同名称的类属性,你的实例属性将隐藏它。

The upshot is that reading the value of an attribute is not the same as assigning to it. When you read the value of self.x, you may be retrieving a value that is stored on the class and shared among all instances. However, if you assign a value to self.x, you are always assigning to an instance attribute; if there is already a class attribute with the same name, your instance attribute will hide that.

这篇关于当我实例化一个python子类,它覆盖基类的属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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