作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
概括
如何使用类变量的值(它是一个类对象)作为 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
的父类(super class),但这并不是我真正想要的。不过,我现在知道如何正确定义
return_type: Type[T]
.
ApiClient
知道 API URL 并执行所有 HTTP 请求的类。 ApiClient
的属性。 .根据端点的功能,REST 管理器可以列出端点的对象、获取单个对象或创建、更新和删除对象。 RestManager
HTTP 操作的基类和各种混合,例如,GetMixin
用于通过 ID 获取单个对象。 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
属性。我的建议是,您还可以将它们添加为您的 mixin 类的注释,结果如下:
T = TypeVar('T')
class Base(Generic[T]):
return_type: Type[T]
value: T # This attribute is only needed for this minimal example
class Mixin(Generic[T]):
return_type: Type[T]
value: T
def get(self) -> T: # annotation on `self` can be dropped
return self.return_type(self.value)
请注意,最后一行仍然是
mypy
中的错误,因为不能证明
__init__
self.return_type
的方法只需要一个参数。您可以使用
typing.Protocol
解决此问题这是在 Python 3.7 中引入的,但它可能有点矫枉过正。恕我直言,如果你有一些简单的代码,你很确定是正确的,有时有点
# type: ignore
最适合你。
关于Python 输入 : Use a class variable's value as return type of a (mixin) method,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61916762/
我是一名优秀的程序员,十分优秀!