使用Python Protocol类型提示时方法返回不同类型触发类型检查错误
类型推断窄化问题与泛型Protocol解决方案
问题原因
这不是Pylance误报,而是类型推断逻辑导致的:
- 当把
obj和input的定义放在分支外统一赋值时,Pylance会将obj推断为MyClass | MyOtherClass联合类型,input推断为int | str联合类型。 - 对于
MyClass的my_propertysetter,它仅接受int类型,但此时input可能是str,类型检查器无法确保两者类型始终匹配,因此抛出不兼容错误。 - 而将赋值操作移到分支内部时,每个分支里
obj和input的类型都是明确的(比如分支1里obj是MyClass,input是int),类型检查器能确认类型匹配,所以报错消失。
解决方案:使用泛型Protocol
原来的MyProtocol用typing.Any无法约束类型一致性,应该改用泛型Protocol,让my_method、my_property的输入输出类型与泛型参数绑定,这样每个实现类对应具体的类型,类型检查器能正确跟踪类型关联。
修改后的代码如下:
import typing from typing import Protocol, TypeVar # 定义泛型类型变量,限定为int或str T = TypeVar('T', int, str) class MyProtocol(Protocol[T]): _output: T def my_method(self, some_arg: T) -> T: ... # 用...代替raise NotImplementedError更符合Protocol规范 @property def my_property(self) -> T: ... @my_property.setter def my_property(self, some_arg: T) -> None: ... class MyClass(MyProtocol[int]): _output: int def my_method(self, some_arg: int) -> int: return some_arg @property def my_property(self) -> int: return self._output @my_property.setter def my_property(self, some_arg: int) -> None: some_value = self.my_method(some_arg) self._output = some_value class MyOtherClass(MyProtocol[str]): _output: str def my_method(self, some_arg: str) -> str: return some_arg @property def my_property(self) -> str: return self._output @my_property.setter def my_property(self, some_arg: str) -> None: some_value = self.my_method(some_arg) self._output = some_value
调整process函数的返回类型标注后,即使把赋值操作放在分支外,类型检查器也能正确识别类型匹配:
def process(class_name: str) -> MyProtocol[int] | MyProtocol[str]: if class_name == 'MyClass': input_val = 3 # 避免使用Python内置关键字input obj = MyClass() elif class_name == 'MyOtherClass': input_val = 'stuff' obj = MyOtherClass() else: raise NotImplementedError obj.my_property = obj.my_method(input_val) return obj
内容的提问来源于stack exchange,提问作者henryn
相关产品推荐
相关产品推荐

