Python3.10运行时如何获取Optional包装的底层类型完成类型对比
解决方法
首先要明确:Python的类型注解默认只供静态类型检查工具识别,不会在运行时改变变量的实际类型,type()方法只能拿到变量当前绑定的实例的真实类型,根本读不到你写的Optional[str]注解信息,自然没法基于注解做类型对比。
要在运行时穿透Optional修饰符拿到它包裹的底层类型,用Python 3.10原生支持的typing.get_origin()和typing.get_args()两个方法就可以实现:
Optional[X]本质是Union[X, None](3.10中也等价于X | None写法)的语法糖get_origin(注解对象)可以拿到泛型注解的原始根类型,用来识别当前注解是不是Optional对应的联合类型get_args(注解对象)可以拿到泛型包裹的所有参数,排除None类型后剩下的就是Optional包装的底层类型
修正后的可运行代码如下,运行后会输出你预期的结果:
from typing import Optional, get_type_hints, get_args, get_origin import types my_string: str = "" my_optional_string: Optional[str] = "" def unwrap_optional(annotation): # 兼容typing.Union、3.10+ | 联合类型两种Optional的底层实现 union_origins = (types.UnionType, type(Optional[str])) if get_origin(annotation) in union_origins: args = get_args(annotation) # 过滤掉None类型,剩下的就是Optional包裹的实际类型 real_types = [arg for arg in args if arg is not type(None)] if len(real_types) == 1: return real_types[0] return annotation # 拿到当前作用域的类型注解,类/函数场景传对应类/函数对象即可 hints = get_type_hints(__import__(__name__)) base_str_type = unwrap_optional(hints["my_string"]) unwrapped_optional_type = unwrap_optional(hints["my_optional_string"]) if base_str_type == unwrapped_optional_type: print("Yes they both can contain strings") else: print("No, not stringy types")
补充说明:如果你不需要校验注解,只是要判断运行时传入的值是不是合法的字符串,直接用isinstance(变量, str)即可——Optional[str]允许的合法值只有字符串实例和None,非None值直接用isinstance判断类型就足够,不需要额外解析注解。
内容的提问来源于stack exchange,提问作者JimmyNJ
相关产品推荐
相关产品推荐

