[英]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.