获取类属性列表,包括子对象的属性 - Python



我想得到这个类的所有属性的列表,包括这个类的sub_objects中使用的属性。

示例:

@dataclass
class Phones:
mobile: Optional[str] = None
work_phone: Optional[str] = None
@dataclass
class People:
id: str
name: str
phones: Phones

我有People类,它的一个属性是类型Phones。我想返回此列表:

['id', 'name', 'mobile', 'work_phone']

我尝试了__dict____annotations__dir()和更多的员工,但我找不到通用和动态的方法。我的解决方案是做一个转换器并返回这个硬编码的列表,这对维护来说似乎是个坏主意。

我想要所有具有原始类型的属性。(例如,我不想包含phones。(

递归?你不需要sbNative,它只是我的干净日志模块。

from dataclasses import dataclass, is_dataclass
from typing import Optional
from sbNative.debugtools import log
@dataclass
class Phones:
mobile: Optional[str] = None
work_phone: Optional[str] = None
@dataclass
class People:
id: str
name: str
phones: Phones

def find_dataclasses(cls):
classes = []
for obj in cls.__annotations__.values():
if is_dataclass(obj):
classes += find_dataclasses(obj)
classes.append(obj)
return classes
if __name__ == "__main__":
log(*find_dataclasses(People))

感谢https://stackoverflow.com/users/13526701/noblockhit

我设法用下一个代码实现了我想要的:

def list_attributes(entity: object) -> List[str]:
"""
@returns: List of all the primitive attributes
"""
attributes: List[str] = []
entity_attributes = entity.__annotations__.items()
for attribute_name, attribute_type in entity_attributes:
if is_dataclass(attribute_type):
attributes += list_attributes(attribute_type)
else:
attributes.append(attribute_name)
return attributes

这个很好,但不幸的是,如果您有更复杂的注释,例如List[Phones]这样的容器类型,它就不起作用了。例如:

@dataclass
class Phones:
mobile: Optional[str] = None
work_phone: Optional[str] = None
@dataclass
class People:
id: str
name: str
phones: List[Phones]

电流输出为:['id', 'name', 'phones']。但是,请注意,我们希望排除字段phones,并包括Phone类的所有字段mobilework_phone

要处理此类类型,可以使用typing.get_args()并对每个带下标的类型进行迭代,检查每个类型是否为数据类。

from dataclasses import dataclass, is_dataclass
from typing import Optional, List, get_args

@dataclass
class Phones:
mobile: Optional[str] = None
work_phone: Optional[str] = None

@dataclass
class People:
id: str
name: str
phones: List[Phones]

def list_attributes(entity: object) -> List[str]:
"""
@returns: List of all the primitive attributes
"""
attributes: List[str] = []
entity_attributes = entity.__annotations__.items()
for attribute_name, attribute_type in entity_attributes:
args = get_args(attribute_type)
if args:
found_class = False
for arg in args:
if is_dataclass(arg):
found_class = True
attributes += list_attributes(arg)
if not found_class:
attributes.append(attribute_name)
elif is_dataclass(attribute_type):
attributes += list_attributes(attribute_type)
else:
attributes.append(attribute_name)
return attributes

print(list_attributes(People))

上述修改版本正确输出所需结果:

['id', 'name', 'mobile', 'work_phone']

最新更新