如何使用类变量的值(它是一个类对象)作为Python类型化/mypy的(mixin)方法的返回类型
下面是一个简单的示例,您将发现真实的、更复杂的用例:
from typing import Generic, Type, TypeVar
T = TypeVar('T')
class Base(Generic[T]):
return_type: Type[T]
value: T # This attribute is only needed for this minimal example
class Mixin:
def get(self: Base[T]) -> T: # mypy: The erased type of self "Base" is not a supertype of its class "Mixin"
return self.return_type(self.value) # mypy: Too many arguments for "object"
class Concrete(Mixin, Base[int]):
return_type = int
def __init__(self):
self.value = 3
c = Concrete()
x: str = c.get() # mypy: expected incompatible types (str vs int) error :)
当将Base
设置为Mixin
的超类时,我可以消除第二个错误,但这并不是我真正想要的。不过,我现在知道了如何正确定义return_type: Type[T]
我已经阅读了python类型文档和mypy文档,但什么也没找到。网络搜索也没有产生有用的结果
我目前正在编写一个REST客户端,其架构类似于python-gitlab:
用户使用一个ApiClient
类,该类知道API URL并执行所有HTTP请求
API的端点由REST管理器类表示,这些类是ApiClient
的属性。根据端点的功能,REST管理器可以列出端点的对象、获取单个对象或创建、更新和删除对象
具体的REST管理器子类aRestManager
基类和各种混合用于HTTP操作,例如,aGetMixin
用于按ID获取单个对象。
具体的REST管理器有一个类变量,该类变量保存它将返回的对象类
在mixin类中,我想表示“此方法返回对象类的实例,子类restmanager将其定义为类变量”
用法示例:
client = ApiClient('https://example.com/myapi/v1')
item = client.items.get(42)
assert isinstance(item, Item)
实施:
from typing import ClassVar, Type, TypeVar
T = TypeVar(T)
class Item:
"""Data class that represents objects of the "items" endpoint"""
pass
class ApiClient:
"""Main object that the user works with."""
def __init__(self, url: str):
self.url = url
# There is one manager instance for each endpoint of the API
self.items = ItemManager(self)
# self.cats = CatManager(self)
def http_get(self, path: str) -> 'Response':
... # Request the proper url and return a response object
class RestManager:
"""Base class for REST managers."""
_path: ClassVar[str]
_obj_cls: ClassVar[Type[T]] # Concrete subclasses set this with an object class, e.g., "Item"
def __init__(self, client: ApiClient):
self.client = client
@property
def path(self) -> str:
return self._path
class GetMixin:
"""Mixin for getting a single object by ID"""
def get(self: RestManager, id: int) -> T: # Return type is the value the subclass' "_obj_cls" attribute
response = self.client.http_get(f'{self.path}/{id}')
return self._obj_cls(**response.json())
class ItemsManager(GetMixin, RestManager):
"""Concrete manager for "Item" objects."""
_path = '/items'
_obj_cls = Item # This is the return type of ItemsManager.get()
client = ApiClient()
item = client.items.get(42)
assert isinstance(item, Item)
免责声明:我没有仔细阅读您的实际用例,所以我可能是错的。以下分析基于您的简化示例
我认为
mypy
不支持这一点。当前mypy
假定(并且理所当然地)方法中的self
类型是类的子类型但是,为了使mixin正常工作,必须对可以混合的类的类型进行限制。例如,在简化的示例中,类必须具有
return_type
和value
属性。我的建议是,您还可以将这些作为注释添加到yout mixin类中,结果如下:请注意,} 解决这个问题,但这可能有点过分。嗯,如果你有一些简单的代码,你肯定是对的,有时候一点
mypy
中的最后一行仍然是一个错误,因为它无法证明self.return_type
的__init__
方法只接受一个参数。您可以使用Python3.7中引入的^{# type: ignore
对你来说是最好的相关问题 更多 >
编程相关推荐