我想将泛型类传递给函数,以便我可以返回与结果相同的类型。我的用例是编写 ORM 和读取函数,该函数将采用表 ORM,并返回与结果相同的类型,如下所示:
def read<T>(id, fields="*") -> T:
目前无需输入,我的代码如下所示:
def read(table, id, fields="*"):
这样的事情可能吗?
TL;DR Python 不需要泛型,因为它是动态类型语言。这允许我们使用所谓的鸭子类型而不是显式泛型。
首先要注意的是,Python 中的类型注释只是建议。它们在您编写代码时帮助静态分析工具(例如代码完成),但不会在运行时强制执行。
考虑到这一点,让我们看一下函数的无注释版本:
def read(table, fields="*"):
pass
这里,Python 并不关心你传递给
table
的内容,只要它支持 read()
内部使用的操作即可。这就是我们所说的鸭子打字:如果它像鸭子一样嘎嘎叫,那么它就是鸭子。您可以在作用于序列的函数中看到这一点。例如:
def print_list(my_list):
for el in my_list:
print(el)
我们可以用列表或元组调用
print_list()
:
print_list([1, 2, 3, 4])
print_list((1, 2, 3, 4))
事实上,任何实现
__iter__()
和 __next__()
的东西都可以工作。这是类型的契约,不需要用接口、超类或泛型类型来指定。
现在回到类型提示:有一种方法可以通过类型提示指定“鸭子类型合约”,但我不知道具体细节。你可以做一些研究来找出答案。正如 @juanpa.arrivillaga 在评论中发布的,如果您有兴趣学习如何对此类情况进行类型提示,您可以查看
typing.Protocol
。
好吧,我最近在研究 Python 类型提示功能并想出了类似的东西
DBModel = TypeVar('DBModel')
class BaseRepository(Generic[DBModel]):
def __init__(self):
self.model: Type[DBModel] = get_args(self.__orig_bases__[0])[0]
def get_where(self, *args) -> DBModel
... # any logic with self.model
作为基类并且
class UsersRepository(BaseRepository[User]):
pass
UsersRepository
现在已经使用 get_where()
模型实现了 User
,并且还将在 User
内部提供
self.model
的参考
我想这就是你想要的。 Github 带有源代码(实际上是小项目。)
是的,从Python 3.12开始你可以写:
def read[T](table, id, fields="*") -> T: