mypy select 方法 return 可以根据当前对象的类型类型吗?
Can mypy select a method return type based on the type of the current object?
在下面的代码中,在 A 的实例上调用 clone()
方法将 return 类型 A 的实例,在 B 的实例上调用它会 return 一个实例B型,依此类推。目的是创建一个与当前实例相同但内部生成的主键不同的新实例,因此可以从那里对其进行编辑并安全地另存为新项目。
???
是某种类型限定符,但我不确定正确的选择是什么。
class A:
def clone(self) -> ???:
cls = self.__class__
result = cls.__new__(cls)
for k, v in self.__dict__.items():
setattr(result, k, deepcopy(v))
result.id = self.__generate_id()
return result
class B(A):
def do_b(self):
pass
我目前用 'A'
替换了 ???
。这行得通,但是如果我想克隆 B 类型的对象,如果我想在其上调用 B 特定的方法,我必须转换 return 值:
b = B().clone()
b.do_b() # type error!
b = cast(B, B().clone())
b.do_b() # OK
但是,可以保证对 B 类型的对象调用 .clone()
将 return 另一个 B 类型的对象,这对我来说有点太 Java 的味道了。有没有一些基于泛型的方法我可以告诉 mypy 方法 return 是一个 __class__
类型的对象,无论 class 是什么?
您可以使用 generic methods with a generic self 来做到这一点——基本上,将您的 self
变量注释为通用的:
from typing import TypeVar
T = TypeVar('T', bound='A')
class A:
def __generate_id(self) -> int:
return 0
def clone(self: T) -> T:
cls = self.__class__
result = cls.__new__(cls)
for k, v in self.__dict__.items():
setattr(result, k, deepcopy(v))
result.id = self.__generate_id()
return result
class B(A):
def do_b(self):
pass
reveal_type(A().clone()) # Revealed type is A
reveal_type(B().clone()) # Revealed type is B
基本上,当我们调用 clone()
时,当 mypy 尝试对 clone 调用进行类型检查时,T
typevar 将绑定到当前实例的类型。这最终使 return 类型匹配实例的类型,无论它是什么。
您可能想知道为什么我将 T
的上限设置为 A
。这是因为行 self.__generate_id()
。基本上,为了对该行进行类型检查,self
不能是字面上的任何类型:它需要是 A
或 A
的某个子类。绑定对此要求进行编码。
在下面的代码中,在 A 的实例上调用 clone()
方法将 return 类型 A 的实例,在 B 的实例上调用它会 return 一个实例B型,依此类推。目的是创建一个与当前实例相同但内部生成的主键不同的新实例,因此可以从那里对其进行编辑并安全地另存为新项目。
???
是某种类型限定符,但我不确定正确的选择是什么。
class A:
def clone(self) -> ???:
cls = self.__class__
result = cls.__new__(cls)
for k, v in self.__dict__.items():
setattr(result, k, deepcopy(v))
result.id = self.__generate_id()
return result
class B(A):
def do_b(self):
pass
我目前用 'A'
替换了 ???
。这行得通,但是如果我想克隆 B 类型的对象,如果我想在其上调用 B 特定的方法,我必须转换 return 值:
b = B().clone()
b.do_b() # type error!
b = cast(B, B().clone())
b.do_b() # OK
但是,可以保证对 B 类型的对象调用 .clone()
将 return 另一个 B 类型的对象,这对我来说有点太 Java 的味道了。有没有一些基于泛型的方法我可以告诉 mypy 方法 return 是一个 __class__
类型的对象,无论 class 是什么?
您可以使用 generic methods with a generic self 来做到这一点——基本上,将您的 self
变量注释为通用的:
from typing import TypeVar
T = TypeVar('T', bound='A')
class A:
def __generate_id(self) -> int:
return 0
def clone(self: T) -> T:
cls = self.__class__
result = cls.__new__(cls)
for k, v in self.__dict__.items():
setattr(result, k, deepcopy(v))
result.id = self.__generate_id()
return result
class B(A):
def do_b(self):
pass
reveal_type(A().clone()) # Revealed type is A
reveal_type(B().clone()) # Revealed type is B
基本上,当我们调用 clone()
时,当 mypy 尝试对 clone 调用进行类型检查时,T
typevar 将绑定到当前实例的类型。这最终使 return 类型匹配实例的类型,无论它是什么。
您可能想知道为什么我将 T
的上限设置为 A
。这是因为行 self.__generate_id()
。基本上,为了对该行进行类型检查,self
不能是字面上的任何类型:它需要是 A
或 A
的某个子类。绑定对此要求进行编码。