Python - 重载异步方法

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

我正在为 API 构建一个包装器。目前来说,它有效。然而,它是同步的,使用 requests 模块进行 HTTP 调用。

我想实现一种异步调用这些方法的方法,而不必使用不同的名称或库版本。我立即想到了重载,但由于 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

python python-3.x oop async-await python-requests
2个回答
14
投票

问题:重载异步方法

考虑以下

class
定义,使用
Inheritance
Overloading

您有一个基础

class Foo:
,从中继承
class Foo_async(Foo):

因此,您可以在
sync
async
模式下重用大部分实现。
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


0
投票

使用不涉及异步的所有内容的继承来实现要好得多。这避免了 mypy 的错误。 所以基于 stovfl 的回答:


class BaseFoo:
    def __init__(*args, **kwargs):
        self.myattr1 = ...
        self.myattr2 = ...

    def mymethod(self):
        # do something common here
        # keep it sync to share it between both sync and async implementations
        pass

class Foo(BaseFoo):

    def foo(self):
        val = mymethod()
        return my_sync_code(val)


class AsyncFoo(BaseFoo):

    async def foo(self):
        val = mymethod()
        return await my_async_code(val)

请注意,Foo.foo 和 AsyncFoo.foo 在类型方面完全不相关。你不能把它们放在基类中,因为覆盖类型不是一个好主意。

© www.soinside.com 2019 - 2024. All rights reserved.