从子类实例中访问父类实例属性?

28
在这个代码示例中,如何从“child”访问“myvar”:
class Parent():
    def __init__(self):
        self.myvar = 1

class Child(Parent):
    def __init__(self):
        Parent.__init__(self)

        # this won't work
        Parent.myvar

child = Child()

1
如果你的属性以“双下划线”(例如self.__myvar)开头,它将不起作用,因为Python认为它是私有的。 - ihadanny
根据你的代码编写方式,我可以以两种方式解释这个问题。要么是,1)你在问“从子类中如何访问在其父类中定义的名称?” 要么是2)你对类变量和实例变量之间的区别感到困惑。 - Alex Oakley
5个回答

39

Parent是一个类 - 蓝图而不是它的实例, 在面向对象编程中,要访问对象的属性,需要该对象的实例, 这里self/child是实例,而Parent/Child是类...

请查看下面的答案,可能会澄清你的疑惑。

class Parent():
    def __init__(self):
        self.myvar = 1

class Child(Parent):
    def __init__(self):
        Parent.__init__(self)

        # here you can access myvar like below.
        print self.myvar

child = Child()
print child.myvar

2
我本来以为我尝试了正常的“self”实例引用。哎,等待接受答案... - user975135
注意:在这种情况下,您不需要在子类中拥有一个init方法即可使此解决方案起作用。 - Ahmed Alhallag
2
对于未来的读者,应该在子类__init__中使用super()方法而不是父类名称。请参见此问题 - Bilbottom

10

父类没有名为myvar的属性。只有parent的实例才拥有该属性。
在子类方法内部,您可以使用self.myvar访问该属性。


9

替代继承的方法

目前的答案都是从 继承 的角度来看的,但这并不总是你想要的方式 -- 有时你可能希望子类是与父类完全不同的对象类型,但仍可以访问父类的属性。

以业务为例,可以想象 Excel 中的工作簿(Workbook)有工作表(Worksheet)子项,它们又有范围(Range)等子项。

只有子项

另一种方法(不是唯一的方法)是将父类作为参数传递给子类,以创建对应于父类的属性:

class Parent(object):
    def __init__(self, parent_value):
        self.parent_value = parent_value
        self.child = Child(self)


class Child(object):
    def __init__(self, _parent):
        self.parent = _parent
        self.child_value = 0


new_parent = Parent(1)
print(new_parent.parent_value)        # prints 1

new_child = new_parent.child
print(new_child.child_value)          # prints 0
print(new_child.parent.parent_value)  # prints 1

new_parent.parent_value = 100
print(new_child.parent.parent_value)  # prints 100

注意,这会同时实例化childnew_parent。要访问父类的属性,请通过parent属性进行访问。

多个子类

您可以扩展这个功能,以便通过new_parent对象创建Child类的多个实例。以下代码是一种简单的方法,它用一个children属性和一个add_child方法替换了child属性。

class Parent(object):
    def __init__(self, parent_value):
        self.parent_value = parent_value
        self.children = []

    def add_child(self, child_value):
        new_child = Child(child_value, _parent=self)
        self.children.append(new_child)
        return new_child  # allows add_child to assign a variable


class Child(object):
    def __init__(self, child_value, _parent):
        self.parent = _parent
        self.child_value = child_value


new_parent = Parent(1)

# add 3 Child instances with child_values 2, 4, 8
[new_parent.add_child(v) for v in [2, 4, 8]]

# add another child that utilises the return statement
extra_child = new_parent.add_child(16)

for child in new_parent.children:
    print(child.child_value)          # prints 2, 4, 8, 16
    print(child.parent.parent_value)  # prints 1

new_parent.parent_value = 32
for child in new_parent.children:
    print(child.parent.parent_value)  # prints 32

# prove that extra_child is new_parent.children[3]
extra_child.child_value = 64
print(new_parent.children[3].child_value)  # prints 64

3
虽然您的回答质量很好,但我认为您的回答并没有直接回答问题。问题是关于继承而不是组合或容器类的。老实说,我认为提问者在这里不需要使用组合。 - Peilonrayz

0
一个原因导致你的代码无法运行,并且与父子关系无关,是因为myvar是一个实例变量,但你却试图像访问类变量一样来访问它。
下面的代码将把这个变量视为类变量,并且会按预期工作:
class Parent():
    myvar = 1
    def __init__(self) -> None:
        # Move the definition of myvar outside of the __init__ method, 
        # and remove the self. prefix
        ...

class Child(Parent):
    def __init__(self) -> None:
        print(Parent.myvar) # 1

child =  Child()
        

在您的原始代码中;
class Parent():
    def __init__(self):
        self.myvar = 1 # this is an instance variable

class Child(Parent):
    def __init__(self):
        Parent.__init__(self)

        # this won't work
        Parent.myvar #  this treats `myvar` as a class variable

-1

你需要使用所谓的代理对象通过"super"命令来初始化父类。

所以代码应该像这样:

class Parent():
  def __init__(self):
      self.myvar = 1

class Child(Parent):
  def __init__(self):
      super.__init__()


child = Child()
print child.myvar

我不确定这个答案有什么问题。能有人给我解释一下吗? - Alex Oakley
此答案使用的是已被弃用的Python 2.x版本。而且它实际上并没有回答问题,因为原帖中要求在"child"类内部访问"myvar"。 - Eddudos Kim
真是个专家 :) Kim,你错了。回答完全按照问题提出的方式进行了回答。而且这个解决方案适用于任何版本的Python。很多人都在努力理解父类的概念,看起来你也是其中之一。 - Shtefan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接