继承类的属性名称更改。可能/不良做法?

时间:2018-07-10 19:32:34

标签: python python-2.7

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)

对于class Schoolclass Company,我希望能够使用更具体的属性,例如self.studentsself.employees,但仍然可以使用在self.members中为class Entity定义的方法。

第二季度。这是不好的做法吗?解决此问题的最佳方法是什么?在我的真实情况下,我用于self.members的单词太笼统了。

1 个答案:

答案 0 :(得分:0)

重命名子类中的属性通常是不好的做法。

原因是inheritance is about substitutabilitySchool成为Entity的意思是,您可以在任何期望使用School的代码中使用Entity,它可以正常工作。 / p>

例如,使用Entity的典型代码可能会执行以下操作:

for member in entity.members:

如果您声称自己是Entity(甚至通过了isinstance(myschool, Entity)),但是没有members或空白members ,因为其实际成员存储在其他属性中,所以该代码已损坏。

更一般地说,如果您更改基类和受约束的类之间的接口(一组公共方法和属性),则派生类不是子类型,这意味着它通常不应在第一个中使用继承。情况。 1


如果将students设为members别名,那么可以使用 名称访问相同的属性,那么您 do 有一个子类型:School的{​​{1}}为students,因此可以合理地将其与期望members的代码一起使用:

Entity

这与myschool.students.append(Person(cap')) # ... for member in myschool.members: # now cap is going to show up here 中定义的方法同样有效:

Entity

您可以使用@property来做到这一点。

def slap_everyone(self):
    for member in self.members:
        # this will include cap
        member.slap()

myschool.slap_everyone()

因此,这不是完全无效的。

但这可能会引起误解。

对您的代码读者来说,将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可能有多种成员:学生,老师,管理人员,在旧校园里闲逛的辍学学生,因为他们不知道在其他地方可以找到毒贩,……如果那是设计的一部分,那么您真正想要的是让成员成为一个属性,并且可能是一个只读属性, 2 ,每个子类都可以定义什么对该子类有意义的方式算作“成员”。

School

这将打印出来:

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 作为schoolSchool工作,一切都很好。


1。我通常说 是因为(不管OO教义怎么说),除了子类型化之外,还有其他原因可以进行子类化。但这仍然是主要原因。在这种情况下,似乎没有其他任何原因可以进行子类化-您不是在尝试共享存储详细信息,不提供覆盖的钩子或类似的东西。

2。实际上,您可能甚至想要拖动Entity模块并将其作为抽象属性……但是在这里我不会显示。