簡體   English   中英

python 數據類中使用的字段元數據是什么

[英]what is field metadata used for in python dataclasses

我一直在閱讀 python 數據類和其他 web 頁面的文檔 字段元數據是只讀的,文檔說:

Data Classes 根本不使用它,並作為第三方擴展機制提供

我對第三方擴展如何使用“來自只讀映射的值”感到困惑。 這看起來像是以前將 go 放入軟件文檔中的東西?

我的意圖是裝飾我的字段,以便我知道是否計算了特定值(字段的一部分),我認為這不是可以通過元數據來實現的,對吧?

一些圖書館確實利用了元數據。 例如,marshmallow 是一個非常流行的數據類驗證庫,它允許您通過在您自己定義的數據類中使用元數據掛鈎來安裝自定義驗證器方法和其他一些東西。 我想其他想要擴展數據類可用性的庫也可以利用它。

是的,您的猜測是您不想/不能使用元數據來跟蹤字段是否被計算對我來說聽起來正確。 我認為您可以采取一些技巧來完成您想做的事情,但聽起來您想要一個 class 比數據類更有狀態,並且其字段的元數據功能“應該”是。

由於映射代理是只讀的,因此在實例化數據類時首次創建它之后,您沒有太多更新它的能力。 解決元數據字段只讀限制的最靈活方法是讓元數據字段本身指向數據類實例本身的 scope 之外的內容。 在這種情況下,只讀包裝器圍繞着您所指向的事物,而不是事物中的內容。 或者,您也可以在運行時自己更新該 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

因為您正在嘗試更新數據類的實際只讀部分。

沒有什么能阻止您編寫數據類的方法,該方法在運行時以我在第一個示例中演示的一種方式手動更新其一個字段的元數據部分,例如:

@dataclass
class UsesExternalDict:
    variable: int = field(metadata=external_metadata_dict)

    def messwith(self):
        self.__dataclass_fields__['variable'].metadata = other_external_metadata_dict

但是......它在風格上確實不符合數據類的工作方式。 即使撇開風格問題,它也是一個非常脆弱和粗略的解決方案——它利用了 Python 的一切都是參考語言的特性,這會導致程序員一直編寫錯誤。 如果您與其他人一起工作,這將完全導致混亂。

您可以探索的另一個選擇是讓您自己跟蹤的字段是它自己的 class ,它自己跟蹤該元數據。 對我來說,這對你來說是最好的選擇,但這取決於你。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM