組み込みフック¶
cattrs コンバーターには、 多数の構造化/非構造化フックが組み込まれています。 常にそうであるように、 複雑なフックはより単純なものと組み合わされます。
プリミティブ値¶
int 、 float 、 str 、 bytes¶
構造化する際、 これらの型のいずれかを使用して、 オブジェクトをその型に強制します。
>>> cattrs.structure(1, str)
'1'
>>> cattrs.structure("1", float)
1.0
変換が不可能な場合、 予期される例外が伝播されます。 特定の例外は、 直接強制変換しようとした場合と同じです。
>>> cattrs.structure("not-an-int", int)
Traceback (most recent call last):
...
ValueError: invalid literal for int() with base 10: 'not-an-int'
強制は、 パフォーマンスと互換性の理由から実行されます。 代わりに純粋な検証が必要な場合は、 これらのフックのいずれかをオーバーライドできます。
>>> c = Converter()
>>> @c.register_structure_hook
... def validate(value, type) -> int:
... if not isinstance(value, type):
... raise ValueError(f'{value!r} not an instance of {type}')
>>> c.structure("1", int)
Traceback (most recent call last):
...
ValueError: '1' not an instance of <class 'int'>
非構造化する場合、 これらの型は変更されずに渡されます。
列挙型¶
列挙型は、 それらの値によって構造化され、 それらの値に非構造化されます。 これは、 タプルのような複雑な値でも機能します。
>>> @unique
... class CatBreed(Enum):
... SIAMESE = "siamese"
... MAINE_COON = "maine_coon"
... SACRED_BIRMAN = "birman"
>>> cattrs.structure("siamese", CatBreed)
<CatBreed.SIAMESE: 'siamese'>
>>> cattrs.unstructure(CatBreed.SIAMESE)
'siamese'
繰り返しになりますが、 エラーが発生した場合、 予期される例外が発生します。
pathlib.Path¶
pathlib.Path オブジェクトは、 それらの文字列値を使用して構造化され、 それらの文字列値に非構造化されます。
>>> from pathlib import Path
>>> cattrs.structure("/root", Path)
PosixPath('/root')
>>> cattrs.unstructure(Path("/root"))
'/root'
変換が不可能な場合、 結果の例外が伝播されます。
Added in version 23.1.0.
attrs クラスとデータクラス¶
attrs クラスとデータクラスは、 デフォルトで動作します。 フィールドには型注釈が必要です (静的型チェックが使用されていない場合でも)。 そうでない場合、 それらは typing.Any として扱われます。
構造化する場合、 マッピング d とクラス A が与えられた場合、 cattrs は d をアンパックして A をインスタンス化します。
>>> @define
... class A:
... a: int
... b: int
>>> cattrs.structure({'a': 1, 'b': '2'}, A)
A(a=1, b=2)
タプルは、 structure_attrs_fromtuple() ( attrs.astuple および BaseConverter.unstructure_attrs_astuple() の反対の意味での fromtuple ) を使用してクラスに構造化できます。
>>> @define
... class A:
... a: str
... b: int
>>> cattrs.structure_attrs_fromtuple(['string', '2'], A)
A(a='string', b=2)
タプルからのロードは、 unstruct_strat=cattr.UnstructureStrategy.AS_TUPLE を持つ新しい Converter を作成することでデフォルトにできます。
>>> converter = cattrs.Converter(unstruct_strat=cattr.UnstructureStrategy.AS_TUPLE)
>>> @define
... class A:
... a: str
... b: int
>>> converter.structure(['string', '2'], A)
A(a='string', b=2)
タプルからの構造化は、 通常の方法でフックを登録することによってのみ、 特定のクラスのデフォルトにすることもできます。
>>> converter = cattrs.Converter()
>>> @define
... class A:
... a: str
... b: int
>>> converter.register_structure_hook(A, converter.structure_attrs_fromtuple)
ジェネリクス¶
ジェネリック attrs クラスとデータクラスは、 typing.Generic と PEP 695 の両方を使用して完全にサポートされています。
>>> @define
... class A[T]:
... a: T
>>> cattrs.structure({"a": "1"}, A[int])
A(a=1)
属性の型とコンバーターの使用¶
デフォルトでは、 structure() は、 register_structure_hook() を使用して登録されたフックを使用して、 値を属性の型に変換し、 field を持つ属性に登録されたコンバーターの呼び出しに進みます。
>>> from ipaddress import IPv4Address, ip_address
>>> converter = cattrs.Converter()
# Note: register_structure_hook has not been called, so this will fallback to 'ip_address'
>>> @define
... class A:
... a: IPv4Address = field(converter=ip_address)
>>> converter.structure({'a': '127.0.0.1'}, A)
A(a=IPv4Address('127.0.0.1'))
優先度は、 register_structure_hook() で登録されたフックに引き続き与えられますが、 prefer_attrib_converters を True に設定することで、 この優先度を反転させることができます。
>>> converter = cattrs.Converter(prefer_attrib_converters=True)
>>> @define
... class A:
... a: int = field(converter=lambda v: int(v) + 5)
>>> converter.structure({'a': '10'}, A)
A(a=15)
参考
attrs クラスまたはデータクラスが継承を使用し、 そのため 1 つまたは複数のサブクラスを持つ場合、 サブクラスを含める 戦略を使用することで、 正確なサブタイプに自動的に構造化できます。
ユニオン¶
NoneType と単一の他の型 (オプションとしても知られている) のユニオンは、 特別なケース によってサポートされています。
自動曖昧性解消¶
cattrs には、 attrs クラスのユニオンを自動的に処理するための意見のある戦略が含まれています。 詳細については、 Default Union Strategy を参照してください。
これらの種類のユニオンを非構造化する場合、 各ユニオンメンバーは、 その型のフックに従って非構造化されます。
単純型のユニオン¶
cattrs には Union Passthrough が付属しており、 コンバーターは多くのプリミティブ型とリテラルのユニオンを構造化できます。 この戦略は任意のコンバーターに適用でき、 基になるプロトコルに従って、 すべての preconf コンバーターに事前に適用されます。
特別な型付け形式¶
typing.Any¶
構造化する場合、 構造化しているオブジェクトに変換を適用しないようにするには、 typing.Any を使用します。 それは単に渡されます。
>>> cattrs.structure(1, Any)
1
>>> d = {1: 1}
>>> cattrs.structure(d, Any) is d
True
非構造化する場合、 typing.Any は、 値を実行時クラスに従って非構造化します。
バージョン 24.1.0 で変更: 以前は、 Any の非構造化ルールは十分に指定されておらず、 一貫性のない動作につながっていました。
バージョン 24.1.0 で変更: typing_extensions.Any もサポートされるようになりました。
typing.Literal¶
構造化する場合、 PEP 586 リテラルは、 許可された値のセットに含まれていることが検証されます。
>>> from typing import Literal
>>> cattrs.structure(1, Literal[1, 2])
1
非構造化する場合、 リテラルは渡されます。
Added in version 1.7.0.
typing.NamedTuple¶
型ヒント付きの名前付きタプル ( typing.NamedTuple から作成) がサポートされています。 名前付きタプルは、 デフォルトでタプルまたはリストを使用して構造化/非構造化されます。
cattrs.cols モジュールには、 代わりに辞書を使用して名前付きタプルを構造化/非構造化するためのフックファクトリが含まれています。 詳細については、 こちらをご覧ください 。
Added in version 24.1.0.
typing.Final¶
PEP 591 Final 属性型 ( Final[int] ) がサポートされており、 内部型 (この場合は int ) に従って処理されます。
Added in version 23.1.0.
typing.Annotated¶
PEP 593 アノテーション ( typing.Annotated[type, ...] ) がサポートされており、 アノテーション付きの型に存在する最初の型を使用して処理されます。
Added in version 1.4.0.
型エイリアス¶
型エイリアス は、 Python 3.12 以降でサポートされており、 基になる型のルールに従って処理されます。 それらのフックは、 Predicate Hooks を使用してオーバーライドすることもできます。
警告
typing.TypeAlias を使用する型エイリアスは、 実行時にそれらを基になる型と区別する方法がないため、 サポートされていません。
>>> from datetime import datetime, UTC
>>> type IsoDate = datetime
>>> converter = cattrs.Converter()
>>> converter.register_structure_hook_func(
... lambda t: t is IsoDate, lambda v, _: datetime.fromisoformat(v)
... )
>>> converter.register_unstructure_hook_func(
... lambda t: t is IsoDate, lambda v: v.isoformat()
... )
>>> converter.structure("2022-01-01", IsoDate)
datetime.datetime(2022, 1, 1, 0, 0)
>>> converter.unstructure(datetime.now(UTC), unstructure_as=IsoDate)
'2023-11-20T23:10:46.728394+00:00'
Added in version 24.1.0.
typing.NewType¶
NewTypes がサポートされており、 基になる型のルールに従って処理されます。 それらのフックは、 Converter.register_structure_hook() を使用してオーバーライドすることもできます。
>>> from typing import NewType
>>> from datetime import datetime
>>> IsoDate = NewType("IsoDate", datetime)
>>> converter = cattrs.Converter()
>>> converter.register_structure_hook(IsoDate, lambda v, _: datetime.fromisoformat(v))
>>> converter.structure("2022-01-01", IsoDate)
datetime.datetime(2022, 1, 1, 0, 0)
Added in version 22.2.0.
typing.Protocol¶
プロトコル は、 デフォルトで構造化できず、 カスタムフックが必要です。
プロトコルは、 値の実際の実行時型に従って非構造化されます。
Added in version 1.9.0.