继承:父类的属性

时间:2018-10-05 12:46:10

标签: python class inheritance

我目前正在使用python开发一个更大的项目,并试图使用OOP原理来建立结构。我有一个父类,它包含许多属性以及几个子类,这些子类必须利用父类的属性。但是我在从子类中检索父类的属性时遇到了一些麻烦。作为简化示例,这是我要完成的工作:

class A:
  def __init__(self, firstname):
    self.__firstname = firstname

  @property
  def firstname(self):
    return self.__firstname

class B(A):
  def __init__(self, lastname):
    self.__lastname = lastname
    A.__init__(self)

  @property
  def lastname(self):
    return self.__lastname

parent = A('somefirstname')
child = B(parent, 'somelastname')

print(child.firstname)
print(child.lastname)

执行时出现以下错误:

Traceback (most recent call last):
  File "classplay.py", line 23, in <module>
    child = B(parent, 'somelastname')
TypeError: __init__() takes 2 positional arguments but 3 were given

3 个答案:

答案 0 :(得分:1)

您的代码的正确(python 2.7)版本为:

class A(object):
  def __init__(self, firstname):
    self.firstname = firstname


class B(A):
  def __init__(self, lastname):
    super(B, self).__init__(firstname)
    self.lastname = lastname


parent = A('somefirstname')
child = B('somefirstname', 'somelastname')

print(child.firstname)
print(child.lastname)

但是我怀疑您并不真正了解OO,尤其是不继承。在您写的评论中:

  

我发现必须实例化子类中父类的实例的工作效率极低。

您在哪里看到的???对超类的__init__的调用不是“创建父类的实例”,它只是在当前子实例上应用父类的__init__。子实例还应该如何正确初始化?

  

真的没有办法简单地将父实例传递给子类并简单地添加新属性吗?

是的-只需在类上调用方法并将实例作为第一个参数传递即可

parent = A("firstname")
B.__init__(parent, "lastname")
print(parent.firstname, parent.lastname)

但这不会实现您的期望-parent将仍然是A实例(尽管具有其他属性):

print(type(parent))

此外,您的B类与A不兼容,因此它不是A的适当子类型(根据liskov的替换原理)。从技术上讲,这不是非法的,也不是问题,但继承不仅涉及实现重用,还涉及子类型化(继承表示一种is a关系,因此“ B继承自A”意味着“ B是A(的一种)”)。由于实现继承主要是受限制的案例组合/委托,因此在决定继承与组合/委托之间,您可能需要三思而后行考虑模型的语义。

编辑-此:

class A(object):
  def __init__(self, firstname):
    self.firstname = firstname


class B(A):
  def __init__(self, parent, lastname):
    self.lastname = lastname
    A.__init__(self, parent.firstname)

parent = A('somefirstname')
child = B(parent, 'somelastname')

是这个设计的非常糟糕的版本:

class A(object):
  def __init__(self, firstname):
    self.firstname = firstname


class B(A):
  def __init__(self, firstname, lastname):
    super(B, self).__init__(firstname)
    self.lastname = lastname


parent = A('somefirstname')
child = B(parent.firstname, 'somelastname')

它的设计很糟糕,因为它需要您拥有一个A实例-或任何具有“ firstname”属性的东西-才能创建一个B实例,而所有B都需要名字。您始终希望将对象之间的耦合/依赖关系限制在所需的最低限度。

FWIW,您似乎也混淆了“父母”和“孩子”的两种不同接受。

在OOP中,“父”和“子”是关于的,而不是关于 instances 的,并且不表示基类和派生类的实例之间有任何直接关系(请注意,使用“基础”和“派生”而不是“父母”和“孩子”,这不太含糊。)

在这里,您似乎想建模一些跨实例的关系(“卢克,我是您的父亲”吗?),其中“孩子”为“父母”(而不是“是”)。继承不是此处的适当工具,您需要组合/委托:

class Father(object):
    def __init__(self, firstname):
        self.firstname = firstname


class Child(object):
    def __init__(self, father, lastname):
        self.father = father # composition
        self.lastname = lastname

   @property
   def firstname(self):
        # delegation
        return self.father.firstname

vador = Father("Vador")
luke = Child(vador, "Luke")

答案 1 :(得分:0)

首先,我认为您对继承有误解。您可以从类B继承类A,但不能从另一个对象继承对象。

第二,您犯了以下两个错误:

  • child = B(parent, 'somelastname'):查看类B的__init__函数,仅请求一个参数,例如child = B('somelastname')可以。

  • A.__init__(self):查看类A的__init__函数,请求一个参数,例如A.__init__('myfirstname')可以。

答案 2 :(得分:0)

回答自己的问题。我想要的结果在python中是不可能的。但是,通过将父类用作子类中的参数,我们可以达到所需的结果(但并非不为父类重新键入每个需要的参数)

class A:
  def __init__(self, firstname):
    self.__firstname = firstname

  @property
  def firstname(self):
    return self.__firstname

class B(A):
  def __init__(self, parent, lastname):
    self.__lastname = lastname
    A.__init__(self, parent.firstname)

  @property
  def lastname(self):
    return self.__lastname

parent = A('somefirstname')
child = B(parent, 'somelastname')

print(child.firstname)
print(child.lastname)