python 数据类中使用的字段元数据是什么
what is field metadata used for in python dataclasses
我一直在 documentation 通读 python 数据类和其他网页。字段元数据是只读的,文档说:
It is not used at all by Data Classes and is provided as a third-party extension mechanism
我对第三方扩展如何使用“只读映射中的值”感到困惑。这看起来像是以前会进入软件文档的内容?
我的目的是装饰我的字段,以便我知道是否计算了特定值(字段的一部分),我认为这不是通过元数据可以实现的,对吗?
有些图书馆确实利用了元数据。例如,marshmallow 是一个非常流行的 dataclass 验证库,它允许您安装自定义验证器方法和一些其他的东西,方法是在您自己定义的 dataclass 中使用元数据挂钩。我想其他想要扩展 dataclasses 可用性的库也可以利用它。
是的,您的猜测是您不想/不能使用元数据来跟踪某个字段是否已计算,这对我来说是正确的。我认为你可以做一些 hack 来完成你想做的事情,但听起来你想要一个 class 比 dataclasses 及其字段的元数据功能更有状态“应该是。
由于映射代理是只读的,因此在实例化数据时首次创建它后,您无法对其进行更新class。解决元数据字段的只读限制的最灵活方法是让元数据字段本身指向 dataclass 实例本身范围之外的内容。在这种情况下,只读包装器围绕着您指向的内容,而不是内容中的内容。或者,您也可以在运行时自己更新 class 的整个元数据字段(这是允许的,因为元数据的内容是只读的,而不是元数据字段本身)。
但是,如果您更匿名地创建它,您将无法在创建时间后更改元数据字段的内容。
例如:
from dataclasses import dataclass, field, fields
external_metadata_dict = {'is_initialized': False}
other_external_metadata_dict = {'foo': 1}
@dataclass
class UsesExternalDict:
variable: int = field(metadata=external_metadata_dict)
example1 = UsesExternalDict(0)
print(f'example1 initial metadata: {fields(example1)[0].metadata}')
example2 = UsesExternalDict(0)
print(f'example2 initial metadata: {fields(example2)[0].metadata}')
# update the thing example1 and example2 both point to, even though their metadata is in a read-only wrapper
external_metadata_dict['is_initialized'] = True
print(f'example1 updated metadata: {fields(example1)[0].metadata}')
print(f'example2 updated metadata: {fields(example2)[0].metadata}')
# directly modifying the 'metadata' field also allowed
example3 = UsesExternalDict(0)
fields(example3)[0].metadata = other_external_metadata_dict
给予
example1 initial metadata: {'is_initialized': False}
example2 initial metadata: {'is_initialized': False}
example1 updated metadata: {'is_initialized': True}
example2 updated metadata: {'is_initialized': True}
example3 initial metadata: {'is_initialized': True}
example3 updated metadata: {'foo': 1}
但在大多数编程情况下,您最有可能想要这样做:
from dataclasses import dataclass, field, fields
@dataclass
class UsesInternalDict:
variable: int = field(metadata={'is_initialized': False})
example = UsesInternalDict(0)
print(f'example initial metadata: {fields(example)[0].metadata}')
fields(example)[0].metadata['is_initialized'] = True
print(f'example updated metadata: {fields(example)[0].metadata}')
刚给
example initial metadata: {'is_initialized': False}
Traceback (most recent call last):
File "/home/sinback/scrap.py", line 11, in <module>
fields(example)[0].metadata['is_initialized'] = True
TypeError: 'mappingproxy' object does not support item assignment
因为您正在尝试更新数据的实际只读部分class。
没有什么阻止您编写数据的方法class,它在运行时以其中一种方式手动更新其中一个字段的元数据部分我在第一个示例中进行了演示,例如:
@dataclass
class UsesExternalDict:
variable: int = field(metadata=external_metadata_dict)
def messwith(self):
self.__dataclass_fields__['variable'].metadata = other_external_metadata_dict
但是...它在风格上确实不符合数据classes 应该如何工作。即使抛开样式问题,它也是一个非常脆弱和粗略的解决方案 - 它利用了 Python 的一切都是参考语言功能,这导致程序员总是编写错误。如果您与其他人一起工作,这将完全导致混乱。
您可以探索的另一个选择是让您自己跟踪的字段成为它自己的 class,它自己跟踪该元数据。对我来说,这对你来说是最好的选择,但这取决于你。
我一直在 documentation 通读 python 数据类和其他网页。字段元数据是只读的,文档说:
It is not used at all by Data Classes and is provided as a third-party extension mechanism
我对第三方扩展如何使用“只读映射中的值”感到困惑。这看起来像是以前会进入软件文档的内容?
我的目的是装饰我的字段,以便我知道是否计算了特定值(字段的一部分),我认为这不是通过元数据可以实现的,对吗?
有些图书馆确实利用了元数据。例如,marshmallow 是一个非常流行的 dataclass 验证库,它允许您安装自定义验证器方法和一些其他的东西,方法是在您自己定义的 dataclass 中使用元数据挂钩。我想其他想要扩展 dataclasses 可用性的库也可以利用它。
是的,您的猜测是您不想/不能使用元数据来跟踪某个字段是否已计算,这对我来说是正确的。我认为你可以做一些 hack 来完成你想做的事情,但听起来你想要一个 class 比 dataclasses 及其字段的元数据功能更有状态“应该是。
由于映射代理是只读的,因此在实例化数据时首次创建它后,您无法对其进行更新class。解决元数据字段的只读限制的最灵活方法是让元数据字段本身指向 dataclass 实例本身范围之外的内容。在这种情况下,只读包装器围绕着您指向的内容,而不是内容中的内容。或者,您也可以在运行时自己更新 class 的整个元数据字段(这是允许的,因为元数据的内容是只读的,而不是元数据字段本身)。 但是,如果您更匿名地创建它,您将无法在创建时间后更改元数据字段的内容。
例如:
from dataclasses import dataclass, field, fields
external_metadata_dict = {'is_initialized': False}
other_external_metadata_dict = {'foo': 1}
@dataclass
class UsesExternalDict:
variable: int = field(metadata=external_metadata_dict)
example1 = UsesExternalDict(0)
print(f'example1 initial metadata: {fields(example1)[0].metadata}')
example2 = UsesExternalDict(0)
print(f'example2 initial metadata: {fields(example2)[0].metadata}')
# update the thing example1 and example2 both point to, even though their metadata is in a read-only wrapper
external_metadata_dict['is_initialized'] = True
print(f'example1 updated metadata: {fields(example1)[0].metadata}')
print(f'example2 updated metadata: {fields(example2)[0].metadata}')
# directly modifying the 'metadata' field also allowed
example3 = UsesExternalDict(0)
fields(example3)[0].metadata = other_external_metadata_dict
给予
example1 initial metadata: {'is_initialized': False}
example2 initial metadata: {'is_initialized': False}
example1 updated metadata: {'is_initialized': True}
example2 updated metadata: {'is_initialized': True}
example3 initial metadata: {'is_initialized': True}
example3 updated metadata: {'foo': 1}
但在大多数编程情况下,您最有可能想要这样做:
from dataclasses import dataclass, field, fields
@dataclass
class UsesInternalDict:
variable: int = field(metadata={'is_initialized': False})
example = UsesInternalDict(0)
print(f'example initial metadata: {fields(example)[0].metadata}')
fields(example)[0].metadata['is_initialized'] = True
print(f'example updated metadata: {fields(example)[0].metadata}')
刚给
example initial metadata: {'is_initialized': False}
Traceback (most recent call last):
File "/home/sinback/scrap.py", line 11, in <module>
fields(example)[0].metadata['is_initialized'] = True
TypeError: 'mappingproxy' object does not support item assignment
因为您正在尝试更新数据的实际只读部分class。
没有什么阻止您编写数据的方法class,它在运行时以其中一种方式手动更新其中一个字段的元数据部分我在第一个示例中进行了演示,例如:
@dataclass
class UsesExternalDict:
variable: int = field(metadata=external_metadata_dict)
def messwith(self):
self.__dataclass_fields__['variable'].metadata = other_external_metadata_dict
但是...它在风格上确实不符合数据classes 应该如何工作。即使抛开样式问题,它也是一个非常脆弱和粗略的解决方案 - 它利用了 Python 的一切都是参考语言功能,这导致程序员总是编写错误。如果您与其他人一起工作,这将完全导致混乱。
您可以探索的另一个选择是让您自己跟踪的字段成为它自己的 class,它自己跟踪该元数据。对我来说,这对你来说是最好的选择,但这取决于你。