Python子类inheritan

2024-06-09 00:54:00 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图构建一些继承自父类的类,其中包含继承自其他父类的子类。但是,当我在任何子类中更改子类的属性时,更改将影响所有子类。我希望避免创建实例,因为我稍后将使用该功能。

下面的代码将问题归结为。最后一行显示意外结果。

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"!

Tags: 实例hello属性objectpass子类classreturns
3条回答

你所看到的行为正是你所期望的。定义类时

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

您可以修改那个类而不是它的实例,类本身,因为这个类只是另一个对象,存储在变量Foo中。例如,您可以获取和设置类的属性:

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

换句话说,class关键字创建一种新的对象类型,并将指定的名称绑定到该对象。


现在,如果在另一个类(顺便说一句,这是一件很奇怪的事情)内定义一个类,这相当于在类主体内定义一个局部变量。您知道在类的主体中定义局部变量的作用:它将它们设置为类属性。换句话说,本地定义的变量存储在类对象上,而不是单个实例上。因此

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

用一个类属性Bar定义一个类Foo,它本身恰好是一个类。不过,这里没有进行子类化——类FooBar是完全独立的。(你所达到的行为可以复制如下:

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

(第三章)

因此,您总是在修改同一个变量!当然,你会改变你看到的价值观;你自己也改变了它们!


您的问题似乎是您在实例属性和类属性之间有点混淆,这两个属性根本不是一回事。

class属性是在整个类上定义的变量。也就是说,类的任何实例都将共享同一个变量。例如,大多数方法都是类属性,因为您希望对每个实例(通常)调用相同的方法。您还可以将类属性用于全局计数器之类的事情(您实例化了该类多少次?)以及其他应该在实例之间共享的属性。

instance属性是类实例特有的变量。也就是说,每个实例都有一个变量的不同副本,其中可能包含不同的内容。这是将数据存储在类中的地方——如果您有一个Page类,比如说,您希望每个实例存储contents属性,因为不同的Page当然需要不同的contents

在您的示例中,您希望Child1.Subcls.aChild2.Subcls.a是不同的变量。自然,那么,它们应该依赖于实例!


这可能是一个信念的飞跃,但您是否试图在Python中实现Java风格的接口?换句话说,您是否试图指定类应该具有哪些属性和方法,而不实际定义这些属性?

这曾经被认为是一件非Pythonic的事情,因为普遍的共识是,你应该允许类做他们想做的任何事情,并捕捉当它们没有定义所需的属性或方法时出现的异常。然而,最近人们已经意识到,接口有时候是件好事,Python中添加了新的功能来实现这一点:abstract base classes

当您使用Child1.Subcls时,python会看到没有Child1.Subcls,因此会检查找到它的父级并返回它。同样的情况也发生在Child2.Subcls上。因此,这两个表达式都引用同一个类。Child1和Child2没有自己的子类,而是可以访问原始的子类。

*我希望避免创建实例,因为我稍后将使用该功能。*

我不明白你的意思。

试试这个

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

直接在类上定义SubclsParent.a时,将其定义为静态。

相关问题 更多 >