首页 > 解决方案 > 如何设置类方法从类属性中动态返回类型

问题描述

我在我的一个宠物项目中工作,发现了这个小问题。我想在基类中使用类型,问题是类方法的返回类型是由子类设置的字段定义的。这是我的基类

class BaseRepository(metaclass=RequiredAttributes('model')):

    model = None  # The subclasses have to define the this field with a class type.
                  # All the class methods will return objects of the same
                  # type as this field.

    def get(self, id) -> ??:
        # return an object of the type defined in mode
        ...


class UserRepo(BaseRepository): # subclass

    model = User # class type

    ...


我想将get函数的类型设置为与模型字段中定义的对象类型相同。

关于如何完成这样的事情有什么建议吗?

标签: pythonpython-3.xtype-hintingpython-typing

解决方案


如果没有元类,这将通过 MyPy,它能够正确推断出xtype User。我无法使用元类对其进行测试,因为我没有您的元类定义。该解决方案使用参数化Generic作为基类,它允许您向类型检查器断言跨类的不同方法将具有相同的参数和返回参数类型。Django 的存根文件中使用了类似的技术。

注意如果您使用 Python <= 3.8,则必须Typetyping模块导入并使用Optional[Type[M]]而不是注释。Optional[type[M]]model

from typing import Optional, Generic, TypeVar


M = TypeVar('M')


class BaseRepository(Generic[M], metaclass=RequiredAttributes('model')):
    model: Optional[type[M]] = None     # The subclasses have to define the this field with a class type.
                                        # All the class methods will return objects of the same
                                        # type as this field.

    def get(self, id: int) -> M: ...
        # return an object of the type defined in mode
        

class User:
    pass


class UserRepo(BaseRepository[User]): # subclass
    model = User # class type
    

x = UserRepo().get(1)
reveal_type(x)  # Revealed type is "__main__.User*"

推荐阅读