Python如何将typing泛型字符串表示还原为对应类型对象
问题描述
现有如下代码:
from typing import List from dataclasses import dataclass, field @dataclass class Paradise: saints : List[str] the_type_i_want = Paradise.__dataclass_fields__["saints"].type
上述代码中获取到的the_type_i_want的字符串表示为"typing.List[str]",查看the_type_i_want.__dict__可得如下内容:
{'_inst': False, '_special': False, '_name': 'List', '__origin__': list, '__args__': (str,), '__parameters__': (), '__slots__': None }
现在给定任意泛型类型的字符串表示,例如"typing.List[str]"、"typing.List[MyClass]"甚至更复杂的typing.Optional[typing.Map[str,MyOtherClass]],需要将其还原为对应的实际类型对象,且要求不出现类型擦除,完整保留泛型参数信息。
现有的类似Java Class.forName的Python类名反射实现仅支持普通类,无法处理泛型场景,需要实现如下通用方法:
def class_for_name(class_name: str) -> type: ???
实现方案
核心逻辑为递归解析泛型字符串的嵌套结构,同时支持内置类型、typing模块泛型、自定义类的动态导入,完整实现代码如下:
import importlib def _import_base_type(type_name: str): """导入非泛型的基础类型,支持内置类型、typing模块类型、自定义类""" # 优先匹配内置类型 if type_name in __builtins__: return __builtins__[type_name] # 拆分模块路径和类名 parts = type_name.split('.') module_name = '.'.join(parts[:-1]) class_name = parts[-1] module = importlib.import_module(module_name) return getattr(module, class_name) def class_for_name(class_name: str) -> type: class_name = class_name.strip() # 无泛型参数,直接导入基础类型 if '[' not in class_name: return _import_base_type(class_name) # 拆分泛型基类名和参数部分 bracket_start = class_name.index('[') base_type_name = class_name[:bracket_start].strip() # 找到匹配的闭合方括号,处理嵌套场景 bracket_count = 1 bracket_end = bracket_start + 1 while bracket_count > 0 and bracket_end < len(class_name): if class_name[bracket_end] == '[': bracket_count += 1 elif class_name[bracket_end] == ']': bracket_count -= 1 bracket_end += 1 params_str = class_name[bracket_start+1 : bracket_end-1].strip() # 拆分多个泛型参数,忽略嵌套括号内的逗号 params = [] current_param = '' bracket_count = 0 for c in params_str: if c == ',' and bracket_count == 0: params.append(current_param.strip()) current_param = '' continue if c == '[': bracket_count += 1 elif c == ']': bracket_count -= 1 current_param += c if current_param.strip(): params.append(current_param.strip()) # 递归处理每个泛型参数 processed_params = [class_for_name(p) for p in params] # 导入基础泛型类,构造完整泛型对象 base_type = _import_base_type(base_type_name) return base_type[tuple(processed_params)]
使用示例
from typing import List, Optional, Dict # 测试简单泛型 t1 = class_for_name("typing.List[str]") print(t1 == List[str]) # 输出 True # 测试嵌套泛型 t2 = class_for_name("typing.Optional[typing.Dict[str, int]]") print(t2 == Optional[Dict[str, int]]) # 输出 True # 测试自定义类泛型(假设my_module模块下存在MyClass类) # from my_module import MyClass # t3 = class_for_name("typing.List[my_module.MyClass]") # print(t3 == List[MyClass]) # 输出 True
注意事项
- 自定义类需要确保对应的模块在Python的导入搜索路径中,否则会抛出导入异常
- 支持任意深度的泛型嵌套场景
- Python 3.9+支持的原生集合泛型(如
list[str])也可直接使用,传入对应字符串即可自动识别构造
内容的提问来源于stack exchange,提问作者JayZee
相关产品推荐
相关产品推荐

