Python多继承中子类继承父类属性及属性初始化验证的问题
Python多继承中子类继承父类属性及属性初始化验证的问题
我来帮你解决这两个问题,顺便修正代码里的一些逻辑小问题,先看第一个:
问题1:让Child自动继承Father的surname,无需创建对象时手动传入
你当前的代码里Child类没有定义__init__方法,默认会调用第一个父类Father的__init__,但Father的__init__需要4个参数,你创建peter时只传了3个,本身就会报错。而且原来的patronymic属性逻辑有问题,它会取孩子自己的名字而不是父亲的名字,达不到预期的Alexeyvich效果。
最符合现实逻辑的解决方案是让Child关联具体的父类实例,直接继承父类的属性,修改如下:
修改后的Child类及调用代码
class Father: def __init__(self, surname, name, age, size): self.surname = surname self.name = name self.age = age if size in range(5, 31): self.__d_size = size @property def d_size(self): return self.__d_size @d_size.setter def d_size(self, size): if size in range(5, 31): self.__d_size = size class Mother: def __init__(self, surname, name, age, size): self.surname = surname self.name = name self.age = age if size in range(1, 7): self.__b_size = size @property def b_size(self): return self.__b_size @b_size.setter def b_size(self, size): if size in range(1, 7): self.__b_size = size class Child(Father, Mother): def __init__(self, father_instance, mother_instance, child_name, child_age, child_d_size, child_b_size): # 保存父类实例的引用,方便后续获取父亲的名字等属性 self.father = father_instance self.mother = mother_instance # 调用Father的初始化:用父亲的姓氏,孩子的名字、年龄、d_size Father.__init__(self, father_instance.surname, child_name, child_age, child_d_size) # 调用Mother的初始化:同样用父亲的姓氏,孩子的名字、年龄,以及孩子的b_size Mother.__init__(self, father_instance.surname, child_name, child_age, child_b_size) @property def gender(self): # 改用self直接访问属性,super()在这里会找不到Mother的b_size if (self.d_size + self.b_size) % 2 != 0: return "male" else: return "female" @property def patronymic(self): # 从保存的父亲实例里取名字,而不是自己的名字 if self.gender == "male": return self.father.name + "vich" else: return self.father.name + "vna" @property def full_name(self): return f"{self.surname} {self.name} {self.patronymic}, {self.age} years old, {self.gender}" if __name__ == '__main__': alex = Father('Romanov', 'Alexey', 46, 20) nata = Mother('Naryshkina', 'Natalya', 24, 3) # 传入父类实例+孩子自身的信息,无需手动传姓氏 peter = Child(alex, nata, 'Peter', 3, 5, 3) print(peter.full_name) # 输出:Romanov Peter Alexeyvich, 3 years old, male
这样peter的surname自动从父亲alex那里继承,patronymic也正确取到了父亲的名字,完全符合你的预期。
问题2:属性初始化时的验证最佳实践
你说得很对,@property的setter只在修改已存在的属性时生效,初始化时的验证必须在__init__里处理,但重复写验证逻辑会很冗余。最佳实践是把验证逻辑抽成单独的私有方法,让__init__和setter都调用它,这样既统一了规则,又避免重复代码。
修改后的父类验证逻辑
以Father类为例,优化后:
class Father: def __init__(self, surname, name, age, size): self.surname = surname self.name = name # 初始化时调用年龄验证方法 self.age = self._validate_age(age) # 初始化时调用d_size验证方法 self.__d_size = self._validate_d_size(size) # 抽取出d_size的统一验证逻辑 def _validate_d_size(self, size): if not isinstance(size, int): raise ValueError("d_size必须是整数") if size not in range(5, 31): raise ValueError(f"d_size必须在5到30之间,你传入的是{size}") return size @property def d_size(self): return self.__d_size @d_size.setter def d_size(self, size): # 修改属性时同样调用验证方法 self.__d_size = self._validate_d_size(size) # 抽取出年龄的统一验证逻辑 def _validate_age(self, age): if not isinstance(age, int) or age < 12: raise ValueError(f"年龄必须是大于等于12的整数,你传入的是{age}") return age
Mother类可以用同样的方式优化b_size和age的验证:
class Mother: def __init__(self, surname, name, age, size): self.surname = surname self.name = name self.age = self._validate_age(age) self.__b_size = self._validate_b_size(size) def _validate_b_size(self, size): if not isinstance(size, int): raise ValueError("b_size必须是整数") if size not in range(1, 7): raise ValueError(f"b_size必须在1到6之间,你传入的是{size}") return size @property def b_size(self): return self.__b_size @b_size.setter def b_size(self, size): self.__b_size = self._validate_b_size(size) def _validate_age(self, age): if not isinstance(age, int) or age < 12: raise ValueError(f"年龄必须是大于等于12的整数,你传入的是{age}") return age
这样不管是初始化属性还是后续修改属性,都会执行相同的验证规则,代码更简洁易维护。如果后续要调整验证条件,只需要修改对应的私有方法即可。
备注:内容来源于stack exchange,提问作者TiimeIrre
相关产品推荐
相关产品推荐

