[英]Checking if a field is a dataclass doesn't work when annotations are imported
from __future__ import annotations
from dataclasses import dataclass, is_dataclass, field, fields
@dataclass
class A:
a: int | None = None
b: int | None = None
@dataclass
class B:
a_obj: A = field(default_factory=A)
x: int = 0
y: int = 0
for f in fields(B):
print(is_dataclass(f.type)) # False for all
不是使用annotations
的唯一方法,我將不得不更改很多類型注釋以使用Optional[T]
而不是T | None
T | None
我檢查了 Python 3.10 中的數據類代碼,並且沒有任何預置可以使用字符串注釋,就像使用from __future__ import annotations
時發生的那樣。
這是因為字符串化注釋的想法只是在將它們用於 static 類型提示時是可以的。 數據類和較新的 Python 庫,例如 pydantic 實際上將注釋用於運行時目的 - 這一直是 PEP 563 的原因,它描述了這種字符串化效果,沒有被提升為 Python 3.10 中的默認行為。 649 被提出。
在這種情況下,您可以在將 class 傳遞給數據類裝飾器之前“重新水化”注釋,因為它不會這樣做。 -- 把它作為一個中間裝飾器,它應該可以工作:
def hydrate(cls):
cls.__annotations__ = typing.get_type_hints(cls)
return cls
接着:
from __future__ import annotations
...
@dataclass
@hydrate
class B:
a_obj: A = field(default_factory=A)
x: int = 0
y: int = 0
一種選擇是使用緩存 class 屬性的方法; 例如,這也有助於解決 class A
在B
之后定義的情況。
from __future__ import annotations
from dataclasses import dataclass, is_dataclass, field, fields, Field
from functools import cache
from typing import get_type_hints
def cached_class_attr(f):
return classmethod(property(cache(f)))
@dataclass
class B:
# using lambda because we can't use `A` directly, as it's not defined yet
a_obj: A = field(default_factory=lambda: A())
x: int = 0
y: int = 0
@cached_class_attr
def __true_annotations__(cls):
return get_type_hints(cls)
@cached_class_attr
def __fields__(cls):
ann_dict: dict = cls.__true_annotations__
cls_fields: tuple[Field, ...] = fields(cls)
for f in cls_fields:
f.type = ann_dict[f.name]
return cls_fields
@dataclass
class A:
a: int | None = None
b: int | None = None
for name, tp in B.__true_annotations__.items():
print(name, is_dataclass(tp))
Output:
a_obj True
x False
y False
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.