“输入”和“从”接口:在打字方面苦苦挣扎。类型的协方差

Into and From interfaces: struggling with typing.Type's covariance

提问人:joel 提问时间:10/12/2019 最后编辑:joel 更新时间:5/17/2020 访问量:229

问:

我正在尝试实现一个用于类型之间转换的接口,但我正在努力使其保持一致,因为是协变的typing.Type

U = TypeVar('U')


class Into(Protocol[U]):
    @abstractmethod
    def into(self, t: Type[U]) -> U:
        pass

这些文档给出了一个类似的例子,但有一个关键的区别

class User: ...
class BasicUser(User): ...
class ProUser(User): ...
class TeamUser(User): ...

def make_new_user(user_class: Type[User]) -> User:
    return user_class()

他们说类型检查器应该检查所有子类是否应该实现一个具有有效签名的构造函数,以便像这样实例化。我的用例是不同的,因为我可能没有构造新类型,只是返回一个预先存在的类型。说我愿意User

class X: pass

class Wrapper:
    def __init__(self, x: X):
        self._x = x

    def into(self, t: Type[X]) -> X:
        return self._x

一切正常,直到有人子类X

w = Wrapper(X())
...
class XX(X): pass
x: XX = w.into(XX)

mypy 的 RHS 很好,因为 cos 是协变的,但显然 API 已损坏,因为 an 不是 .如果不是协变,这不会是一个问题:RHS 不会进行类型检查,直到更新为支持 .TypeXXXTypeWrapperXX

我的问题是:有没有办法实现这一点(或类似的东西),给定的协方差?Type

上下文

我想用它来将一个类型转换为多个其他类型,显式指定所需的类型,而不仅仅是 ,等等。我希望用 or 来做到这一点。我在那里也遇到了困难。into_Xinto_YTypeVaroverload

这是受 rust 的启发,其中是类型参数而不是函数参数。Intot: Type[U]

Python 协方差 类型提示

评论

0赞 chepner 5/17/2020
into根本没有使用它的参数,所以继承或协方差不是你的问题。t
0赞 joel 5/17/2020
@chepner我希望它使用参数,如果我正在实现并且用于单个类Into[X]Into[Y]
0赞 joel 5/17/2020
撇开这一点不谈,你能详细说明为什么不使用参数意味着协方差不是问题吗?
0赞 Kate Melnykova 5/17/2020
@joelb,您能介绍一下代码的简单用例吗?我不完全明白你在做什么。Wrapper 是否应该通过添加方法来扩展其输入的功能?什么返回 -- 其输入的实例或实例?是要调用并获取存储在 中的值,还是要修改以更改其属性的类型?另外,是否要调用 ,-- 即相同的值转换为不同的类型?Wrapper()Wrapperw.into(int)www.into(List[str])w.into(List[int])
1赞 chepner 5/17/2020
@joelb 它暗示函数应该返回一个 ,如果像这样的工具检测到你试图返回某些东西,它会引发错误,但类型提示在运行时不起作用:可以返回任何内容。Xmypyinto

答:

-2赞 Kate Melnykova 5/17/2020 #1

eval解决了问题。

class Wrapper:
    def __init__(self, x: X):
        self._x = x

    def into(self, t: Type[X]) -> X:
        return eval(f'{t}({self._x})')

评论

1赞 chepner 5/17/2020
你根本不需要; 会做同样的事情(假设可以用来首先使 ,或者更确切地说是 的结果)。evalreturn t(self._x)ttself._xstr(self._x)
0赞 Kate Melnykova 5/17/2020
我以为这是一个字符串。t
1赞 joel 5/17/2020
t不会是字符串。它是一种类型,例如如果是,将是self._x1tint
0赞 Kate Melnykova 5/17/2020
我的解决方案仍然有效,@chepner的解决方案更简单,也有效。我认为问题已经解决。
0赞 joel 5/17/2020
正如 Chepner 所指出的,这只有在你能从另一个类似中构造一个时才有效,而这通常不能,你不能XXX(x)