gpt4 book ai didi

Python 输入 : Use a class variable's value as return type of a (mixin) method

转载 作者:行者123 更新时间:2023-12-04 17:28:23 26 4
gpt4 key购买 nike

概括

如何使用类变量的值(它是一个类对象)作为 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] .

我已经阅读了 python 类型文档以及 mypy 文档,但一无所获。网络搜索也没有产生有用的结果。

我真正想做的事

我目前正在编写一个架构类似于 python-gitlab 的 REST 客户端。 :
  • 用户使用 ApiClient知道 API URL 并执行所有 HTTP 请求的类。
  • API 的端点由 REST 管理器类表示,这些类是 ApiClient 的属性。 .根据端点的功能,REST 管理器可以列出端点的对象、获取单个对象或创建、更新和删除对象。
  • RestManager 返回和接收“哑”数据类(例如,attrspydantic 模型)
  • 具体的 REST 管理器子类 a RestManager HTTP 操作的基类和各种混合,例如,GetMixin用于通过 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_typevalue属性。我的建议是,您还可以将它们添加为您的 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/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com