Rod*_*ino 8 python typing python-3.7
检查类中的字段是否正在打字的最佳方法是什么?可选?
示例代码:
from typing import Optional
import re
from dataclasses import dataclass, fields
@dataclass(frozen=True)
class TestClass:
required_field_1: str
required_field_2: int
optional_field: Optional[str]
def get_all_optional_fields(fields) -> list:
return [field.name for field in fields if __is_optional_field(field)]
def __is_optional_field(field) -> bool:
regex = '^typing.Union\[.*, NoneType\]$'
return re.match(regex, str(field.type)) is not None
print(get_all_optional_fields(fields(TestClass)))
Run Code Online (Sandbox Code Playgroud)
fields来自哪里dataclasses,我想列出所有Optional字段。我现在正在做的解决这个问题是使用基于字段名称的正则表达式,但我不喜欢这种方法。有更好的方法吗?
作为参考,Python的3.8(第一释放2019年10月)中加入get_origin并get_args起到将typing模块。
文档中的示例:
assert get_origin(Dict[str, int]) is dict
assert get_args(Dict[int, str]) == (int, str)
assert get_origin(Union[int, str]) is Union
assert get_args(Union[int, str]) == (int, str)
Run Code Online (Sandbox Code Playgroud)
这将允许:
def is_optional(field):
return typing.get_origin(field) is Union and \
type(None) in typing.get_args(field)
Run Code Online (Sandbox Code Playgroud)
对于较旧的 Python,这里有一些兼容性代码:
assert get_origin(Dict[str, int]) is dict
assert get_args(Dict[int, str]) == (int, str)
assert get_origin(Union[int, str]) is Union
assert get_args(Union[int, str]) == (int, str)
Run Code Online (Sandbox Code Playgroud)
注意:typing.Optional[x]是别名typing.Union[x, None]
现在,人们可以检查您输入字段批注的属性,以检查它是否像联盟[X,无]定义的:
你可以阅读它的属性__module__,__args__以及__origin__:
from typing import *
def print_meta_info(x):
print(x.__module__, x.__args__, x.__origin__)
x = Optional[int]
print_meta_info(x) # 'typing', (class Int,), typing.Union
x = Union[int, float]
print_meta_info(x) # 'typing', (class int, class float), typing.Union
x = Iterable[str]
print_meta_info(x) # 'typing', (class int,), typing.Iterable
Run Code Online (Sandbox Code Playgroud)
您需要执行以下步骤来定义您的检查器:
__module__,__args__并且__origin____module__必须设置为“打字”。如果不是,则注解不是typing 模块定义的对象__origin__ 值等于typing.Union__args__必须是包含 2 个项目的元组,其中第二个是类 NoneType ( type(None))
如果所有条件都评估为真,则您有 typing.Optional[x]
您可能还需要知道注释中的可选类是什么:
x = Optional[int].__args__[0]
print(x) # class int
Run Code Online (Sandbox Code Playgroud)
另一种方法(适用于 python 3.7 和 3.8)是中继 setUnion操作的工作原理:
union([x,y],[y])= union([x],[y]) = union(union([x],[y]),[x,y])
逻辑是Optional类型不能是Optional呃。虽然您无法直接知道 a 是否type可为空/可选,但与可选和其他(确切地说)Optional[type]相同。typetypeUnion[type,None]
所以,在我们的例子中:
Union[SomeType,None] == Union[Union[SomeType,None]]
Run Code Online (Sandbox Code Playgroud)
(第一个相当于Optional[SomeType],第二个相当于Optional[Optional[SomeType]]
这可以非常轻松地检查Optional值:
from dataclasses import dataclass, fields
from typing import Optional
@dataclass()
class DC:
x: Optional[str] = None
y: str = "s"
def get_optional_fields(cls):
fields_list = fields(cls)
return [
field.name
for field in fields_list if
field.type == Optional[field.type]
]
if __name__ == '__main__':
print(get_optional_fields(DC())) # ['x']
Run Code Online (Sandbox Code Playgroud)
Optional[X]相当于Union[X, None]. 所以你可以这样做,
import re
from typing import Optional
from dataclasses import dataclass, fields
@dataclass(frozen=True)
class TestClass:
required_field_1: str
required_field_2: int
optional_field: Optional[str]
def get_optional_fields(klass):
class_fields = fields(klass)
for field in class_fields:
if (
hasattr(field.type, "__args__")
and len(field.type.__args__) == 2
and field.type.__args__[-1] is type(None)
):
# Check if exactly two arguments exists and one of them are None type
yield field.name
print(list(get_optional_fields(TestClass)))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3995 次 |
| 最近记录: |