我目前正在使用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
答案 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)