在Python中,是否可以像C#一样传递函数泛型?

问题描述 投票:0回答:3

我想将泛型类传递给函数,以便我可以返回与结果相同的类型。我的用例是编写 ORM 和读取函数,该函数将采用表 ORM,并返回与结果相同的类型,如下所示:

def read<T>(id, fields="*") -> T:

目前无需输入,我的代码如下所示:

def read(table, id, fields="*"):

这样的事情可能吗?

python generics
3个回答
1
投票

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


0
投票

好吧,我最近在研究 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 带有源代码(实际上是小项目。)


0
投票

是的,从Python 3.12开始你可以写:

def read[T](table, id, fields="*") -> T:
© www.soinside.com 2019 - 2024. All rights reserved.