Into 和 From 接口:与打字的斗争。Type 的协方差

Posted

技术标签:

【中文标题】Into 和 From 接口:与打字的斗争。Type 的协方差【英文标题】:Into and From interfaces: struggling with typing.Type's covariance 【发布时间】:2020-02-09 18:33:50 【问题描述】:

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

U = TypeVar('U')


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

docs 给出了一个类似的例子,但有一个关键的区别

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)

RHS 很好,因为 Type 是协变的,但显然 API 已损坏,因为 X 不是 XX。如果Type 不是协变的,这不会是一个问题:在Wrapper 更新为支持XX 之前,RHS 不会进行类型检查。

我的问题是:考虑到Type 的协方差,有什么方法可以实现这一点(或类似的东西)吗?

上下文

我想使用它来将一个类型转换为多个其他类型,明确指定所需的类型,而不仅仅是into_Xinto_Y 等。我希望使用TypeVaroverload 来执行此操作。我也有困难there。

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

【问题讨论】:

into 根本不使用其 t 参数,因此继承或协变不是您的问题。 @chepner 如果我为单个类实现 Into[X]Into[Y],我希望它使用参数 除此之外,您能否详细说明为什么不使用参数意味着协方差不是问题? @joelb,你能介绍一个简单的代码用例吗?我不完全明白你在做什么。 Wrapper 是否应该通过添加方法来扩展其输入的功能? Wrapper() 返回什么——Wrapper 的实例或其输入的实例?您是想调用w.into(int) 并获取存储在w 中的值,还是要修改w 使其属性改变其类型?另外,你想打电话给w.into(List[str])w.into(List[int])——即相同的值转换为不同的类型? @joelb 它提示该函数应该返回一个X,如果像mypy 这样的工具检测到你试图返回一些东西,它会引发一个错误,但是类型提示在运行时无效:into 可以返回任何东西。 【参考方案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)')

【讨论】:

你根本不需要evalreturn t(self._x) 会做同样的事情(首先假设t 可以用来从self._x 中生成t,或者更确切地说是str(self._x) 的结果)。 我假设t 是一个字符串。 t 不会是字符串。它是一种类型,例如如果self._x1t 将是int 我的解决方案仍然有效,@chepner 的解决方案更简单,也有效。我认为问题已经解决了。 正如 chepner 指出的那样,只有当你可以从另一个 X 中构造一个 X 时,这才有效,比如 X(x),一般来说,你不能

以上是关于Into 和 From 接口:与打字的斗争。Type 的协方差的主要内容,如果未能解决你的问题,请参考以下文章

select into from 与insert into select from区别

Select into 与 Insert into … select … from

SQLINSERT INTO SELECT语句与SELECT INTO FROM语句

select into from 和 insert into select的使用

自动匹配 INSERT INTO ... SELECT ... FROM 中的列

select into from和insert into select from两种表复制语句区别