编程语言
首页 > 编程语言> > 在Python 3.x中是否可以进行类型化的隐式转换(强制转换)?

在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