Python获取数据类中所有字段的名称

6
我将尝试编写一个函数来记录数据类,我希望能够获取数据类中所有字段的名称并打印每个字段的值(类似于编写打印字典的函数)。
例如:
@dataclasses.dataclass
class Test:
    a: str = "a value"
    b: str = "b value"


test = Test()
def print_data_class(dataclass_instance):
   fields = # get dataclass fileds
   for field in fields:
       print(f{field}: {dataclass.field})
print_data_class(test)

-->
"a"  : "a value"
"b"  : "b value"

然而,我还没有找到如何获取数据类的字段,有人知道怎么做吗?
谢谢。

1
https://docs.python.org/3/library/dataclasses.html#dataclasses.fields - deceze
3个回答

14

这个例子只展示了名称、类型和值,然而__dataclass_fields__是一个字典,其中包含Field对象的信息,每个对象都包含名称、类型、默认值等。

使用dataclasses.fields()

使用dataclasses.fields()可以访问您在数据类中定义的字段。

fields = dataclasses.fields(dataclass_instance)

使用 inspect.getmembers()

通过 inspect.getmembers() 你可以访问你的数据类中的所有字段。

members = inspect.getmembers(type(dataclass_instance))
fields = list(list(filter(lambda x: x[0] == '__dataclass_fields__', members))[0][1].values())

完整代码解决方案

import dataclasses
import inspect


@dataclasses.dataclass
class Test:
    a: str = "a value"
    b: str = "b value"


def print_data_class(dataclass_instance):

    # option 1: fields
    fields = dataclasses.fields(dataclass_instance)

    # option 2: inspect
    members = inspect.getmembers(type(dataclass_instance))
    fields = list(list(filter(lambda x: x[0] == '__dataclass_fields__', members))[0][1].values())

    for v in fields:
      print(f'{v.name}: ({v.type.__name__}) = {getattr(dataclass_instance, k)}')


print_data_class(Test())
# a: (str) = a value
# b: (str) = b value

print_data_class(Test(a="1", b="2"))
# a: (str) = 1
# b: (str) = 2

当你已经展示了可用的好的、干净的方法时,那些不祥的过滤器/lambda/索引的字符串似乎是不必要的。它有什么优势吗? - CrazyChucky
@CrazyChucky 区别在于 inspect 为您提供了访问除您定义的这些字段之外的更多信息(例如 __annotations____dataclass_params____doc__ 等)。 - K.Mat
2
你不需要将dataclass_instance传递给fields(),直接使用类本身也可以。 - undefined

2

使用__dict__属性

def print_data_class(dataclass_instance):
   fields = [(attribute, value) for attribute, value in dataclass_instance.__dict__.items()]
   for field in fields:
       print("{}: {}".format(*field))

1
我认为你可能是想用dataclass_instance.__dict__.items()print("f{field[0]}: {field[1]}",但除此之外都很棒,谢谢。 - Pioneer_11
1
我曾经认为,由于数据类不是普通类,所以那样做行不通。 - Pioneer_11
1
请注意,这也将获取在运行时设置的其他属性,而不仅仅是在数据类中定义的字段。 - CrazyChucky

0
此外,您还可以使用__annotations__,因为数据字段始终会被注释。这是使用数据类的精髓。
它适用于类。
    fields = list(Test.__annotations__)

以及具体例子
    fields = list(test.__annotations__)

需要注意的是,它不能与数据类的子类一起使用。显然。然而,简单性使您直接获得字段名称,无需额外的代码从字段对象中提取。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接