簡體   English   中英

導入注釋時檢查字段是否為數據類不起作用

[英]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 AB之后定義的情況。

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.

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