【问题标题】:Python - Overloading asynchronous methodsPython - 重载异步方法
【发布时间】:2019-02-26 18:33:32
【问题描述】:

我正在为 API 构建一个包装器。目前,它有效。但是,它是同步的,使用请求模块进行 HTTP 调用。

我想实现一种方法来异步调用这些方法,而不必使用不同的名称或 lib 版本。我立刻想到了重载,但是看到python中的重载与其他语言有点不同,看起来不太可能。

基本上,我想构建一个看起来像这样的类(从想法上讲,我知道它在 Python 中不起作用):

class Foo:
    def foo(self):
        # Requests code...
        print("foo sync")

    async def foo(self):
        # aiohttp code...
        print("foo async")

并以这种方式使用它:

f = Foo()
f.foo()
await f.foo()

输出:

>> "foo sync"
>> "foo async"

基本上,在这段代码中,异步函数会完全覆盖前一个函数,这并没有真正的帮助。

通过谷歌搜索,这看起来不太可能,但是,Python 总是设法让我感到惊讶。

提前致谢:D

【问题讨论】:

  • 为什么不只创建foo()foo_async() 方法来处理特定的用例呢?为 API 用户定义显式方法(几乎)总是比根据其用途让单个方法执行不同的方法更好 - 对于初学者来说,它可以避免混淆,并且不会强迫用户阅读有关该方法如何为他们和他们执行的详细文档用例。
  • @zwer 是的,所以我想到了这一点,但后来我认为能够使用重载样式语法会更方便。既然你这么说,我觉得还是把方法分开比较好。无论如何,我将不得不复制大部分代码(因为异步需要一直异步,AFAIK),这样会更具可读性。感谢您的建议。

标签: python python-3.x oop async-await python-requests


【解决方案1】:

问题:重载异步方法

考虑以下class 定义,将InheritanceOverloading 一起使用!

你有一个基础class Foo:,从它继承class Foo_async(Foo):
因此,您可以在 syncasync 模式下重用大部分实现。
class Foo_async主要只实现async/await的要求。

注意:我使用的是asyncio。例如:

import asyncio

class Foo():
    def __init__(self):
        self.mode = "sync"

    def __repr__(self):
        return "{}::foo() {}".format(self.__class__.__name__, self.mode)

    def foo(self):
        print("{}".format(self.__repr__()))
        print("\t\tworkload {}".format(1))
        print("\t\tworkload {}".format(2))

class Foo_async(Foo):
    def __init__(self):
        self.mode = "async awaited"

    async def foo(self):
        super().foo()

用法

async def run(foo):
    await foo.foo()

if __name__ == '__main__':
    Foo().foo()

    loop = asyncio.get_event_loop()
    loop.run_until_complete(run(Foo_async()))
    loop.close()

输出

Foo::foo() sync
        workload 1
        workload 2
Foo_async::foo() async awaited
        workload 1
        workload 2

如果您想要更细化,请将 def foo(...) 中的工作负载拆分为单独的工作负载函数。
现在您可以使用await 调用此函数。

例如:(显示,只改代码!)

class Foo():
    ...

    def foo(self):
        print("{}".format(self.__repr__()))
        self.workload_1()
        self.workload_2()

    def workload_1(self):
        print("\t\t{} workload {}".format(self.mode, 1))

    def workload_2(self):
        print("\t\t{} workload {}".format(self.mode, 2))

class Foo_async(Foo):
    ...       

    async def foo(self):
        print("{}".format(self.__repr__()))
        await self.workload_1()
        await self.workload_2()

    async def workload_1(self):
        super().workload_1()

    async def workload_2(self):
        super().workload_2()

输出

Foo::foo() sync
        sync workload 1
        sync workload 2
Foo_async::foo() async awaited
        async awaited workload 1
        async awaited workload 2

用 Python:3.5.3 测试

【讨论】:

  • 这是个好主意。我认为我最终要做的是将我的课程分成两个文件:classes.pyclasses_async.py。如果他们想使用异步版本,他们必须显式导入classes_async(这将重新实现应该是异步的函数),然后定期将其与 await 一起使用。所以实际上你的建议。这样两个文件都会相对较薄。非常感谢,您帮助解决了一个巨大的设计挑战。
  • 我收到 mypy 错误(返回类型“Coroutine[Any, Any, ...]” of "..." 与超类型 "..." mypy 中的返回类型 "..." 不兼容(错误))使用异步版本覆盖同步方法时。
  • 好主意,但要添加一个具有不同函数名称和 2 个关键字的函数,工作量太大。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
  • 2018-02-24
  • 1970-01-01
  • 2015-03-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多