簡體   English   中英

使用類層次結構和 mypy 進行靜態類型測試

[英]Using a class hierarchy and mypy for static type testing

在下面的示例代碼中,我有一個簡單的類層次結構: 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" 不兼容; 超類型將參數類型定義為“事物”

但是, get_by_id簽名的返回類型沒有問題。

這里發生了什么,我該如何修復類型檢查?

通用類型是您的朋友。

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上找到這個后,我將抽象類中的類型簽名更改為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 here 似乎沒問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM