python 3.5+ 中的类型提示克隆功能
type hint clone function in python 3.5+
假设我有以下 类:
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()
然而正如所写,这不会通过类型检查,因为克隆被认为是 Parent
类型而不是 Child
。
我尝试使用 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_with_class
的解决方案是否正确?也许 PyCharm 抱怨是错误的?否则,需要做些什么来修复上面的代码?
应该是TypeVar('Entity', bound='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 错误地抱怨提出错误。
使用 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()
请注意,我为 self
指定了 clone_self
的特定类型——这让我们可以根据需要更精确地输入 return 类型。您可以在此处了解有关使用通用自我的更多信息:http://mypy.readthedocs.io/en/stable/generics.html#generic-methods-and-generic-self
您的 clone_with_class
方法也有一个错误,这可能会使事情变得混乱 -- 您忘记包含 self
参数。
假设我有以下 类:
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()
然而正如所写,这不会通过类型检查,因为克隆被认为是 Parent
类型而不是 Child
。
我尝试使用 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_with_class
的解决方案是否正确?也许 PyCharm 抱怨是错误的?否则,需要做些什么来修复上面的代码?
应该是TypeVar('Entity', bound='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 错误地抱怨提出错误。
使用 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()
请注意,我为 self
指定了 clone_self
的特定类型——这让我们可以根据需要更精确地输入 return 类型。您可以在此处了解有关使用通用自我的更多信息:http://mypy.readthedocs.io/en/stable/generics.html#generic-methods-and-generic-self
您的 clone_with_class
方法也有一个错误,这可能会使事情变得混乱 -- 您忘记包含 self
参数。