如何从Dog实例创建子类BigDog并通过mypy类型检查?
从父类实例初始化子类并兼容类型检查的解决方案
问题背景
现有不可修改的Dog类及两个方法:
class Dog: def __init__(self, size): self.size = size # 可能存在更多未知属性 def bar(self): print(f"WOOF {self.size}") # 以下两个方法不可修改 def get_dog(): return Dog("big") def foo(dog: Dog): dog.bar()
需要扩展bar方法的功能,让foo调用修改后的版本,因此定义了Dog的子类BigDog并重写bar:
class BigDog(Dog): def bar(self): print("WOFWOF")
但面临的问题是:需要从get_dog()返回的Dog实例创建BigDog实例,且不清楚Dog的全部属性和get_dog的实现;此前尝试的包装类方案会触发mypy类型不兼容错误。
解决方案
方法1:通过复制实例属性初始化子类
利用Python实例的__dict__属性(存储实例的自定义属性),直接将父类实例的属性复制到子类实例中,无需知晓Dog的构造参数和全部属性:
class BigDog(Dog): def __init__(self, dog_instance: Dog): # 复制父类实例的所有属性到当前子类实例 self.__dict__.update(dog_instance.__dict__) def bar(self): print("WOFWOF")
使用方式:
original_dog = get_dog() big_dog = BigDog(original_dog) foo(big_dog) # 输出 WOFWOF,且mypy类型检查通过
方法2:用类方法实现实例转换
如果想避免直接在__init__中处理父类实例,可定义类方法来完成转换逻辑,更符合面向对象的代码风格:
class BigDog(Dog): @classmethod def from_dog(cls, dog: Dog) -> "BigDog": # 创建子类实例但不调用父类__init__ instance = cls.__new__(cls) # 复制父类实例的所有属性 instance.__dict__.update(dog.__dict__) return instance def bar(self): print("WOFWOF")
使用方式:
big_dog = BigDog.from_dog(get_dog()) foo(big_dog) # 输出 WOFWOF,类型检查正常
关键说明
- 类型兼容性:
BigDog是Dog的子类,完全符合foo函数对参数类型Dog的要求,mypy不会抛出类型不兼容错误。 - 属性复制:上述两种方法通过
__dict__.update()复制实例属性,无需了解Dog的具体属性列表,适配Dog存在未知属性的场景。 - 特殊情况处理:如果
Dog类使用了__slots__(此时实例没有__dict__),可改用vars()函数获取属性字典,或遍历dir(dog)筛选实例属性进行复制。
内容的提问来源于stack exchange,提问作者kosciej16
相关产品推荐
相关产品推荐

