Python类继承时如何优化返回类实例方法的类型提示
实现方法
要实现子类调用父类类方法时,类型检查器自动识别返回值为对应子类类型,不需要在每个子类重复重写方法,有两种标准实现方案:
方案1:Python 3.11+ 直接使用Self类型
Python 3.11 标准库typing模块新增了专门用于标记「当前类实例」的Self类型,是最简洁的实现方式:
from random import randint from typing import Self class Person: def __init__(self, name: str, age: int): self.name = name self.age = age @classmethod def get_random_person(cls) -> Self: return cls("Random Guy", randint(18, 65)) class Player(Person): pass def welcome_player(player: Player): print(f"Welcome {player.name}") player = Player.get_random_person() welcome_player(player)
用mypy检测上述代码不会抛出任何类型错误,Player.get_random_person()的返回值会被自动识别为Player类型。
方案2:兼容Python 3.6+ 旧版本的泛型实现
如果需要兼容低于3.11的Python版本,可以通过TypeVar绑定父类类型的方式实现相同效果:
from random import randint from typing import TypeVar # 定义绑定到Person类的泛型参数 T = TypeVar("T", bound="Person") class Person: def __init__(self, name: str, age: int): self.name = name self.age = age # 给cls参数标注泛型类型,返回值对应泛型代表的子类实例 @classmethod def get_random_person(cls: type[T]) -> T: return cls("Random Guy", randint(18, 65)) class Player(Person): pass def welcome_player(player: Player): print(f"Welcome {player.name}") player = Player.get_random_person() welcome_player(player)
原理说明
最初的写法里,把方法返回值标注为Person,类型检查器会默认所有子类调用该方法的返回值都是父类Person实例,无法自动推断为子类类型,因此会抛出类型不匹配错误。
上述两种方案都可以让类型检查器追踪调用方法的类,自动匹配返回值为对应的类类型,不管Person被多少个子类继承,都不需要额外在子类中重写方法补充类型注解,完全避免冗余代码。
注意:如果使用旧版本方案,在Python 3.7及以上版本,可以通过开头添加
from __future__ import annotations,把TypeVar的bound参数从字符串"Person"改为直接写Person,避免前向引用报错。
内容的提问来源于stack exchange,提问作者Jean-Francois T.
相关产品推荐
相关产品推荐

