Dem*_*kyy 6 python python-typing
我有 3 个简单的类,例如:
class Animal(abc.ABC):
...
class Cat(Animal):
...
class Dog(Animal):
...
Run Code Online (Sandbox Code Playgroud)
然后我有一个注释如下的函数:
def speak(animals: List[Animal]) -> List[str]:
...
Run Code Online (Sandbox Code Playgroud)
我的问题是我想限制List[Animal]只包含一种动物,所以:
speak([Dog(), Dog()]) # OK
speak([Cat(), Cat()]) # OK
speak([Cat(), Dog()]) # typing error
Run Code Online (Sandbox Code Playgroud)
我将如何注释该speak函数以实现此目的?是否可以使用打字来完成,或者我是否被迫在运行时检查这一点?
我尝试使用上面的方法,但是在调用likeList[Animal]时不会出现错误。speakspeak([Cat(), Dog()])
我也尝试过使用泛型,TypeVar('T', bound=Animal)但这仍然允许我传递子List类的任意组合。
我认为您的问题尚未明确定义。一旦您开始填写更具体的实现Animal,您可能会得到一个令人信服的解决方案。
在这里,我将重新表述您speak目前的标准:您希望它接受list的任何单个子类的a Animal,但不接受Animal其本身。希望我们能明白为什么这没有意义 - 您给定的代码中没有任何内容表明Animal 可以与 的任何子类区分开来,至少从对动物的作用的Animal角度来看是这样。speaklist
让我们提供一些区别特征:
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()])
Run Code Online (Sandbox Code Playgroud)
请注意,虽然mypy不会抱怨签名squeak(animals: list[Animal[Sound]]),但这在技术上不是类型安全的;您可以决定附加Cat()到list[Dog]. 这就是使用 的原因Sequence(它的元素类型是不可变且协变的)。
| 归档时间: |
|
| 查看次数: |
602 次 |
| 最近记录: |