英文:
Nested generics in python using the returns package
问题
以下是代码的翻译部分:
作为示例,我有一个动物园。一个动物园(Z)有一个笼子列表(C),而一个笼子有一个动物列表(A)。
由于mypy不支持嵌套泛型,我正在尝试使用[returns](https://returns.readthedocs.io/en/latest/)包的高级类型来获得正确的类型检查。
作为一种特殊类型的动物园,我有一个OpenZoo,它只能包含包含狗的OpenCages。
我的尝试看起来像这样:
```python
import itertools
from typing import TypeVar
from returns.primitives.hkt import Kind1, Kind2, SupportsKind1, SupportsKind2
A = TypeVar('A', bound='Animal')
C = TypeVar('C', bound='Cage')
Z = TypeVar('Z', bound='Zoo')
class Animal:
def feed(self):
...
class Dog(Animal):
def bark(self):
print("Woof!")
class Cage(SupportsKind1['Cage', A]):
def __init__(self, animals: list[A]):
self.animals = animals
class OpenCage(Cage[Dog]):
def unleash(self) -> None:
...
class Zoo(SupportsKind2['Zoo', C, A]):
def __init__(self, cages: list[Kind1[C, A]]):
self.cages = cages
def all_animals(self) -> list[A]:
return list(itertools.chain.from_iterable([c.animals for c in iter(self.cages)]))
class OpenZoo(Zoo[OpenCage, Dog]):
def unlock_cages(self) -> None:
...
my_animal = Dog()
my_cage = OpenCage([my_animal])
my_zoo = OpenZoo([my_cage]) # <--- mypy错误在这里
然而,这会导致mypy错误 error: List item 0 has incompatible type "OpenCage"; expected "KindN[OpenCage, Dog, Any, Any]" [list-item]
。
你有任何解决此问题的想法吗?或者是否有另一种更好的方法来实现这一目标?
我正在使用Python 3.10和mypy 1.0.1。
英文:
As an example, I have a zoo. A zoo (Z) has a list of cages (C), and a cage has a list of animals (A).
Since mypy doesnt support nested generics properly, I am experimenting with the returns package's higher kinded types in order to get proper typechecks.
As a special type of zoo, I have an OpenZoo which can only contain OpenCages with Dogs in it.
My attempt looks like so:
import itertools
from typing import TypeVar
from returns.primitives.hkt import Kind1, Kind2, SupportsKind1, SupportsKind2
A = TypeVar('A', bound='Animal')
C = TypeVar('C', bound='Cage')
Z = TypeVar('Z', bound='Zoo')
class Animal:
def feed(self):
...
class Dog(Animal):
def bark(self):
print("Woof!")
class Cage(SupportsKind1['Cage', A]):
def __init__(self, animals: list[A]):
self.animals = animals
class OpenCage(Cage[Dog]):
def unleash(self) -> None:
...
class Zoo(SupportsKind2['Zoo', C, A]):
def __init__(self, cages: list[Kind1[C, A]]):
self.cages = cages
def all_animals(self) -> list[A]:
return list(itertools.chain.from_iterable([c.animals for c in iter(self.cages)]))
class OpenZoo(Zoo[OpenCage, Dog]):
def unlock_cages(self) -> None:
...
my_animal = Dog()
my_cage = OpenCage([my_animal])
my_zoo = OpenZoo([my_cage]) # <--- mypy error here
However, this yields mypy error error: List item 0 has incompatible type "OpenCage"; expected "KindN[OpenCage, Dog, Any, Any]" [list-item]
Any idea how I should fix this issue? Or if there is another (better) way of achieving this?
I'm using python 3.10 and mypy 1.0.1
答案1
得分: 0
错误消息建议my_cage的类型为OpenCage,与OpenZoo的第二个类型参数KindN[OpenCage, Dog, Any, Any]的预期类型不兼容。
这是因为OpenZoo被定义为只包含具有Dog作为动物类型的OpenCage的动物园,但my_cage的类型仅为OpenCage[Dog]。因此,my_cage的类型需要使用SupportsKind1提升为Kind1[OpenCage, Dog],以匹配Zoo的类型参数。
以下代码应该解决这个错误:
import itertools
from typing import TypeVar
A = TypeVar('A', bound='Animal')
C = TypeVar('C', bound='Cage')
Z = TypeVar('Z', bound=Zoo[C, A])
class Animal:
def feed(self):
...
class Dog(Animal):
def bark(self):
print("Woof!")
class Cage:
def __init__(self, animals: list[A]):
self.animals = animals
class OpenCage(Cage):
def unleash(self) -> None:
...
class Zoo:
def __init__(self, cages: list[Cage]):
self.cages = cages
def all_animals(self) -> list[A]:
return [animal for cage in self.cages for animal in cage.animals]
class OpenZoo(Zoo):
def unlock_cages(self) -> None:
...
my_animal = Dog()
my_cage = OpenCage([my_animal])
my_zoo = OpenZoo([my_cage])
希望对你有所帮助
英文:
I did some research and i found this :
The error message suggests that the type of my_cage is OpenCage, which is not compatible with the expected type of KindN[OpenCage, Dog, Any, Any] for the second type parameter of OpenZoo.
This is because OpenZoo is defined as a Zoo that only contains OpenCage with Dog as the animal type, but my_cage is of type OpenCage[Dog] only. Therefore, the type of my_cage needs to be lifted to a Kind1[OpenCage, Dog] using SupportsKind1 in order to match the type parameter of Zoo.
The code below should resolve the error
import itertools
from typing import TypeVar
A = TypeVar('A', bound='Animal')
C = TypeVar('C', bound='Cage')
Z = TypeVar('Z', bound=Zoo[C, A])
class Animal:
def feed(self):
...
class Dog(Animal):
def bark(self):
print("Woof!")
class Cage:
def __init__(self, animals: list[A]):
self.animals = animals
class OpenCage(Cage):
def unleash(self) -> None:
...
class Zoo:
def __init__(self, cages: list[Cage]):
self.cages = cages
def all_animals(self) -> list[A]:
return [animal for cage in self.cages for animal in cage.animals]
class OpenZoo(Zoo):
def unlock_cages(self) -> None:
...
my_animal = Dog()
my_cage = OpenCage([my_animal])
my_zoo = OpenZoo([my_cage])
Hope this helps
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论