Python中如何为参数添加类型注解,限定为正规类实例或非原始类型对象
这个问题问得太精准了!确实,Any和object太宽泛,根本没法区分开那些能安全调用setattr的自定义类实例,以及调用就会报错的内置原始类型。我给你几个实用的折中方案,完全符合你“不用绝对严谨”的需求:
方案1:结合协议(Protocol)与运行时类型守卫
这种方式兼顾静态类型提示和运行时安全,是最常用的做法:
from typing import Protocol, TypeGuard, Any # 定义一个协议,标记支持__setattr__的类型 class Settable(Protocol): def __setattr__(self, name: str, value: Any) -> None: ... # 类型守卫函数:过滤掉运行时调用setattr会报错的内置类型 def is_safe_settable(obj: Any) -> TypeGuard[Settable]: # 列出所有不可添加属性的内置类型 unsafe_builtins = (int, str, float, bool, tuple, frozenset, bytes) return not isinstance(obj, unsafe_builtins) def func(a: Settable) -> None: # 运行时兜底检查,避免意外报错 if not is_safe_settable(a): raise TypeError(f"不能给{type(a).__name__}类型的实例设置属性") setattr(a, "foo", "bar") # 自定义类可以显式实现协议,让类型检查器更明确 class MyClass(Settable): pass func(MyClass()) # 静态检查+运行时都完全正常 func(1) # 运行时会抛出错误,静态检查器(如mypy)会提示类型不匹配 func({}) # 运行时可正常设置属性(dict实例支持添加属性),静态检查也通过
方案2:严格只允许自定义类实例
如果你的需求是完全排除所有内置类型(哪怕像dict这种能设置属性的也不想允许),可以用下面的方式:
from typing import Any, TypeGuard def is_custom_instance(obj: Any) -> TypeGuard[object]: # 判断对象的类是否定义在非内置模块中 return obj.__class__.__module__ != 'builtins' def func(a: object) -> None: if not is_custom_instance(a): raise TypeError("仅允许自定义类的实例") setattr(a, "foo", "bar") func(MyClass()) # 正常运行 func(1) # 触发错误 func({}) # 触发错误
这个方案完全匹配你例子中的期望,但缺点是静态类型检查器没法提前识别,只能靠运行时拦截——不过对于大多数场景来说已经足够用了。
补充说明
因为Python的动态特性,没有一种完美的静态类型注解能100%区分“可安全setattr”和“不可安全setattr”的对象(比如有些自定义类可能重写了__setattr__,导致无法设置属性)。上面的方案都是在“实用优先”的前提下做的折中,完全符合你“不追求绝对严谨”的要求。
内容的提问来源于stack exchange,提问作者aleneum
相关产品推荐
相关产品推荐

