python 协程在 3.4 和 3.5 之间,如何保持向后兼容性?
Coroutine in python between 3.4 and 3.5, How can I keep backwords compatibility?
我正在使用 asyncio
开发 python 聊天机器人框架。但是我看了 PEP-492 并且有新的语法,async
/await
最后它被接受了。
我喜欢 async
/await
语法,我想使用它。但我担心 3.4 backwords 兼容性。
如果我在我的代码中使用新语法,有人可以在 3.4 中使用它吗?
比如我写了这样一段代码,
import asyncio
class ChatBot:
def __init__(self, loop):
self.loop = loop
async def connect(self):
self.reader, self.writer = await asyncio.open_connect(HOST, PORT, loop=self.loop)
async def read():
return await self.reader.read()
async def run(self):
running = True
while running:
try:
await self.connect()
line = await self.read()
if not line:
continue
await self.parse(line)
except BotInternalError as e:
if e.stop:
running = False
break
except:
pass
async def parse(self, msg):
if msg.startswith('PING'):
self.pong()
elif msg.startswith('ERROR'):
self.error()
else:
await self.some_work(msg)
async def some_work(self, msg):
# some looooooooong works
self.send(msg)
def send(self, msg):
self.writer.write(msg)
然后,我可以在 py35
中使用这个源代码
loop = asyncio.get_event_loop() # I don't know it really needed in py35.
bot = ChatBot(loop)
asyncio.run_until_complete(bot.run())
但是,py34 没有 await
语法。如果我在没有版本限制的情况下在 PyPI 上上传以上源代码并且有人将其安装在 py34 上,它会正常工作吗?我怎样才能保留它?
如果您需要在代码中支持 Python 3.4,则需要使用旧的 @asyncio.coroutine
/yield from
样式语法。如果没有 运行ning 3.5,就无法支持 async
/await
语法;你会在 3.4 或更低版本的编译时得到一个 SyntaxError
。
唯一利用您可以以向后兼容的方式执行的新功能的方法是将各种__a*__
方法添加到您的classes 在适当的地方(__aiter__
、__aenter__
、__aexit__
等),使用 yield from
协程语法。这样,您的对象可以支持 async with
/async for
语句,这样您的库 运行ning Python 3.5 的用户就可以利用新功能。
例如,这个 class 可以与 async with
一起使用,但在 运行 上 Python 3.4:
时不会中断
import asyncio
class Test:
def __enter__(self):
return self
def __exit__(self, *args):
print("arg")
@asyncio.coroutine
def __aenter__(self):
yield from self.init_state()
return self
@asyncio.coroutine
def init_state(self):
yield from asyncio.sleep(2) # Pretend this is real initialization
@asyncio.coroutine
def __aexit__(self, *args):
return self.__exit__(self, *args)
在 Python 3.5:
import asyncio
from test import Test
async def main():
print("entering with")
async with Test() as t:
print("in here")
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
在 Python 3.4
import asyncio
from test import Test
@asyncio.coroutine
def oldmain():
print("entering with")
with Test() as t:
yield from t.init_state()
print("in here")
loop = asyncio.get_event_loop()
loop.run_until_complete(oldmain())
如果您正在编写使用 asyncio
的应用程序,这可能没有用,但如果您正在开发旨在供其他开发人员使用的库或框架,则值得这样做。
我正在使用 asyncio
开发 python 聊天机器人框架。但是我看了 PEP-492 并且有新的语法,async
/await
最后它被接受了。
我喜欢 async
/await
语法,我想使用它。但我担心 3.4 backwords 兼容性。
如果我在我的代码中使用新语法,有人可以在 3.4 中使用它吗?
比如我写了这样一段代码,
import asyncio
class ChatBot:
def __init__(self, loop):
self.loop = loop
async def connect(self):
self.reader, self.writer = await asyncio.open_connect(HOST, PORT, loop=self.loop)
async def read():
return await self.reader.read()
async def run(self):
running = True
while running:
try:
await self.connect()
line = await self.read()
if not line:
continue
await self.parse(line)
except BotInternalError as e:
if e.stop:
running = False
break
except:
pass
async def parse(self, msg):
if msg.startswith('PING'):
self.pong()
elif msg.startswith('ERROR'):
self.error()
else:
await self.some_work(msg)
async def some_work(self, msg):
# some looooooooong works
self.send(msg)
def send(self, msg):
self.writer.write(msg)
然后,我可以在 py35
中使用这个源代码loop = asyncio.get_event_loop() # I don't know it really needed in py35.
bot = ChatBot(loop)
asyncio.run_until_complete(bot.run())
但是,py34 没有 await
语法。如果我在没有版本限制的情况下在 PyPI 上上传以上源代码并且有人将其安装在 py34 上,它会正常工作吗?我怎样才能保留它?
如果您需要在代码中支持 Python 3.4,则需要使用旧的 @asyncio.coroutine
/yield from
样式语法。如果没有 运行ning 3.5,就无法支持 async
/await
语法;你会在 3.4 或更低版本的编译时得到一个 SyntaxError
。
唯一利用您可以以向后兼容的方式执行的新功能的方法是将各种__a*__
方法添加到您的classes 在适当的地方(__aiter__
、__aenter__
、__aexit__
等),使用 yield from
协程语法。这样,您的对象可以支持 async with
/async for
语句,这样您的库 运行ning Python 3.5 的用户就可以利用新功能。
例如,这个 class 可以与 async with
一起使用,但在 运行 上 Python 3.4:
import asyncio
class Test:
def __enter__(self):
return self
def __exit__(self, *args):
print("arg")
@asyncio.coroutine
def __aenter__(self):
yield from self.init_state()
return self
@asyncio.coroutine
def init_state(self):
yield from asyncio.sleep(2) # Pretend this is real initialization
@asyncio.coroutine
def __aexit__(self, *args):
return self.__exit__(self, *args)
在 Python 3.5:
import asyncio
from test import Test
async def main():
print("entering with")
async with Test() as t:
print("in here")
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
在 Python 3.4
import asyncio
from test import Test
@asyncio.coroutine
def oldmain():
print("entering with")
with Test() as t:
yield from t.init_state()
print("in here")
loop = asyncio.get_event_loop()
loop.run_until_complete(oldmain())
如果您正在编写使用 asyncio
的应用程序,这可能没有用,但如果您正在开发旨在供其他开发人员使用的库或框架,则值得这样做。