简体   繁体   English

Python子类继承

[英]Python subclass inheritance

I am trying to build some classes that inherit from a parent class, which contains subclasses that inherit from other parent classes. 我正在尝试构建一些继承自父类的类,该类包含从其他父类继承的子类。 But when I change attributes in the subclasses in any children, the change affects all child classes. 但是当我在任何子级中更改子类中的属性时,更改会影响所有子类。 I am looking to avoid having to create instances, as I am using that feature later. 我希望避免创建实例,因为我稍后使用该功能。

The code below boils down the problem. 下面的代码归结了这个问题。 The final line shows the unexpected result. 最后一行显示了意外的结果。

class SubclsParent(object):
    a = "Hello"

class Parent(object):
    class Subcls(SubclsParent):
        pass

class Child1(Parent):
    pass

class Child2(Parent):
    pass

Child1.Subcls.a # Returns "Hello"
Child2.Subcls.a # Returns "Hello"
Child1.Subcls.a = "Goodbye"
Child1.Subcls.a # Returns "Goodbye"
Child2.Subcls.a # Returns "Goodbye" / Should still return "Hello"!

The behaviour you are seeing is exactly what you should expect. 您所看到的行为正是您应该期待的。 When you define a class 定义类时

>>> class Foo(object): pass
...

you can modify that class -- not instances of it, the class itself -- because the class is just another object, stored in the variable Foo. 你可以修改那个类 - 不是它的实例,类本身 - 因为类只是另一个对象,存储在变量Foo中。 So, for instance, you can get and set attributes of the class: 因此,例如,您可以获取并设置类的属性:

>>> Foo.a = 1
>>> Foo.a
1

In other words, the class keyword creates a new type of object and binds the specified name to that object. 换句话说, class关键字创建一种新类型的对象,并将指定的名称绑定到该对象。


Now, if you define a class inside another class (which is a weird thing to do, by the way), that is equivalent to defining a local variable inside the class body. 现在,如果你另一个类中定义一个类(顺便说一句,这是一个奇怪的事情),这相当于在类体中定义一个局部变量。 And you know what defining local variables inside the body of a class does: it sets them as class attributes. 而且你知道在类体内定义局部变量的作用是什么:它将它们设置为类属性。 In other words, variables defined locally are stored on the class object and not on individual instances. 换句话说,本地定义的变量存储在类对象中,而不是存储在单个实例上。 Thus, 从而,

>>> class Foo(object):
...     class Bar(object): pass
...

defines a class Foo with one class attribute, Bar , which happens itself to be a class. 定义一个具有一个类属性Bar的类Foo ,它本身就是一个类。 There is no subclassing going on here, though -- the classes Foo and Bar are entirely independent. 但是这里没有子类化 - 类FooBar完全独立。 (The behaviour you have achieved could be replicated as follows: (您已实现的行为可以复制如下:

>>> class Foo(object):
...     class Bar(object): pass
...
>>> class Foo(object): pass
...
>>> class Bar(object): pass
...
>>> Foo.Bar = Bar

.) 。)

So you are always modifying the same variable ! 所以你总是修改同一个变量 Of course you will change the values you see; 当然,你会改变你看到的价值观; you have changed them yourself! 你自己改变了!


Your problem seems to be that you are somewhat confused between instance and class attributes, which are not the same thing at all. 您的问题似乎是您在实例和类属性之间有些混淆,这些属性完全不同。

A class attribute is a variable which is defined over the whole class. class属性是在整个类上定义的变量。 That is, any instance of the class will share the same variable. 也就是说,该类的任何实例都将共享相同的变量。 For instance, most methods are class attributes, since you want to call the same methods on every instance (usually). 例如,大多数方法都是类属性,因为您希望在每个实例上调用相同的方法(通常)。 You can also use class attributes for things like global counters (how many times have you instantiated this class?) and other properties which should be shared amongst instances. 您还可以将类属性用于全局计数器(您实例化此类的次数?)以及应在实例之间共享的其他属性。

An instance attribute is a variable peculiar to an instance of the class. 实例属性是类的实例特有的变量。 That is, each instance has a different copy of the variable, with possibly-different contents. 也就是说,每个实例都有一个不同的变量副本,可能含有不同的内容。 This is where you store the data in classes -- if you have a Page class, say, you would like the contents attribute to be stored per-instance, since different Page s will of course need different contents . 这是将数据存储在类中的位置 - 例如,如果您有Page类,那么您希望每个实例存储contents属性,因为不同的Page当然需要不同的contents

In your example, you want Child1.Subcls.a and Child2.Subcls.a to be different variables. 在您的示例中,您希望Child1.Subcls.aChild2.Subcls.a不同的变量。 Naturally, then, they should depend on the instance! 当然,他们应该依赖于实例!


This may be a bit of a leap of faith, but are you trying to implement Java-style interfaces in Python? 这可能是一种信念的飞跃,但您是否尝试在Python中实现Java风格的接口? In other words, are you trying to specify what properties and methods a class should have, without actually defining those properties? 换句话说,您是否尝试指定类具有哪些属性和方法,而不实际定义这些属性?

This used to be considered something of a non-Pythonic thing to do, since the prevailing consensus was that you should allow the classes to do whatever they want and catch the exceptions which arise when they don't define a needed property or method. 这曾经被认为是非Pythonic要做的事情,因为普遍的共识是你应该允许类做任何他们想做的事情并捕捉他们没有定义所需属性或方法时产生的异常。 However, recently people have realised that interfaces are actually sometimes a good thing, and new functionality was added to Python to allow this: abstract base classes . 然而,最近人们已经意识到接口实际上有时是一件好事,并且Python中添加了新功能以允许这样: 抽象基类

Try this 尝试这个

class SubclsParent(object):
    def __init__(self):
         self.a = "Hello"

When you define SubclsParent.a directly on the class, you are defining it as static. 直接在类上定义SubclsParent.a时,您将其定义为static。

When you use Child1.Subcls, python sees there is no Child1.Subcls, and so checks Parent where it finds it and returns it. 当您使用Child1.Subcls时,python看到没有Child1.Subcls,因此检查Parent在哪里找到它并返回它。 The same thing happens for Child2.Subcls. Child2.Subcls也发生了同样的事情。 As a result, both of those expressions refer to the same class. 结果,这两个表达式都引用了同一个类。 Child1 and Child2 do not get their own subclasses of it, rather they have access to the original. Child1和Child2没有自己的子类,而是可以访问原始类。

* I am looking to avoid having to create instances, as I am using that feature later. * 我希望避免创建实例,因为我稍后使用该功能。 * *

I don't understand what you mean here. 我不明白你的意思。

Your problem is that when you access the attributes you are accessing inherited routines that were created in the parent class, which all refer to the same variable. 您的问题是,当您访问属性时,您正在访问在父类中创建的继承例程,这些例程都引用同一个变量。 You can either make those instance variables, or else you can create the attributes in the child classes to get independent attributes. 您可以创建这些实例变量,也可以在子类中创建属性以获取独立属性。

可能你真正想要的是元类

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM