我想在 python 3.8 中以 Lisp 方式实现一个 Liste 类,其中包含 head 和 tail、car()、cdr() 和 nil。我想定义一个通用类型,接受 Liste 中类型 T 的对象。
from __future__ import annotations
from typing import TypeVar, Callable, Generic
T = TypeVar('T')
class Liste(Generic[T]):
def __init__(self, h: T, t: Liste[T]) -> None:
self.head = h
self.tail = t
@staticmethod
def nil() -> Liste[T]:
return Liste(None, None)
def est_vide(self) -> bool:
return (self.head is None) and (self.tail is None)
def cdr(self)->Liste[T]:
if self.tail is None: return Liste.nil()
else: return self.tail
def sum(self)->T:
if self.est_vide():
return 0
else:
return self.head + self.cdr().sum()
我一直在类型提示方面度过了一段非常愉快的时光。但是mypy点了4个错误
liste_sof.py:13: error: Argument 1 to "Liste" has incompatible type "None"; expected "T"
liste_sof.py:13: error: Argument 2 to "Liste" has incompatible type "None"; expected "Liste[T]"
liste_sof.py:23: error: Incompatible return value type (got "int", expected "T")
liste_sof.py:25: error: Unsupported left operand type for + ("T")
Found 4 errors in 1 file (checked 1 source file)
问题 1 是能够指定我期望实现 __add__
方法的 T 对象。我不知道该怎么做。
问题 2 是处理我的类中特殊的 Liste.nil()
空对象。
最佳答案
Mypy 正在提示,因为您需要使用 Optional
如果你想要h
或t
能够成为None
,否则,您是在暗示一切都必须是 None
,这不是通用的。
您可以使用 Protocol
的结构类型表达“有__add__
”。
最后,没有干净的方法来获取“空对象”。对于内置类型,type(self)()
可能可行,但老实说,我只是强制 API 采用初始值。
from __future__ import annotations
from typing import TypeVar, Callable, Generic, Protocol, Optional
T = TypeVar('T')
class SupportsAdd(Protocol[T]):
def __add__(self: T, other: T) -> T:
...
A = TypeVar('A', bound=SupportsAdd)
class Liste(Generic[A]):
def __init__(self, h: Optional[A], t: Optional[Liste[A]]) -> None:
self.head = h
self.tail = t
@staticmethod
def nil() -> Liste[A]:
return Liste(None, None)
def est_vide(self) -> bool:
return (self.head is None) and (self.tail is None)
def cdr(self)->Liste[A]:
if self.tail is None: return Liste.nil()
else: return self.tail
def sum(self, init: A) -> A:
if self.head is None or self.tail is None:
return init
else:
return self.head + self.cdr().sum(init)
正如我在评论中所说,这个类(class)非常学术化,你可能不应该实际使用它。这将是低效的。至少,您不应该对 sum
使用递归。 .
关于python 通用类型提示 + 用户定义的容器 + 约束实现 __add__ 方法的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64141153/