python - 继承类的属性名称更改。可能/不好的做法?
问题描述
Q1。如果我有一个非常通用的类,其名称可以在更具体的继承类中更好地表示,如果属性已更改其名称,我如何从父类访问相同的方法?例如(不是我的真实场景,但它说明了我的意思)。
class Entity(object):
def __init__(self):
self.members= {}
... # Methods that use self.members
class School(Entity):
def __init__(self):
super(Entity,self).__init__(self)
class Company(Entity):
def __init__(self):
super(Entity,self).__init__(self)
forclass School
和 for class Company
,我希望能够使用更具体的属性,例如self.students
and self.employees
,但仍然可以使用self.members
在class Entity
.
Q2。这是不好的做法吗?解决这个问题的最佳方法是什么?在我的真实案例中,我使用的这个词self.members
太笼统了。
解决方案
重命名子类中的属性通常是不好的做法。
原因是继承是关于可替代性的。aSchool
成为 an 的意思Entity
是,您可以School
在任何预期 an 的代码中使用 aEntity
并且它会正常工作。
例如,使用 an 的典型代码Entity
可能会执行以下操作:
for member in entity.members:
如果您有一些声称是Entity
(甚至通过isinstance(myschool, Entity)
)的东西,但它要么没有members
,要么有一个空的members
,因为它的实际成员存储在其他一些属性中,那么该代码就被破坏了。
更一般地说,如果您更改基类和派生类之间的接口(公共方法和属性集),则派生类不是子类型,这意味着它通常不应该在第一种情况下使用继承。1
如果您students
为设置别名,members
因此可以在任一名称下访问相同的属性,那么您确实有一个子类型: aSchool
有它的students
as members
,因此它可以与需要 a 的代码一起使用Entity
:
myschool.students.append(Person(cap'))
# ...
for member in myschool.members:
# now cap is going to show up here
这与定义在中的方法一样有效Entity
:
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
所以,这不是完全无效或任何东西。
但它可能具有误导性。
对您的代码的读者来说,添加to 会将他添加cap
到是否会很明显?如果是这样,它可能没问题。如果不是,或者如果您不确定,那么您可能不应该这样做。myschool.students
myschool.members
要考虑的另一件事是,aSchool
可能有多种成员:学生、教师、管理人员、辍学者,他们在旧校园里闲逛,因为他们不知道在哪里可以找到毒贩……如果这是你设计的一部分,那么你真正想要的是将成员作为一个属性,并且可能是一个只读属性,2并且每个子类都可以以对该子类有意义的方式定义什么算作“成员”。
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
是作为一个School
,作为一个Entity
,一切都很好。
1. 我说通常是因为(不管 OO 教条怎么说)除了子类型之外还有其他原因进行子类化。但这仍然是主要原因。在这种情况下,似乎没有任何其他原因进行子类化——您没有尝试共享存储详细信息,或提供覆盖挂钩或类似的东西。
2. 实际上,您甚至可能想将abc
模块拖入并使其成为抽象属性……但我不会在这里展示。
推荐阅读
- reactjs - 在 React 中处理服务器端受保护路由的正确方法?
- reactjs - React 事件处理函数在不使用 bind() 的情况下工作
- swift4.1 - Swift 4.1 中的“.addingPercentEncoding”有什么问题?
- java - 带有页面大小检测的 itext 7 html 到 pdf
- go - 在没有接收器的情况下,是否可以将数据打开的缓冲通道保留下来?
- rest - PowerBuilder 如何连接到 REST API?
- c++ - openmp Linux中的分段错误
- python - Python 的 Queue.PriorityQueue 不是自动排序的吗?
- c++ - 获取指向地图内结构的指针
- c# - 为什么用户设置找不到布尔设置?