如何解决在联合中处理带值的参数的 Pythonic 方法
在下面的代码中,print_pos
接受一个参数,它可以是
三种不同的类型。
from typing import List,Tuple,Union
pos_t = Tuple[int,int]
anchor_t = Tuple[str,str]
anchor_pos_t = Tuple[anchor_t,pos_t]
def print_pos(
pos: Union[
pos_t,anchor_pos_t,List[Union[pos_t,anchor_pos_t]]
]
) -> None:
if isinstance(pos,tuple) and isinstance(pos[0],int):
print('xy =',pos)
elif isinstance(pos,tuple):
print('anchor =',pos[0])
print('xy =',pos[1])
elif isinstance(pos,list):
print('[')
for p in pos:
print_pos(p)
print(']')
else:
raise ValueError('invalid pos')
print_pos((0,100))
print_pos((('right','bottom'),(0,100)))
print_pos([
(0,100),(('right',100))
])
现在,我使用 isinstance
来检查不同的可能性
对于 pos
的类型,但我发现代码相当笨拙。有没有
更方便/优雅的方式来做到这一点?特别是有没有意思
重用我在类型检查中定义的类型 (pos_t
,anchor_t
,anchor_pos_t
)?
解决方法
您可以使用 typeguard
库在运行时检查变量类型。
该库主要用于运行时类型验证,而不是条件类型检查,因此需要定义一个额外的 is_type
函数以满足您的需求。
不幸的是,额外的类型转换对于防止类型检查器错误也是必要的。
from typing import Any,List,Tuple,Union,cast
from typeguard import check_type
pos_t = Tuple[int,int]
anchor_t = Tuple[str,str]
anchor_pos_t = Tuple[anchor_t,pos_t]
def is_type(value: Any,expected_type: Any) -> bool:
"""
Return whether the given value is of the expected type or not.
"""
try:
check_type('<blank>',value,expected_type)
return True
except TypeError:
return False
def print_pos(
pos: Union[pos_t,anchor_pos_t,List[Union[pos_t,anchor_pos_t]]]
) -> None:
if is_type(pos,pos_t):
pos = cast(pos_t,pos)
print('xy =',pos)
elif is_type(pos,anchor_pos_t):
pos = cast(anchor_pos_t,pos)
print('anchor =',pos[0])
print('xy =',pos[1])
elif is_type(pos,anchor_pos_t]]):
pos = cast(List[Union[pos_t,anchor_pos_t]],pos)
print('[')
for p in pos:
print_pos(p)
print(']')
else:
raise ValueError('invalid pos')
print_pos((0,100))
print_pos((('right','bottom'),(0,100)))
print_pos([(0,100),(('right',100))])
这不是最干净的解决方案,但它有效。
如果可能,我建议对类使用更面向对象的方法,以消除对联合类型的需要。
,这还不适用于任何当前的 python 版本,但 python 3.10(计划于 2021 年 10 月发布)将具有结构模式匹配。
这允许类似这样的事情,这可能稍微更具可读性:
from typing import List,Union
pos_t = Tuple[int,pos_t]
def print_pos(
pos: Union[
pos_t,anchor_pos_t]]
]
) -> None:
match pos:
# need to match this more specific case first,as tuple((x,y)) matches this as well
case tuple(((a,b),(x,y))):
print('anchor =',(a,b))
print('xy =',y))
case tuple((x,y)):
print('xy =',y))
case list(_):
print('[')
for p in pos:
print_pos(p)
print(']')
case _:
raise ValueError('invalid pos')
print_pos((0,100)))
print_pos([
(0,100))
])
这已经适用于 3.10.0a7 预发行版,尽管尚不支持 mypy。
结构模式匹配在某种意义上类似于序列解包
(a,y) = pos
但更强大。
描述结构模式匹配的三个 PEP:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。