Когда на самом деле будет возвращаться 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()

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