繁体   English   中英

Python 键入 - 约束列表只允许一种类型的子类

[英]Python typing - constrain list to only allow one type of subclass

我有 3 个简单的类,例如:

class Animal(abc.ABC):
    ...

class Cat(Animal):
    ...

class Dog(Animal):
    ...

然后我有一个 function 注释如下:

def speak(animals: List[Animal]) -> List[str]:
   ...

我的问题是我想限制List[Animal]只包含一种动物,所以:

speak([Dog(), Dog()]) # OK
speak([Cat(), Cat()]) # OK
speak([Cat(), Dog()]) # typing error

我将如何注释speak function 以允许这样做? 甚至可以使用打字还是我被迫在运行时检查它?

我曾尝试使用List[Animal]如上所述,但是在调用speak speak([Cat(), Dog()])时不会给我错误。

我也尝试过像TypeVar('T', bound=Animal)这样的 generics 乱搞,但这仍然允许我传入一个子类的任意组合的List

我认为您的问题尚未明确定义。 一旦您开始填写更具体的Animal实现,您可能会得出一个令人信服的解决方案。

在这里,我将重新表述您目前的speak标准:您希望它接受Animal的任何单个子类的list ,但不接受Animal本身。 希望我们能明白为什么这没有意义——您给定的代码中没有任何内容表明Animal可以Animal的任何子类区分开来,至少从speak对动物list的作用来看是这样。

让我们提供一些与众不同的功能:

Python 3.10

import typing as t
from typing_extensions import LiteralString
from collections.abc import Sequence

Sound = t.TypeVar("Sound", bound=LiteralString)

class Animal(t.Generic[Sound]):
    def speak(self) -> Sound:
        ...

class Cat(Animal[t.Literal["meow"]]):
    ...

class Dog(Animal[t.Literal["bark"]]):
    ...

def speak(animals: Sequence[Animal[Sound]]) -> list[str]:
    return [animal.speak() for animal in animals]


>>> speak([Dog(), Dog()])  # OK
>>> speak([Cat(), Cat()])  # OK
>>>
>>> # mypy: Argument 1 to "speak" has incompatible type "List[object]"; expected "Sequence[Animal[<nothing>]]" [arg-type]
>>> # pyright: Argument of type "list[Cat | Dog]" cannot be assigned to parameter "animals" of type "Sequence[Animal[Sound@speak]]" in function "speak"
>>> # pyre: Incompatible parameter type [6]: In call `speak`, for 1st positional only parameter expected `Sequence[Animal[Variable[Sound (bound to typing_extensions.LiteralString)]]]` but got `List[Union[Cat, Dog]]`
>>> speak([Cat(), Dog()])

请注意,尽管mypy不会抱怨签名squeak(animals: list[Animal[Sound]]) ,但这在技术上不是类型安全的; 您可以决定将 append Cat() list[Dog] 这就是使用Sequence的原因(它的元素类型是不可变的和协变的)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM