假设我有以下数据:
@dataclass
class Product:
color: str
@dataclass
class Wrench(Product):
pass
@dataclass
class Hammer(Product):
pass我试图用两个字段创建一个名为Order的新数据集,这两个字段必须具有相同的Product子类。我可以像这样创建Order类:
@dataclass
class Order:
primary_product: Product
secondary_product: Product但是,这并不验证我前面所述的相同的Product子类条件:
product1 = Wrench(color="Yellow")
product2 = Hammer(color="Black")
order = Order(primary_product=product1, secondary_product=product2) # NO ERROR以下Order与仿制药的实现为我提供了一些方法:
from typing import Generic, TypeVar
T = TypeVar("T")
@dataclass
class Order(Generic[T]):
primary_product: T
secondary_product: T
product1 = Wrench(color="Yellow")
product2 = Wrench(color="White")
product3 = Hammer(color="Black")
order1 = Order[Wrench](primary_product=product1, secondary_product=product2)
order2 = Order[Wrench](primary_product=product1, secondary_product=product3) # error: Argument "secondary_product" to "Order" has incompatible type "Hammer"; expected "Wrench"在每个对象初始化时将目标Product子类(在上面的情况下是Wrench)传递给Order是很烦人的。此外,这并不能确保这两个领域都是产品:
order1 = Order[int](primary_product=1, secondary_product=2) # NO ERROR究竟是为了实现这一目标,还是我将mypy和Python暗示的限制推得太远了?
发布于 2021-01-07 16:58:59
在您发布的类型文档中,有两种不同的方式。两者都不理想。
第一种方法:使用类型绑定
T = TypeVar('T', bound=Product)现在,泛型参数只能是Product。
order1 = Order[int](primary_product=1, secondary_product=2)
# error: Value of type variable "T" of "Order" cannot be "int"
order1 = Order(primary_product=1, secondary_product=2)
# error: Value of type variable "T" of "Order" cannot be "int"不幸的是,泛型参数现在可以推断为确切的Product。
product1 = Wrench(color="Yellow")
product2 = Hammer(color="Black")
order = Order(primary_product=product1, secondary_product=product2) # no error
reveal_type(order)
# Revealed type is 'Order[Product*]'所以有来指定泛型类型
第二条途径:价值限制
T = TypeVar('T', Hammer, Wrench)现在,甚至这也被正确地识别为错误。
product1 = Wrench(color="Yellow")
product2 = Hammer(color="Black")
order = Order(primary_product=product1, secondary_product=product2)
# error: Value of type variable "T" of "Order" cannot be "Product"这种方法的问题很明显:您必须将Product的所有子类键入到TypeVar构造函数中。
第三条路:工厂功能
经过一些实验,我发现了第三种方法,它有一些奇怪的语法,但结合了前两种方法的优点。这样做的目的是将泛型参数强制为第一个参数的类型。
T = TypeVar('T', bound=Product)
def make_order(primary: P) -> Callable[[P], Order[P]]:
def inner(secondary: P) -> Order[P]:
return Order(primary, secondary)
return inner
make_order(1)(2)
# error: Value of type variable "T" of "make_order" cannot be "int"
product1 = Wrench(color="Yellow")
product2 = Hammer(color="Black")
make_order(product1)(product2)
# Argument 1 has incompatible type "Hammer"; expected "Wrench"
order = make_order(product1)(product1)
reveal_type(order)
# Revealed type is 'Order[Wrench*]'缺点是:
为了防止用户直接实例化Order,可以将类重命名为_Order。
https://stackoverflow.com/questions/65607438
复制相似问题