python中运算种类有哪些_python – mypy中的计算类型

旁白:这个问题的标题并不理想.我想要做的事情可以通过计算类型实现,也可以通过其他方式实现.

我正在编写一些代码来验证并有时将动态类型化的JSON数据转换为静态Python类型.以下是一些功能:

def from_str(x: Any) -> str:

assert isinstance(x, str)

return x

def from_int(x: Any) -> int:

assert isinstance(x, int)

return x

def from_list(f: Callable[[Any], T], x: Any) -> List[T]:

assert isinstance(x, list)

return [f(y) for y in x]

这些工作很棒.我也希望能够将它们组合起来转换联合类型.理想情况下是这样的:

union = from_union([from_str, from_int], json)

问题是如何键入from_union函数.我的第一个方法是:

def from_union(fs: Iterable[Callable[[Any], T]], x: Any) -> T:

for f in fs:

try:

return f(x)

except AssertionError:

pass

assert False

从技术上讲,这是正确的.如果我们用Union替换Union [str,int],则上面的表达式被正确输入,因为from_str,由于返回一个str也返回一个Union [str,int](str类型的任何值都是Union类型的值[str] ,INT]).但是,mypy不想做这个替换:

test/fixtures/python/quicktype.py:59: error: Argument 1 to "from_union" has incompatible type "List[Callable[[Any], object]]"; expected "Iterable[Callable[[Any], ]]"

它似乎是对象而不是推断Union [str,int].

理想情况下,我想给from_union提供的类型是这样的

def from_union(fs: Iterable[Union[[Callable[[Any], S], Callable[[Any], T], ...]], x: Any) -> Union[S, T, ...]):

Python的类型不支持这一点.另一种选择是能够指定一个函数,该函数可以从特定调用的实际返回类型计算fs的类型,或者反过来.有可能吗?有没有其他选择可以做到这一点,而不必诉诸演员?

最佳答案 正如您所推断的那样,遗憾的是,这不是可以在Python的类型系统中表达的东西.最好的可用解决方法(与Typeshed用于键入内置,如map,filter和zip的解决方法相同)是滥用重载,如下所示:

from typing import Iterable, Callable, Any, Union, TypeVar, overload, List

T1 = TypeVar('T1')

T2 = TypeVar('T2')

T3 = TypeVar('T3')

# Note: the two underscores tell mypy that the argument is positional-only

# and that doing things like `from_union(blob, f1=from_str)` is not legal

@overload

def from_union(x: Any,

__f1: Callable[[Any], T1],

) -> T1: ...

@overload

def from_union(x: Any,

__f1: Callable[[Any], T1],

__f2: Callable[[Any], T2],

) -> Union[T1, T2]: ...

@overload

def from_union(x: Any,

__f1: Callable[[Any], T1],

__f2: Callable[[Any], T2],

__f3: Callable[[Any], T3],

) -> Union[T1, T2, T3]: ...

# The fallback: give up on the remaining callables

@overload

def from_union(x: Any,

__f1: Callable[[Any], T1],

__f2: Callable[[Any], T2],

__f3: Callable[[Any], T3],

*fs: Callable[[Any], Any]

) -> Union[T1, T2, T3, Any]: ...

def from_union(x: Any, *fs: Callable[[Any], Any]) -> Any:

for f in fs:

try:

return f(x)

except AssertionError:

pass

assert False

这个函数基本上做的是硬代码,支持最多三个callables,并且如果你再尝试传入则放弃.当然,为了支持接受更多的callables,增加一些重载.

这个新函数的API稍有改变:它需要像这样调用:

my_union = from_union(json_blob, from_str, from_int)

如果你想要一个与原版更相似的API并且首先使用函数,你需要将x转换为仅关键字参数(例如from_union(* fs:Callable [[Any],Any],*, x:Any) – > Any)或将函数存储在元组中,如下所示:

@overload

def from_union(fs: Tuple[Callable[[Any], T1]], x: Any) -> T1: ...

@overload

def from_union(fs: Tuple[Callable[[Any], T1], Callable[[Any], T2]], x: Any) -> Union[T1, T2]: ...

# etc...

# The final fallback: have the tuple accept any number of callables

@overload

def from_union(fs: Tuple[Callable[[Any], Any], ...], x: Any) -> Any: ...

def from_union(fs: Tuple[Callable[[Any], Any], ...], x: Any) -> Any:

for f in fs:

try:

return f(x)

except AssertionError:

pass

assert False

在这两种情况下,如果用户传入太多args,则“回退”将在输出中引入一些动态.如果您不喜欢这样,请删除最终的后备.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值