Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在python 3.5+;_Python_Python 3.x_Python 3.5_Type Hinting - Fatal编程技术网

在python 3.5+;

在python 3.5+;,python,python-3.x,python-3.5,type-hinting,Python,Python 3.x,Python 3.5,Type Hinting,假设我有以下课程: class Parent: def clone_self(self) -> 'Parent': clone = self.__class__() # Initialize clone here. return clone def clone_with_class(self, klass: Type['Parent']) -> 'Parent': clone = klass()

假设我有以下课程:

class Parent:
    def clone_self(self) -> 'Parent':
        clone = self.__class__()
        # Initialize clone here.
        return clone

    def clone_with_class(self, klass: Type['Parent']) -> 'Parent':
        clone = klass()
        # Initialize clone here.
        return clone

class Child(Parent):
    def child_method(self) -> None:
        pass
有没有办法让类型更具体一些?我希望能够说出这样的话:

child = Child()
clone = child.clone_self()
clone.child_method()

clone = child.clone_with_class(Child)
clone.child_method()
但是,正如所写的,这不会通过类型检查,因为克隆被认为是类型
父项
而不是
子项

我尝试使用
TypeVar
,但这似乎不起作用-至少在PyCharm中是这样,因为当我尝试调用构造函数时,它抱怨类型不可调用,可能是因为它涉及前向引用,PyCharm变得混乱

Entity = TypeVar('Entity', bound='Parent')
class Parent:
    def clone_self(self) -> ???:
        clone = self.__class__()
        # initialize clone here
        return clone

    def clone_with_class(self, klass: Type[Entity]) -> Entity:
        clone = klass()
        # initialize clone here
        return clone
对于
clone\u和\u class
的解决方案是否正确?也许PyCharm抱怨是不对的?否则,需要做什么来修复上述代码

这应该是
TypeVar('Entity',bind='Parent')
还是
TypeVar('Entity','Parent')

我发现的另一个解决方案,尽管看起来有点难看,是插入断言:

child = Child()
parent = Parent()

clone = child.clone_self()
clone.child_method()  # should work

clone = child.clone_with_class(Child)
clone.child_method()  # should work

clone = parent.clone_with_class(Child)
clone.child_method()  # should work

clone2 = parent.clone_self()
clone2.child_method()  # should be an error

clone2 = parent.clone_with_class(Parent)
clone2.child_method()  # should be an error

clone2 = child.clone_with_class(Parent)
clone2.child_method()  # Should be an error
一旦我很好地理解了什么是正确的,如果PyCharm错误地抱怨,我就可以针对它提交bug

对于mypy,我按照建议的答案尝试:

from typing import TypeVar, Type

Entity = TypeVar('Entity', bound='Parent')
class Parent:
    def clone_self(self: Entity) -> Entity:
        clone = type(self)()
        # initialize clone here
        return clone

    def clone_with_class(self, klass: Type[Entity]) -> Entity:
        clone = klass()
        # initialize clone here
        return clone

class Child(Parent):
    def child_method(self) -> None:
        print("Calling child method")

child = Child()
parent = Parent()

clone = child.clone_self()
clone.child_method()  # should work

clone = child.clone_with_class(Child)
clone.child_method()  # should work

clone = parent.clone_with_class(Child)
clone.child_method()  # should work

clone2 = parent.clone_self()
clone2.child_method()  # should be an error

clone2 = parent.clone_with_class(Parent)
clone2.child_method()  # should be an error

clone2 = child.clone_with_class(Parent)
clone2.child_method()  # Should be an error
我得到以下信息:

$ mypy --strict test.py
test.py:32: error: "Parent" has no attribute "child_method"
test.py:35: error: "Parent" has no attribute "child_method"
test.py:38: error: "Parent" has no attribute "child_method"

这些错误是意料之中的。

我不知道PyCharm当前是否接受此错误,但以下代码适用于mypy:

from typing import TypeVar, Type

Entity = TypeVar('Entity', bound='Parent')
class Parent:
    def clone_self(self: Entity) -> Entity:
        clone = self.__class__()
        # initialize clone here
        return clone

    def clone_with_class(self, klass: Type[Entity]) -> Entity:
        clone = klass()
        # initialize clone here
        return clone

class Child(Parent):
    def child_method(self) -> None:
        print("Calling child method")

child = Child()
clone = child.clone_self()
clone.child_method()

clone = child.clone_with_class(Child)
clone.child_method()
请注意,我为
clone\u self
指定了一个特定的类型,这让我们可以根据需要更精确地键入返回类型。您可以在此处了解有关使用通用self的更多信息:


您的
clone\u with_class
方法中也有一个bug,这可能会混淆问题——您忘记包含
self
参数。

我修复了
clone\u with_class
bug,谢谢。这里的问题是个错误,不是我的测试用例。这给出了PyCharm中的错误:
klass不可调用
,用于
clone\u with\u class
中的第一行。我倾向于认为PyCharm是错误的。根据您引用的文档,这仍然是实验性的。因此,PyCharm可能不会被破坏,但这还没有实现。mypy处于严格模式时,我在
clone\u self
函数中收到一条警告:从声明返回类型为“Entity`-1”的函数返回Any。此外,严格模式下的mypy不喜欢将
Parent
作为参数传递给
clone\u with\u class
@penguinbian--尝试使用
type(self)(
而不是
self.\uu class\uuuuuuuuuuuuu()
--目前,
type
的签名比
obj更精确。我无法重新编写第二个问题(虽然公平地说,我使用的是从github repo克隆的最新版本的mypy,所以这可能是最近修复的错误)。我添加了更多测试用例来测试所需的行为。