使用类层次结构和mypy进行静态类型测试

2024-04-26 18:32:17 发布

您现在位置:Python中文网/ 问答频道 /正文

在下面的示例代码中,我有一个简单的类层次结构:Thing->Bookmark。你知道吗

from abc import ABC, abstractmethod
from dataclasses import dataclass
from datetime import datetime
import rdflib
import json
import dateutil.parser

########### Class Hierarchy ##############ß
@dataclass
class Thing:
    ID: str

@dataclass
class Bookmark(Thing):
    creator: str
    description: str
    url: str
    created_on: datetime

########### Ports #################
class RepositoryInterface(ABC):
    @abstractmethod
    def save(self, data: Thing) -> str:
        pass
    @abstractmethod
    def get_by_id(self, ID: str) -> Thing:
        pass

########### Adaptors ###############

class FileBasedBookmarkStore(RepositoryInterface):
    def save(self, data: Bookmark) -> str:
        with open(data.ID, "w") as f:
            dataJson = data.__dict__
            dataJson["created_on"] = data.created_on.isoformat()
            json.dump(data.__dict__, f)
            return data.ID

    def get_by_id(self, ID: str) -> Bookmark:
        with open(ID, "r") as f:
            jsonBookmark  = json.load(f)
            jsonBookmark["created_on"] = dateutil.parser.parse(jsonBookmark["created_on"])
            return Bookmark(**jsonBookmark)

我的存储库有一个为Thing定义的抽象类,然后我为Bookmark实现了一个特定的版本。你知道吗

mypy权利要求:

>; “save”的参数1与超类型“RepositoryInterface”不兼容;超类型将参数类型定义为“Thing”

但是,get_by_id签名的返回类型没有问题。你知道吗

这是怎么回事?我该如何修复类型检查?你知道吗


Tags: fromimportselfid类型dataondef
2条回答

泛型是你的朋友。你知道吗

from abc import ABC, abstractmethod
from dataclasses import dataclass
from datetime import datetime
from typing import TypeVar, Generic
import json
import dateutil.parser

########### Class Hierarchy ##############ß
@dataclass
class Thing:
    ID: str

@dataclass
class Bookmark(Thing):
    creator: str
    description: str
    url: str
    created_on: datetime

T = TypeVar('T', bound=Thing)

########### Ports #################
class RepositoryInterface(ABC, Generic[T]):
    @abstractmethod
    def save(self, data: T) -> str:
        pass
    @abstractmethod
    def get_by_id(self, ID: str) -> T:
        pass

########### Adaptors ###############

class FileBasedBookmarkStore(RepositoryInterface[Bookmark]):
    def save(self, data: Bookmark) -> str:
        with open(data.ID, "w") as f:
            dataJson = data.__dict__
            dataJson["created_on"] = data.created_on.isoformat()
            json.dump(data.__dict__, f)
            return data.ID

    def get_by_id(self, ID: str) -> Bookmark:
        with open(ID, "r") as f:
            jsonBookmark  = json.load(f)
            jsonBookmark["created_on"] = dateutil.parser.parse(jsonBookmark["created_on"])
            return Bookmark(**jsonBookmark)

github上找到this之后,我将抽象类中的类型签名更改为Any。你知道吗

########### Ports #################
class RepositoryInterface(ABC):
    @abstractmethod
    def save(self, data: Any) -> str:
        pass
    @abstractmethod
    def get_by_id(self, ID: str) -> Thing:
        pass

大多数其他参考文献都说,由于Liskov替换原理,早期版本被正确地标记为问题。你知道吗

但是,由于该方法是抽象的,并且需要一个具体的实现,在这里有Any在我看来是可以的。你知道吗

相关问题 更多 >