50

結果を返した後、関数でさらに作業を行うことができるかどうか、少し興味がありました。基本的に、入力を処理した後、ピラミッドフレームワーク(Pythonでコーディングしているだけです)を使用してサイトを作成しています。ページをレンダリングするために変数を返しますが、ページをレンダリングした後にさらに作業をしたい場合があります。

たとえば、あなたは私のサイトにアクセスしてプロファイルを更新しますが、気になるのは成功したことだけなので、「成功!」というメッセージを出力します。しかし、その後、更新を取得して、アクティビティログを更新したり、友達のアクティビティストリームを更新したりしたいと思います。現在、気になる結果ステータスを返す前に、これらすべてを実行しています。ユーザーがより早く応答を得ることができるように、後でそれを行うことができるかどうか興味があります。

私は以前にマルチプロセッシングを行ったことがあり、最悪の場合、この作業を行うためにスレッドをフォークするかもしれませんが、returnステートメントの後に作業を行う方法があれば、それはより簡単です。

例:

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

11 に答える 11

39

try-blockから戻った場合でも、戻った後でもいくつかの作業を行うことができます。finally-blockは引き続き実行されます。例:

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

print(fun(5))

期待される出力:

Yay! I still got executed, even though my function has already returned!
100

ドキュメントの引用:

returnがfinally節を含むtryステートメントから制御を渡すと、そのfinally節は、実際に関数を終了する前に実行されます。

于 2012-07-23T00:09:02.387 に答える
20

コンテキストマネージャーを使ってみませんか?それは基本的にあなたが望むことを正確に行います。

これが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

編集:私は物事をテストしていたところですが、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]

コンテキストマネージャーには、反復の停止(およびよりクリーンな構文)に到達するために2回の呼び出しを必要としないという利点がありnextますが、複数の値などを返したい場合は、この方法でも実行できますが、postyieldステートメントを確認できます。ジェネレーターが呼び出しで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
于 2012-07-22T23:15:27.443 に答える
16

いいえ、残念ながら、returnステートメントをヒットすると、関数/メソッドから戻ります(戻り値の有無にかかわらず)。

返品用のドキュメントから:

returnは、現在の関数呼び出しを、式リスト(またはNone)を戻り値として残します。

ジェネレーター関数とyieldステートメントを調べることをお勧めします。これは、関数から値を返し、次に関数が呼び出されたときに返される別の値の処理と準備を続行する方法です。

于 2012-07-22T23:06:10.963 に答える
9
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のスレッド機能を使用します。

まず、更新関数を呼び出します(必要に応じて、応答がこの関数に依存しない場合、およびすぐに応答を返す必要がある場合は、スレッドでこの関数を使用することもできます)。

次に、maintenance_function関数を完了し、終了後に停止するスレッドを作成しました。ただし、その機能が終了するまで応答は遅延しません。

つまり、return "it Worked"が返され、ビットプロセスの場合、スレッドは関数maintainence_functionの動作を維持します。

于 2017-12-27T11:12:50.267 に答える
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)

(response, task)次に、単なる応答ではなく、のペアを期待するように呼び出し元をコーディングします。パーツを使用してすぐに何かを実行し(ユーザーに伝達)、後処理を処理するためresponseに呼び出します。task()

これによりprofile_update、後で実行する必要のあるコードを決定できます(そして、それらの詳細を上位レベルから非表示にしてカプセル化したままにします)が、上位レベルは、ユーザーに応答を伝達し、後処理を実行するフローを決定できます。バックグラウンド。

于 2012-07-23T02:06:02.990 に答える
3

スレッドを使用して別のプロセスを分割する場合のShintoJosephの回答が最も気に入っています。しかし、私はこの例が彼の考えをよりよく例示していると信じています。

import threading
from time import sleep

def math_fun(x):
    # The sleep here is simply to make it clear that this happens in the background
    sleep(1)
    print(x*20)


def fun(x):
    # Create thread to run math_fun for each argument in x 
    t = threading.Thread(target=math_fun, args=[x])
    t.setDaemon(False)
    t.start()

    print("Function has returned!")

fun(5)

期待される出力:

Function has returned!
100
于 2020-08-07T20:11:42.560 に答える
2

を使用してTimer、ある時点で非同期的に発生するイベントをスケジュールできます。イベントが発生するまでの間隔を指定することもできます。以下のコードと出力がお役に立てば幸いです。

import time
from threading import Timer

def func():
    print("Inside func at", time.time())

def schedule_an_event():
    print(time.time())
    Timer(3, func).start()
    return "Done"

print(schedule_an_event())

出力:

1579682455.5378997
Done
Inside func at 1579682458.5382733
于 2020-01-22T08:43:06.767 に答える
0

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例外がキャッチされた場合でも、ステートメントが実行されることに注意してください。

于 2016-10-17T21:14:55.333 に答える
0

私はそれがあなたが探しているものだと思います:

def foo():#何かをやってみよう:最後に何かを返す:#戻った後

于 2019-08-03T22:08:32.250 に答える
0

returnステートメントを指定すると、関数スコープはその時点で終了するため、要求していることは不可能ですが、別のアプローチを試すことができます

def show_status():
  return "it worked"

def profile_update(inputs):
  #take updates and update the database 
  show_status
  #do maintainence processing now..
  return  # when you are done with the maintainence processing 
于 2020-06-10T04:51:20.890 に答える
0

これは古いトピックであり、すでに良い答えがあることを認識していますが、新しいユーザーも私のアイデアを魅力的に感じるかもしれません。

def master_profile_update(inputs):
    # since input parameters are global inside the upper scope
    # i omit them from the arguments of lower nested function:
    def profile_update()
        #take updates and update the database 
        return "it worked"

    profile_update()
    #do maintenance processing now..

デコレータコンテキストマネージャよりも従来型であることがわかりました。

于 2021-08-15T15:50:58.717 に答える