通用工厂方法的类型提示

2023-12-23

我很好奇是否可以通过 Python 中的类型参数推断泛型类型(用于类型提示)。

例如,考虑一个(相当愚蠢的)工厂方法:

from typing import TypeVar, Type

T = TypeVar('T')

class Test1(object):
    def test1(self):
        pass

class Test2(object):
    def test2(self):
        pass

# Is the type hinting correct here?
def create( t: Type[T] ) -> T:
    if t == Test1:
        return Test1()
    elif t == Test2:
        return Test2()
    else:
        raise ValueError()

instance1 = create( Test1 )
instance2 = create( Test2 )

Visual Studio 2017 和 intellij Ultimate 2018 似乎都没有在这里选择正确的实例 1 和实例 2 类型,至少在智能感知方面是这样。 我很好奇我的用法是否错误,或者 IDE 是否还不支持。

Thanks


您的类型签名非常好,您的 IDE 应该报告这一点instance and instance2属于类型Test1 and Test2分别。事实上,如果您尝试运行代码,您将得到的输出mypy http://mypy-lang.org/。 (要揭示 mypy 认为您的类型是什么,请尝试暂时添加reveal_locals()在运行 mypy 之前将伪函数添加到代码底部。)


然而,实际情况body您的代码实际上在技术上也不健全!代码的调用者可以传入一个自定义对象,该对象决定始终认为自己等于一切。例如:

from typing import TypeVar, Type

class ForceAlwaysEqual(type):
    def __new__(cls, name, bases, dct):
        return super().__new__(cls, name, bases, dct)

    def __eq__(self, other) -> bool:
        return True

class Hijacked(metaclass=ForceAlwaysEqual): pass

class Test1: pass

class Test2: pass

T = TypeVar('T')

def create(t: Type[T]) -> T:
    if t == Test1:
        return Test1()
    elif t == Test2:
        return Test2()
    else:
        raise ValueError()


mystery = create(Hijacked)
print(type(mystery))

如果您尝试在 Python 中运行此代码,我们将打印出Test1最后:调用create不会抛出 ValueError!

这里基本上发生的是我添加了一个自定义元类Hijacked所以这样做Hijacked == blah将始终返回 True。这会导致 create (t == Test1) 恰好为 true,因此我们返回 Test1,这违反了函数的签名。

因此,如果您的 IDE 也没有指示任何问题body你的create函数,这实际上在技术上是他们的另一个错误。

(这里更普遍的教训是,在 Python 中,不幸的是,类型检查器很难从相等性检查中推断出大部分内容,因为它们可以随时被重新定义以执行任何数量的任意废话。)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通用工厂方法的类型提示 的相关文章

随机推荐