如何迭代 python 中数据类的属性?
How to iterate over attributes of dataclass in python?
是否可以在 python 中迭代数据 class 实例的属性?例如,我想在 __post_init__
中加倍整数属性:
from dataclasses import dataclass, fields
@dataclass
class Foo:
a: int
b: int
def __post_init__(self):
self.double_attributes()
def double_attributes(self):
for field in fields(Foo):
field = field*2
x = {
'a': 1,
'b': 2
}
y = Foo(**x)
>>> TypeError: unsupported operand type(s) for *: 'Field' and 'int'
如何访问 class 实例的值并将其设置为类似于下面但在循环中的其他值?
@dataclass
class Foo:
a: int
b: int
def __post_init__(self):
self.double_a()
self.double_b()
def double_a(self):
self.a = self.a*2
def double_b(self):
self.b = self.b*2
是的,这是可能的。你可以这样做
def double_attributes(self):
for field in self.__dataclass_fields__:
value = getattr(self, field)
setattr(self, field, value * 2)
__dataclass_fields__
returns 包含对象所有字段的字典。然后,您可以使用 getattr 来检索每个字段的值,并使用 setattr 来按名称更改每个字段的值。
你非常接近,但 dataclasses.fields
实际上 return 是一个 Field
对象的元组。至少在我的例子中,return 类型似乎没有正确注释,但这很容易修复。
from dataclasses import dataclass, fields, Field
from typing import Tuple
@dataclass
class Foo:
a: int
b: int
def __post_init__(self):
self.double_attributes()
def double_attributes(self):
# Note the annotation added here (tuple of one or more
# `dataclasses.Field`s)
cls_fields: Tuple[Field, ...] = fields(self.__class__)
for field in cls_fields:
# This check is to avoid fields annotated with other types
# such as `str`
if issubclass(field.type, int):
new_val = getattr(self, field.name) * 2
setattr(self, field.name, new_val)
但是如果您多次 运行(例如创建许多 Foo
对象),那么缓存整数字段列表可能会稍微有效一些。例如,以下是我可能建议的伪代码:
integer_fields: ClassVar[Frozenset[Field]] = frozenset(f for f in fields(cls) if issubclass(f.type, int))
我认为最简单的方法是使用 typing.get_type_hints
检索 实例的注释 ,而不是 class 的字段。 get_type_hints
returns 字典映射 class 属性到它们被注释的类型。例如:
>>> from typing import get_type_hints
>>>
>>> class Bar:
... x: int
... y: str
...
>>> get_type_hints(Bar)
{'x': <class 'int'>, 'y': <class 'str'>}
>>> b = Bar()
>>> get_type_hints(b)
{'x': <class 'int'>, 'y': <class 'str'>}
如您所见,get_type_hints
在实例上的效果与在 classes 上一样好。
对于您的情况,您可以使用 get_type_hints
来解决您的情况,如下所示:
from dataclasses import dataclass
from typing import get_type_hints
@dataclass
class Foo:
a: int
b: int
def __post_init__(self):
self.double_attributes()
def double_attributes(self):
for field_name, field_type in get_type_hints(self).items():
if issubclass(field_type, int):
current_val = getattr(self, field_name)
setattr(self, field_name, (current_val * 2))
是否可以在 python 中迭代数据 class 实例的属性?例如,我想在 __post_init__
中加倍整数属性:
from dataclasses import dataclass, fields
@dataclass
class Foo:
a: int
b: int
def __post_init__(self):
self.double_attributes()
def double_attributes(self):
for field in fields(Foo):
field = field*2
x = {
'a': 1,
'b': 2
}
y = Foo(**x)
>>> TypeError: unsupported operand type(s) for *: 'Field' and 'int'
如何访问 class 实例的值并将其设置为类似于下面但在循环中的其他值?
@dataclass
class Foo:
a: int
b: int
def __post_init__(self):
self.double_a()
self.double_b()
def double_a(self):
self.a = self.a*2
def double_b(self):
self.b = self.b*2
是的,这是可能的。你可以这样做
def double_attributes(self):
for field in self.__dataclass_fields__:
value = getattr(self, field)
setattr(self, field, value * 2)
__dataclass_fields__
returns 包含对象所有字段的字典。然后,您可以使用 getattr 来检索每个字段的值,并使用 setattr 来按名称更改每个字段的值。
你非常接近,但 dataclasses.fields
实际上 return 是一个 Field
对象的元组。至少在我的例子中,return 类型似乎没有正确注释,但这很容易修复。
from dataclasses import dataclass, fields, Field
from typing import Tuple
@dataclass
class Foo:
a: int
b: int
def __post_init__(self):
self.double_attributes()
def double_attributes(self):
# Note the annotation added here (tuple of one or more
# `dataclasses.Field`s)
cls_fields: Tuple[Field, ...] = fields(self.__class__)
for field in cls_fields:
# This check is to avoid fields annotated with other types
# such as `str`
if issubclass(field.type, int):
new_val = getattr(self, field.name) * 2
setattr(self, field.name, new_val)
但是如果您多次 运行(例如创建许多 Foo
对象),那么缓存整数字段列表可能会稍微有效一些。例如,以下是我可能建议的伪代码:
integer_fields: ClassVar[Frozenset[Field]] = frozenset(f for f in fields(cls) if issubclass(f.type, int))
我认为最简单的方法是使用 typing.get_type_hints
检索 实例的注释 ,而不是 class 的字段。 get_type_hints
returns 字典映射 class 属性到它们被注释的类型。例如:
>>> from typing import get_type_hints
>>>
>>> class Bar:
... x: int
... y: str
...
>>> get_type_hints(Bar)
{'x': <class 'int'>, 'y': <class 'str'>}
>>> b = Bar()
>>> get_type_hints(b)
{'x': <class 'int'>, 'y': <class 'str'>}
如您所见,get_type_hints
在实例上的效果与在 classes 上一样好。
对于您的情况,您可以使用 get_type_hints
来解决您的情况,如下所示:
from dataclasses import dataclass
from typing import get_type_hints
@dataclass
class Foo:
a: int
b: int
def __post_init__(self):
self.double_attributes()
def double_attributes(self):
for field_name, field_type in get_type_hints(self).items():
if issubclass(field_type, int):
current_val = getattr(self, field_name)
setattr(self, field_name, (current_val * 2))