我正在为 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
问题:重载异步方法
考虑以下
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
使用不涉及异步的所有内容的继承来实现要好得多。这避免了 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 在类型方面完全不相关。你不能把它们放在基类中,因为覆盖类型不是一个好主意。