Абстрактный метод асинхронной и синхронизированной реализации в 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
поэтому, как только одна часть вашей системы становится асинхронной, она начинает распространяться. Обычно лучше принять эту тенденцию и сделать ее асинхронной.