python中的协程在3.4和3.5之间,如何保持backword的兼容性? [英] Coroutine in python between 3.4 and 3.5, How can I keep backwords compatibility?

查看:89
本文介绍了python中的协程在3.4和3.5之间,如何保持backword的兼容性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用asyncio开发python聊天机器人框架.但是我看到 PEP-492 ,并且有新的语法async/await并最终接受了.

I'm on developing python chatting bot framework with asyncio. But I watch PEP-492 and there is new syntax, async/await and finally it accepted.

我喜欢async/await语法,我想使用它.但我担心3.4个Backwords的兼容性.

I like async/await syntax and I want to use it. but I worry about 3.4 backwords compatibility.

如果我在代码中使用新语法,那么有人可以在3.4中使用它吗?

If I use new syntax in my code, someone can use it in 3.4?

例如,我编写了一些这样的代码,

For example, I write some code like this,

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中的此源一起使用

Than, I can use it with this source in 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上,那么可以正常工作吗?我该如何保存?

But, py34 don't have await syntax. If I uploaded above source at PyPI without version constraint and someone installed it on py34, It'll work fine? How can I keep it?

推荐答案

如果需要在代码中支持Python 3.4,则需要使用旧的@asyncio.coroutine/yield from样式语法.如果不运行3.5,就无法支持async/await语法.您将在编译时获得3.4或更低版本的SyntaxError.

If you need to support Python 3.4 in your code, you'll need to use the old @asyncio.coroutine/yield from style syntax. There's no way to support the async/await syntax without running 3.5; you'll get a SyntaxError at compilation time on 3.4 or lower.

唯一使用向后兼容的新功能的方法是在适当的情况下向类中添加各种__a*__方法(__aiter____aenter____aexit__等),使用yield from协程语法.这样,您的对象可以支持async with/async for语句,以便运行Python 3.5的库用户可以利用这些新功能.

The only thing that takes advantage of the new features you can do in a backwards-compatible way is add the various __a*__ methods to your classes where appropriate (__aiter__, __aenter__, __aexit__, etc.), using the yield from coroutine syntax. That way, your objects can support async with/async for statements, so that users of your library running Python 3.5 could take advantage of the new features.

例如,此类可与async with一起使用,但在Python 3.4上运行时不会中断:

For example, this class can be used with async with, but won't break when run on 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上:

On 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上

On 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的应用程序,那么这可能没有用,但是如果您正在开发打算供其他开发人员使用的库或框架,那是值​​得做的.

This probably isn't useful if you're writing an application that uses asyncio, but if you're developing a library or framework intended to be used by other developers, it's worth doing.

这篇关于python中的协程在3.4和3.5之间,如何保持backword的兼容性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆