在Python 3.x中是否可以进行类型化的隐式转换(强制转换)?
作者:互联网
是否可以在Python 3.6中实现自定义的自动/隐式转换(也称为强制转换),而不会使mypy和其他静态分析器感到难过?一个示例是def(foo:A),并给出def b_to_a(b:B)-> A,有没有一种方法可以代替foo(b_to_a(some_b))来写foo(some_b)(其中some_b:B)?
我认为在Python的动态特性中肯定有一些好的方法(例如,将成员添加到包含转换器的类中),甚至将此类转换器附加到函数对象本身,以便它可以处理选定类型的转换,但是我目前对Python类型的理解使我感到无法满足mypy之类的要求.
进行比较,请参阅Scala的implicit conversions.
解决方法:
这是我想到的此功能的实现.对于已知的“隐式”转换,我们保留了single-dispatch个转换器的字典.我们使用@implicit装饰器为此添加了转换器.
然后,我们有一个@coerce装饰器,可以在运行时检查功能注释,获取适当的转换器并应用转换.下面是框架:
from functools import wraps, singledispatch
from inspect import signature
from collections import OrderedDict
converters = {}
def implicit(func):
ret = func.__annotations__.get('return', None)
if not ret or len(func.__annotations__) != 2:
raise ValueError("Function not annotated properly or too many params")
if ret not in converters:
@singledispatch
def default(arg):
raise ValueError("No such converter {} -> {}".format(type(arg).__name__, ret.__name__))
converters[ret] = default
else:
default = converters[ret]
t = next(v for k, v in func.__annotations__.items() if k != 'return')
default.register(t)(func)
return wraps(func)(default)
def convert(val, t):
if isinstance(val, t):
return t
else:
return converters[t](val)
def coerce(func):
@wraps(func)
def wrapper(*args, **kwargs):
sig = signature(func)
bound = sig.bind(*args, **kwargs)
bound.apply_defaults()
bound.arguments = OrderedDict(
(param, convert(val, sig.parameters[param].annotation))
for param, val in bound.arguments.items())
return func(*bound.args, **bound.kwargs)
return wrapper
还有一个例子:
from typing import Tuple, Type
@implicit
def str_to_int(a: str) -> int:
return int(a)
@implicit
def float_to_int(a: float) -> int:
return int(a)
@coerce
def make_ints(a: int, b: int) -> Tuple[Type, Type]:
return (type(a), type(b))
print(make_ints("20", 5.0))
# (<class 'int'>, <class 'int'>)
标签:python-3-x,mypy,python 来源: https://codeday.me/bug/20191025/1926114.html