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