Абстрактный метод асинхронной и синхронизированной реализации в Python

Допустим, у меня есть BaseClass который содержит некоторую логику в main_function() что является общим для обоих SyncClass а также AsyncClass, Допустим, эти 2 класса имеют свою уникальную реализацию get_data() и первый получает синхронно, а второй асинхронно. Я написал что-то вроде этого, и это похоже на работу:

class BaseClass:
    def get_data():
        pass

    @gen.coroutine
    def main_function():
        # some logic
        try:
            data = yield self.get_data()
        except:
            data = self.get_data()
        # some more logic

class SyncClass(BaseClass):
    def get_data():
        //makes sync call to Mongo and gets data (using Mongoengine)

class AsyncClass(BaseClass):
    @gen.coroutine
    def get_data():
        //makes async call to Mongo and gets data (using Motorengine)

Я использовал этот код в качестве обходного пути, потому что у меня уже были те методы для get_data(), реализованные таким образом. Есть ли более элегантное решение? Есть 2 части моего кода, которые касаются меня:

try:
    data = yield self.get_data()
except:
    data = self.get_data()

Я бы предпочел не использовать попробовать / кроме здесь.

Другое дело: у меня есть @gen.coroutine в AsyncClass в то время как та же функция не украшена @gen.coroutine в BaseClass,

Спасибо!

1 ответ

Решение

Синхронные и асинхронные методы имеют разные интерфейсы (вот что значит быть асинхронным). AsyncClass.get_data возвращает Future; SyncClass.get_data не. Если бы это был язык со статической типизацией, эти два метода не смогли бы реализовать один и тот же абстрактный метод из базового класса. Конечно, Python более гибок и не ограничивает вас таким образом, но вызывающему все равно нужно либо знать, с каким методом он имеет дело, либо быть готовым выяснить через try/except или же isinstance проверки и т. д. (обратите внимание, что попытка / исключение в этом случае опасна, yield в торнадо сопрограмма примет такие вещи как списки и диктовки)

В общем, вы не можете прозрачно переключаться между ними, как вы надеетесь сделать здесь. Помните, что любая функция, которая может вызывать yield self.get_data() также должен быть украшен @coroutineпоэтому, как только одна часть вашей системы становится асинхронной, она начинает распространяться. Обычно лучше принять эту тенденцию и сделать ее асинхронной.

Другие вопросы по тегам