如何为PyCharm中动态生成的类添加类型提示消除Linter警告
解决PyCharm Linter对动态生成类的属性警告问题
方法1:为动态生成函数添加泛型类型提示
用typing.TypeVar和typing.Type定义泛型,让类型检查器明确make_augmented_class返回的是输入类的子类类型,从而识别继承的类属性。
修改后的完整代码:
from typing import TypeVar, Type T = TypeVar('T', bound='MyClass') class MyClass(object): ID_NUM: int = 0 def __init__(self, id_num: int, first_name: str, last_name: str): self.ID_NUM = id_num self.first_name = first_name self.last_name = last_name def make_augmented_class(cls: Type[T]) -> Type[T]: def augmented__eq__(self, other): try: return self.ID_NUM == other.ID_NUM except AttributeError: return False new_cls = type('{}Augmented'.format(cls.__name__), (cls,), {}) new_cls.__eq__ = augmented__eq__ return new_cls def do_stuff(my_class: Type[MyClass]): print(my_class.ID_NUM) if __name__ == '__main__': do_stuff(MyClass) augmented_class = make_augmented_class(MyClass) do_stuff(augmented_class) # Linter不再报警告
注:原代码中augmented__eq__里的self.id_num是笔误,修正为self.ID_NUM保证逻辑正确。
方法2:调用时用typing.cast强制类型转换
如果不想改动函数的类型注解,直接在调用do_stuff时用cast告诉Linter动态类的实际类型:
from typing import cast, Type # MyClass和make_augmented_class代码保持不变 def do_stuff(my_class: Type[MyClass]): print(my_class.ID_NUM) if __name__ == '__main__': do_stuff(MyClass) augmented_class = make_augmented_class(MyClass) do_stuff(cast(Type[MyClass], augmented_class)) # 强制转换类型消除警告
cast仅作用于类型检查阶段,不影响代码运行逻辑。
方法3:用Protocol定义类属性契约
如果需要更灵活的约束(只要类有ID_NUM属性就能传入do_stuff),可以用typing.Protocol定义契约:
from typing import Protocol, Type, TypeVar class HasIDNum(Protocol): ID_NUM: int T = TypeVar('T', bound=HasIDNum) class MyClass(object): ID_NUM: int = 0 def __init__(self, id_num: int, first_name: str, last_name: str): self.ID_NUM = id_num self.first_name = first_name self.last_name = last_name def make_augmented_class(cls: Type[T]) -> Type[T]: def augmented__eq__(self, other): try: return self.ID_NUM == other.ID_NUM except AttributeError: return False new_cls = type('{}Augmented'.format(cls.__name__), (cls,), {}) new_cls.__eq__ = augmented__eq__ return new_cls def do_stuff(my_class: Type[HasIDNum]): print(my_class.ID_NUM) if __name__ == '__main__': do_stuff(MyClass) augmented_class = make_augmented_class(MyClass) do_stuff(augmented_class)
这种方式不局限于MyClass及其子类,任何带有ID_NUM类属性的类都能传入do_stuff。
内容的提问来源于stack exchange,提问作者Roy Wood
相关产品推荐
相关产品推荐

