通常,在子类中重命名属性是不好的做法。
原因是
inheritance is about substitutability
. 它对一个
School
成为一个
Entity
你可以用一个
学校
在编写的任何代码中,
实体
它会正常工作。
例如,使用
实体
可能会这样做:
for member in entity.members:
如果你有什么东西声称是
实体
(甚至传球
isinstance(myschool, Entity)
但是它也没有
members
或者有一个空的
成员
,因为它的实际成员存储在其他某个属性中,所以该代码被破坏。
更一般地说,如果更改了基类和被嘲笑的类之间的接口(一组公共方法和属性),则派生类不是子类型,这意味着在第一种情况下,它通常不应该使用继承。
一
如果你
students
变成一个
别名
对于
成员
,以便在
任何一个
名字,然后是你
做
具有子类型:a
学校
有它的
学生
作为
成员
因此,它可以明智地与期望
实体
:
myschool.students.append(Person(cap'))
# ...
for member in myschool.members:
# now cap is going to show up here
这对于在
实体
:
def slap_everyone(self):
for member in self.members:
# this will include cap
member.slap()
myschool.slap_everyone()
你可以用
@property
.
class Student(Entity):
# ...
@property
def students(self):
return members
@students.setter
def students(self, val):
self.members = val
@students.deleter
def students(self):
del self.members
所以,这并不是完全无效的。
但这有潜在的误导性。
对于代码的读者来说,添加
cap
到
myschool.students
将他添加到
myschool.members
?如果是的话,可能没问题。如果没有,或者你不确定,那么你可能不应该这样做。
另一个需要考虑的是
学校
可能有多种成员:学生、教师、管理人员、辍学者,他们在旧校园里闲逛,因为他们不知道在哪里可以找到毒贩,如果这是你设计的一部分,那么你真正想要的就是
成员
成为一个属性,可能是一个只读属性,
二
每个子类都可以用对该子类有意义的方式定义什么是“成员”。
class Entity(object):
@property
def members(self):
return []
def rollcall(self):
return ', '.join(self.members)
class School(Entity):
def __init__(self):
super(School, self).__init__()
self.students, self.teachers = [], []
@property
def members(self):
return self.students + self.teachers
school = School()
school.teachers.append('cap')
school.students.extend(['marvel', 'america, planet'])
print(school.rollcall())
这将打印出:
cap, marvel, america, planet
那
school
作为一个
学校
作为一个
实体
一切都很好。
1。我说
通常
因为(不管oo教条怎么说)除了子类型外,还有其他的子类化原因。但它仍然是
主要的
原因。在这种情况下,子类化似乎没有任何其他的原因,你没有试图共享存储细节,或者提供覆盖钩子,或者类似的东西。
2。事实上,你
可以
甚至想拖进去
abc
模块化,使其成为抽象属性,但我不会在这里显示。