[英]Python: How to check what types are in defined types.UnionType?
我正在使用 Python 3.11,我需要檢測可選的class屬性是否為 Enum 類型(即 Enum 的子類類型)。
使用typing.get_type_hints()
我可以獲得類型提示作為字典,但是如何檢查字段的類型是否是可選的枚舉(子類)? 如果我能得到任何可選字段的類型就更好了,不管它是Optional[str]
、 Optional[int]
、 Optional[Class_X]
等等。
from typing import Optional, get_type_hints
from enum import IntEnum, Enum
class TestEnum(IntEnum):
foo = 1
bar = 2
class Foo():
opt_enum : TestEnum | None = None
types = get_type_hints(Foo)['opt_enum']
(ipython)
In [4]: Optional[TestEnum] == types
Out[4]: True
(是的,這些都是絕望的嘗試)
In [6]: Optional[IntEnum] == types
Out[6]: False
和
In [11]: issubclass(Enum, types)
Out[11]: False
和
In [12]: issubclass(types, Enum)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In [12], line 1
----> 1 issubclass(types, Enum)
TypeError: issubclass() arg 1 must be a class
和
In [13]: issubclass(types, Optional[Enum])
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In [13], line 1
----> 1 issubclass(types, Optional[Enum])
File /usr/lib/python3.10/typing.py:1264, in _UnionGenericAlias.__subclasscheck__(self, cls)
1262 def __subclasscheck__(self, cls):
1263 for arg in self.__args__:
-> 1264 if issubclass(cls, arg):
1265 return True
TypeError: issubclass() arg 1 must be a class
和
In [7]: IntEnum in types
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In [7], line 1
----> 1 IntEnum in types
TypeError: argument of type 'types.UnionType' is not iterable
我有幾種情況,我從 csv 文件導入數據並從每一行創建 class 的對象。 csv.DictReader()
返回一個dict[str, str]
,我需要在嘗試創建 object 之前修復字段的類型。但是,一些 object 字段是Optional[int]
, Optional[bool]
, Optional[EnumX]
或Optional[ClassX]
。 我有幾個類繼承了我的CSVImportable()
類/接口。 我想在CSVImportable()
class 中實現一次邏輯,而不是在每個子類中以字段感知方式編寫大致相同的代碼。 這個CSVImportable._field_type_updater()
應該:
Optional[ClassX]
字段當然,我也感謝更好的設計:-)
當您處理參數化類型(通用或特殊類型,如typing.Optional
)時,您可以通過get_args
/ get_origin
檢查它。
這樣做你會看到T | S
T | S
的實現方式與typing.Union[T, S]
略有不同。 前者的起源是types.UnionType
,而后者的起源是typing.Union
。 不幸的是,這意味着要涵蓋這兩種變體,我們需要進行兩次不同的檢查。
from types import UnionType
from typing import Union, get_origin
def is_union(t: object) -> bool:
origin = get_origin(t)
return origin is Union or origin is UnionType
使用typing.Optional
只是在引擎蓋下使用typing.Union
,所以起源是一樣的。 這是一個工作演示:
from enum import IntEnum
from types import UnionType
from typing import Optional, get_type_hints, get_args, get_origin, Union
class TestEnum(IntEnum):
foo = 1
bar = 2
class Foo:
opt_enum1: TestEnum | None = None
opt_enum2: Optional[TestEnum] = None
opt_enum3: TestEnum
opt4: str
def is_union(t: object) -> bool:
origin = get_origin(t)
return origin is Union or origin is UnionType
if __name__ == "__main__":
for name, type_ in get_type_hints(Foo).items():
if type_ is TestEnum or is_union(type_) and TestEnum in get_args(type_):
print(name, "accepts TestEnum")
Output:
opt_enum1 accepts TestEnum opt_enum2 accepts TestEnum opt_enum3 accepts TestEnum
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.