python通用类型提示+用户定义的容器+限制为实现__add__方法的类型

问题描述

我想在python 3.8中实现带有头和尾,car(),cdr()和nil的Lisp方式的Liste类。我想在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抱怨是因为如果您想使Optionalh成为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)

正如我在评论中所述,该课程非常学术,您可能不应该实际使用它。这将是低效的。至少,您不应该对sum使用递归。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...