我有一个具有多种配置库的应用程序:
目前,我的代码几乎与所有三个代码相同,但每个函数调用的调用方式都有细微的差别。这意味着我有大量的代码重复,因为我在很多地方都有类似的东西:
#Python2.7native.py
def main(client):
client.foo(args)
client.bar(args)
#Python2.7tornado.py
@gen.coroutine
def main(client):
yield client.foo(args)
yield client.bar(args)
#Python3.5asyncio.py
async def main(client):
await client.foo(args)
await client.bar(args)
其中client
是一种特定于语言的实现,分别支持本机python,asyncio和tornado。 API方法调用是相同的。
我希望能够以某种方式将其概括为我可以包含在共享文件中的单个方法,该文件适当地调用各种方法
我已经考虑过在单独的文件中定义方法并使用getattr
来正确调用测试,但这看起来非常麻烦。
有没有好办法呢?
答案 0 :(得分:1)
你无法在一个功能中完成所有这些工作 - client.foo()
如何知道是否正在从#"正常"同步应用程序,或其调用者是否将使用yield
或await
。但是,只要您愿意将Tornado作为依赖项,就可以避免将所有代码重复三次。
在一个模块client_async.py
中,使用Tornado @gen.coroutine
实现您的功能:
@gen.coroutine
def foo(args):
yield something()
yield something_else()
raise gen.Return(another_thing())
在另一个client_sync.py
中,将client_async.py
中的IOLoop.run_sync()
中的每个函数包装成一个线程局部IOLoop,如下所示:
import client_async
import threading
import tornado.ioloop
class _LocalIOLoop(threading.local):
def __init__(self):
self.value = tornado.ioloop.IOLoop()
local_ioloop = _LocalIOLoop()
def foo(args):
return local_ioloop.value.run_sync(lambda: foo_async.my_func(args))
现在您可以在所有三种环境中使用此代码。从普通的同步代码:
import client_sync
def main():
x = client_sync.foo(args)
来自龙卷风@gen.coroutine
:
import client_async
@gen.coroutine
def main():
x = yield client_async.foo(args)
来自async def
和asyncio
(请注意,这两者不是同义词 - 可以在没有async def
的情况下将asyncio
与Tornado一起使用):
# one-time initialization for Tornado/asyncio integration
import tornado.platform.asyncio
tornado.platform.asyncio.AsyncIOMainLoop().install()
import client_async
async def main():
x = await client_async.foo(args)
答案 1 :(得分:-1)
使用@gen.coroutine
和yield
:这适用于所有Python版本。用gen.coroutine
装饰的函数比原始协程慢一点,但可以在所有相同的场景中使用。
对于同步案例,请使用run_sync
:
result = IOLoop.current().run_sync(main)