Когда на самом деле будет возвращаться yield в стеке вызовов функций?
Я работаю над торнадо и мотором на питоне 3.4.3.
Я получил три файла. Давайте назовем это как main.py
, model.py
, core.py
У меня есть три функции, по одной в каждой...
main.py
def getLoggedIn(request_handler):
# request_handler = tornado.web.RequestHandler()
db = request_handler.settings["db"]
uid = request_handler.get_secure_cookie("uid")
result = model.Session.get(db, uid=uid)
return result.get("_id", None) if result else None
model.py
@classmethod
def get(cls, db, user_id=None, **kwargs):
session = core.Session(db)
return session.get(user_id, **kwargs)
core.py
@gen.coroutine
def get(self, user_id, **kwargs):
params = kwargs
if user_id:
params.update({"_id": ObjectId(user_id)}) #This does not exist in DB
future = self.collection.find_one(params)
print(future) #prints <tornado.concurrent.Future object at 0x04152A90>
result = yield future
print(result) #prints None
return result
Звонки выглядят как getLoggedIn
=> model.get
=> core.get
core.get украшен @gen.coroutine
и я звоню yield self.collection.find_one(params)
print(result)
печать None
но если я верну результат и попытаюсь напечатать возвращаемое значение в getLoggedIn
Функция это печатает.
Я считаю, что это связано с асинхронной природой торнадо, и печать вызывается раньше, чем доходность, но я не уверен. Было бы очень полезно, если бы кто-то мог объяснить принципы и поведение сопрограмм / генераторов в различных возможных случаях.
2 ответа
Каждый вызов сопрограммы должен быть получен, и вызывающий также должен быть сопрограммой. Так что getLoggedIn должен быть сопрограммой, которая вызывает:
result = yield model.Session.get(db, uid=uid)
И так далее. См. Мою статью о рефакторинге сопрограмм Торнадо для подробного примера и объяснения.
PEP 255 охватывает оригинальную спецификацию для генераторов. Тем не мение, tornado
использования yield
внутри сопрограмм очень специфическим способом: http://www.tornadoweb.org/en/stable/guide/coroutines.html
Ваш код на самом деле не выглядит и не пахнет как обычный генератор, потому что понятие генераторов в Python используется tornado
определить сопрограммы. Я бы сказал, что вам не нужны принципы написания генератора, а принципы генерации торнадо - совершенно другого зверя.
Назначение значения yield
это способ для упаковки @gen.coroutine
декоратор, чтобы передать результат будущего обратно в core.get
, Сюда, result
не назначен будущий объект, но future.result()
,
yield future
по существу приостанавливает вашу функцию и превращает ее в обратный вызов, который future
вызовет, возобновив выполнение в месте расположения yield
, Асинхронная природа tornado
не позволяет yield
бежать до print
, как ты переживаешь.
Скорее всего, ваше будущее ничего не возвращает или возвращает None
(семантически эквивалентно, я знаю). Это может быть лучше думать result = yield future
как специализированная версия result = future.result()