Coroutine в python между 3.4 и 3.5, Как я могу сохранить совместимость с паролями?

Я занимаюсь разработкой poton chatting bot framework с помощью asyncio. Но я смотрю PEP-492 и появляется новый синтаксис async/await и, наконец, он принят.

Мне нравится синтаксис async/await, и я хочу его использовать. но я беспокоюсь о совместимости с 3.4 паролями.

Если я использую новый синтаксис в своем коде, кто-то может использовать его в 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, он будет работать нормально? Как я могу его сохранить?

Ответ 1

Если вам нужно поддерживать Python 3.4 в коде, вам нужно использовать старый синтаксис стиля @asyncio.coroutine/yield from. Невозможно поддерживать синтаксис async/await без запуска 3.5; вы получите SyntaxError во время компиляции 3.4 или ниже.

Единственное, что использует новые функции, которые вы можете сделать с обратной совместимостью, - это добавить различные методы __a*__ к вашим классам (__aiter__, __aenter__, __aexit__ и т.д.).), используя синтаксис yield from coroutine. Таким образом, ваши объекты могут поддерживать операторы async with/async for, чтобы пользователи вашей библиотеки, на которой запущен Python 3.5, могли воспользоваться новыми функциями.

Например, этот класс может использоваться с 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, но если вы разрабатываете библиотеку или структуру, предназначенную для использования другими разработчиками, это стоит того.