返回声明后有没有办法做更多的工作?

Los*_*oul 30 python

如果我能在返回结果后在函数中做更多的工作,我有点好奇.基本上我在使用金字塔框架(简单地在python中编码)创建一个网站后我处理输入我返回变量来呈现页面但有时我想在渲染页面后做更多的工作.

例如,您来到我的网站并更新您的个人资料,所有您关心的是它的成功,所以我输出一条消息说"成功!" 但在完成之后我想接受你的更新并更新你的活动日志,更新你的朋友活动流等等.现在我正在做所有这些,然后我返回你关心的结果状态,但我'我很好奇,如果我能做到这一点,那么用户可以更快地得到他们的回复.

我之前已经完成了多处理,最糟糕的情况是我可能只是分叉一个线程来完成这项工作,但是如果有一种方法在return语句之后继续工作那么那会更简单.

例:

def profile_update(inputs):
  #take updates and update the database 
  return "it worked"
  #do maintainence processing now..
Run Code Online (Sandbox Code Playgroud)

Jef*_*ner 17

你为什么不使用上下文管理器?它基本上完全符合你的要求.

这是Python文档中的规范示例.

from contextlib import contextmanager

@contextmanager
def tag(name):
    print "<%s>" % name
    yield
    print "</%s>" % name
Run Code Online (Sandbox Code Playgroud)

所以对于你的功能,你只需:

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

打电话给你,你只需:

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
Run Code Online (Sandbox Code Playgroud)

编辑:我只是测试了一些事情,事实证明,使用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]
Run Code Online (Sandbox Code Playgroud)

contextmanager的优点是不需要两次next调用来进行stop迭代(和更清晰的语法),但是如果你想返回多个值或者其他东西,你也可以这样做,但你可以看到post yield语句实际上直到生成器在next调用时引发StopIteration 时才会被调用(for循环结束时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
Run Code Online (Sandbox Code Playgroud)


Gie*_*iel 13

如果从try-block返回,你仍然可以在返回后做一些工作,finally块仍然会被执行,例如:

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

引用文档:

当return返回带有finally子句的try语句控制时,该finally子句在真正离开函数之前执行.

  • 但是在调用者收到返回值之前,finally仍会运行*.这不会帮助您允许调用者接收响应并通知用户,但*然后*运行更多代码. (7认同)
  • 根据用例,可能没问题.它可以是一种方便的流控制技术,用于将函数的内容包装在try中,并且具有各种不同的return语句,所有这些语句都会将流直接丢弃到finally块以执行维护. (3认同)
  • @Ben 这对我有用。我在 `try` 块中返回了一个类属性,然后在 `finally` 块中清除了该属性,返回值是正确的。 (2认同)

Lev*_*von 12

不,不幸的是,一旦你点击return语句,你就从函数/方法返回(带或不带返回值).

文档返回:

return使用表达式列表(或None)作为返回值保留当前函数调用.

您可能希望查看生成器函数和yield语句,这是一种从函数返回值并继续处理并准备在下次调用该函数时返回的另一个值的方法.

  • 我认为 yield 在这里没有帮助。使用 yield 的函数生成一系列值,因为它们是对调用结果的迭代所需要的。必须修改调用者以期待函数的序列,将第一项视为响应,然后请求更多值,以便在第一个 yield 之后运行代码。 (2认同)

Shi*_*eph 7

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..
Run Code Online (Sandbox Code Playgroud)

这里我们使用python的线程功能。

首先我们调用更新函数(如果需要,如果响应不依赖于这个函数,如果你需要立即给出响应,你也可以在线程中使用这个函数)。

然后我们创建了一个线程,该线程将完成maintenance_function 函数并在完成后停止。但响应不会延迟,直到该功能完成。

即:返回“它工作”将被返回,然后如果ts一个位进程,线程也会维护函数maintenance_function的工作。


Ben*_*Ben 5

不,返回值会将值返回给调用方并停止。

如果调用方也处于您的控制之下(而不是金字塔框架的一部分),则可以更改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)
Run Code Online (Sandbox Code Playgroud)

然后对调用方进行编码,以期望一对(response, task),而不仅仅是响应。它可以立即处理response零件(将其传达给用户),然后调用task()以处理后处理。

这允许profile_update确定随后需要执行哪些代码(并使这些细节从更高级别隐藏和封装),但允许更高级别确定将响应传达给用户然后在后台执行后处理的流程。背景。