Есть ли способ сделать больше работы после заявления возврата? - программирование
Подтвердить что ты не робот

Есть ли способ сделать больше работы после заявления возврата?

Мне было немного любопытно, если бы я мог больше работать в функции после возвращения результата. В основном я создаю сайт, использующий каркас пирамиды (который просто кодируется в python) после обработки входных данных. Я возвращаю переменные для рендеринга страницы, но иногда я хочу сделать больше работы после того, как сделаю страницу.

Например, вы приходите на мой сайт и обновляете свой профиль, и все, о чем вы заботитесь, это то, что он успешно работает, поэтому я выводил сообщение с сообщением "успех!". но после этого я хочу принять ваше обновление и обновить журналы активности, что вы делаете, обновить потоки активности ваших друзей и т.д. Сейчас я делаю все это, прежде чем возвращать статус результата, который вас волнует, m любопытно, могу ли я это сделать после того, как пользователи быстрее получат ответы.

Я делал многопроцессорную обработку до и в худшем случае, я мог бы просто разветкить поток для выполнения этой работы, но если бы был способ выполнить работу после оператора return, это было бы проще.

Пример:

def profile_update(inputs):
  #take updates and update the database 
  return "it worked"
  #do maintainence processing now..
4b9b3361

Ответ 1

Нет, к сожалению, как только вы попадаете в оператор return, вы возвращаетесь из функции/метода (либо с возвращаемым значением, либо без него).

Из docs для возврата:

возвращает текущий вызов функции с листом выражения (или None) в качестве возвращаемого значения.

Вы можете посмотреть в функции генератора и инструкцию yield, это способ вернуть значение из функции и продолжить обработку и подготовку другого значения, которое будет возвращено, когда функция будет вызвана в следующий раз.

Ответ 2

Почему бы вам не использовать contextmanager? Это в основном делает именно то, что вы хотите.

Вот канонический пример из документов Python.

from contextlib import contextmanager

@contextmanager
def tag(name):
    print "<%s>" % name
    yield
    print "</%s>" % name

Итак, для вашей функции вы просто выполните:

@contextmanager
def profile_update(inputs):
  #take updates and update the database 
  yield "it worked"
  #do maintainence processing now..

И чтобы назвать это, вы просто выполните:

with profile_update(inputs) as result: #pre-yield and yield here
    # do whatever while in scope
# as you move out of scope of with statement, post-yield is executed

EDIT: я просто тестировал вещи, и получается, что с оператором yield функция все еще выполняется до конца. Вот тупой пример, который иллюстрирует точку и когда дела выполняются.

def some_generator(lst):
    for elem in lst:
        yield elem
    lst[0] = "I WAS CHANGED POST-YIELD!!!!"

>>> q = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> gen = some_generator(q)
>>> for e in gen:
...    print e, q

0 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
2 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
3 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
4 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
5 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
6 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
7 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
8 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
9 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

print q
['I WAS CHANGED POST YIELD!!!', 1, 2, 3, 4, 5, 6, 7, 8, 9]

Контекст-менеджер имеет то преимущество, что не требует двух вызовов next для перехода к итерации остановки (и более чистого синтаксиса), но если вы хотите вернуть несколько значений или что-то еще, вы также можете сделать это таким образом, но вы можете см., что оператор post yield фактически не вызывается до тех пор, пока генератор не вызовет StopIteration при вызове next (цикл for заканчивается, когда он получает StopIteration)


Если по какой-то причине вам требуется более высокая степень контроля, чем @contextmanager, вы также можете определить класс с методами __enter__ и __exit__:

class MyContextClass(object):
    # ...

    def __enter__(self):
        # do some preprocessing
        return some_object

    def __exit__(self, exc_type, exc_value, traceback):
        # do some post processing
        # possibly do some processing of exceptions raised within the block
        if exc_type == MyCustomErrorType:
            return True #don't propagate the error

Ответ 3

Вы можете выполнить некоторую работу после возврата, если вы вернетесь из блока try, блок finally все равно будет выполнен, например:

def fun():
    try:
        return
    finally:
        print "Yay! I still got executed, even though my function has already returned!"

Цитата документы:

Когда return передает управление из инструкции try с окончательным, что окончательное предложение выполняется до того, как оно действительно покинет функция.

Ответ 4

Нет, возврат возвращает значение вызывающему и останавливается.

Если вызывающий (-ы) также находится под вашим контролем (не является частью структуры пирамиды), вы можете изменить profile_updates, чтобы выглядеть следующим образом:

def profile_update(inputs):
    #take updates and update the database 
    def post_processing_task():
        #do maintainence processing now..
    return ("it worked", post_processing_task)

И затем закодируйте вызывающего абонента, чтобы ожидать пару (response, task), а не только ответ. Он может сделать что-то сразу с частью response (сообщить об этом пользователю), а затем вызвать task() для обработки пост-обработки.

Это позволяет profile_update определить, какой код необходимо выполнить впоследствии (и сохранить эти данные скрытыми и инкапсулированными с более высокого уровня), но позволяет более высокому уровню определять поток передачи ответа пользователю, а затем выполнять пост-обработка в фоновом режиме.

Ответ 5

import threading

def profile_update(inputs):

    # call function to take updates and update the database 
    update_function(inputs)

    # call the maintainence_function here
    t = threading.Thread(target=maintainence_function, args=[input1, input2])
    # setDaemon=False to stop the thread after complete
    t.setDaemon(False)
    # starting the thread
    t.start()

    # return response/anything-else you want to return
    return "it worked"



def update_function(inputs):
    # updating the database process here

def maintainence_function(input1, input2):
    #do maintainence processing now..

Здесь мы используем функции потоковой передачи python.

Сначала мы вызываем функцию обновления (вы также можете использовать эту функцию в потоке, если это необходимо, и если ответ не зависит от этой функции, и если вам нужно немедленно дать ответ).

Затем мы создаем поток, который завершит функцию поддержания и функции после завершения. Но ответ не будет отложен, пока эта функция не будет завершена.

то есть: return "it works" будет возвращен, а затем также будет поддерживаться работа функции maintainence_function, если ts бит процесс.

Ответ 6

Можно обмануть структуру try-except-finally. Пример:

def function():
  try:
    #do some stuff here
    return x
  except Exception:
    #do something when an error occures
  finally:
    #do here whatever you wanna do after return

Обратите внимание, что оператор finally будет выполнен, даже если было обнаружено исключение.