Ich versuche, einen JSON-Decoder in Python zu schreiben, der funktionale Programmierung verwendet, die ein generisches Ergebnis zurückgibt, anstatt Fehler auszulösen. Ich glaube, das Problem liegt daran, dass mypy denkt, dass sich die zugrunde liegende Datenstruktur irgendwann in der Zukunft ändern kann, und die Verwendung von „Kovariante“ behebt das Problem, aber Mypy beschwert sich darüber, dass Kovariante Parameter sind.
Kann sich jemand den folgenden Code und den Mypy-Fehler ansehen und so einfach wie möglich erklären, warum er auftritt, und wie ich den Code ändern könnte, um die Fehler zu beheben und gleichzeitig unveränderliche Datenklassen beizubehalten?
Code: Select all
from dataclasses import dataclass
from typing import Literal
@dataclass(frozen=True)
class Ok[T]:
value: T
@dataclass(frozen=True)
class Err[E]:
value: E
type Result[T, E] = Ok[T] | Err[E]
@dataclass(frozen=True)
class Dog:
nm: str
kind: Literal['Dog'] = 'Dog'
@dataclass(frozen=True)
class Cat:
nm: str
kind: Literal['Cat'] = 'Cat'
type Animal = Dog | Cat
def decodeDog(slop: dict) -> Result[Dog, str]:
try:
return Ok(Dog(slop["nm"]))
except Exception as e:
return Err(f"Decode Error: {e}")
def decodeCat(slop: dict) -> Result[Cat, str]:
try:
return Ok(Cat(slop["nm"]))
except Exception as e:
return Err(f"Decode Error: {e}")
def decodeAnimal(slop: dict) -> Result[Animal, str]:
match slop.get("kind"):
case "Dog":
return decodeDog(slop)
case "Cat":
return decodeCat(slop)
case _:
return Err("Unknown Animal")
if __name__ == "__main__":
print(decodeDog({"nm": "Spot"}))
print(decodeDog({"someOtherField": "someOtherStuff"}))
print(decodeCat({"nm": "Garfield"}))
print(decodeCat({"someOtherField": "someOtherStuff"}))
print(decodeAnimal({"nm": "Spot", "kind": "Dog"}))
print(decodeAnimal({"nm": "Garfield", "kind": "Cat"}))
print(decodeAnimal({"nm": "ET", "kind": "Animal"}))
Code: Select all
❯ python example.py
Ok(value=Dog(nm='Spot', kind='Dog'))
Err(value="Decode Error: 'nm'")
Ok(value=Cat(nm='Garfield', kind='Cat'))
Err(value="Decode Error: 'nm'")
Ok(value=Dog(nm='Spot', kind='Dog'))
Ok(value=Cat(nm='Garfield', kind='Cat'))
Err(value='Unknown Animal')
Code: Select all
example.py:42: error: Incompatible return value type (got "Ok[Dog] | Err[str]", expected "Ok[Dog | Cat] | Err[str]") [return-value]
example.py:44: error: Incompatible return value type (got "Ok[Cat] | Err[str]", expected "Ok[Dog | Cat] | Err[str]") [return-value]
Mobile version