ステートメントとコンテキストマネージャーでPythonを理解しようとしています
-
02-10-2019 - |
質問
私はこれに慣れていません、そしてただ理解しようとしています with
声明。私はそれが置き換えることになっていることを理解しています try
/except
ブロック。
今、私がこのようなことをするとします:
try:
name='rubicon'/2 # to raise an exception
except Exception as e:
print "no not possible"
finally:
print "Ok I caught you"
これをコンテキストマネージャーに置き換えるにはどうすればよいですか?
解決
with
本当に置き換えられません try
/except
, 、 むしろ、 try
/finally
. 。それでも、あなた できる コンテキストマネージャーに、例外のケースとは異なることをしてもらいます。
class Mgr(object):
def __enter__(self): pass
def __exit__(self, ext, exv, trb):
if ext is not None: print "no not possible"
print "OK I caught you"
return True
with Mgr():
name='rubicon'/2 #to raise an exception
return True
一部は、コンテキストマネージャーが例外を抑制することを決定した場所です(あなたがそうするように、あなたの中でそれを再審理しないことによって except
句)。
他のヒント
ContextLib.ContextManager 機能デコレーターは、本格的なものを書く必要なく、コンテキストマネージャーを提供する便利な方法を提供します ContextManager
あなた自身のクラス(と __enter__
と __exit__
方法なので、 __exit__
方法、またはそれ __exit__
メソッドは必要です return True
例外を抑制するため)。代わりに、単一の関数を書きます yield
あなたが望む時点で with
実行するブロック、そしてあなたは例外をトラップします(それは事実上から来ます yield
)あなたが通常そうするように。
from contextlib import contextmanager
@contextmanager
def handler():
# Put here what would ordinarily go in the `__enter__` method
# In this case, there's nothing to do
try:
yield # You can return something if you want, that gets picked up in the 'as'
except Exception as e:
print "no not possible"
finally:
print "Ok I caught you"
with handler():
name='rubicon'/2 #to raise an exception
なぜコンテキストマネージャーを書くための余分なトラブルに行くのですか?コードの再利用。例外処理を複製することなく、複数の場所で同じコンテキストマネージャーを使用できます。例外処理がその状況に固有の場合は、コンテキストマネージャーを気にしないでください。しかし、同じパターンが何度も繰り返される場合(または、ユーザーがファイルを閉じてMutexのロックを解除する可能性がある場合)、それは余分な問題に値します。また、例外処理がコードフローのメインラインから分離されているため、例外処理が少し複雑な場合に使用するのはきちんとしたパターンです。
with
Pythonでは、リソースを設定および破壊または閉鎖する必要がある一連のステートメントを包むことを目的としています。それはに似ています try...finally
その点で、最終句は例外の後でも実行されます。
コンテキストマネージャーは、2つの方法を実装するオブジェクトです。 __enter__
と __exit__
. 。それらは(それぞれ)直前と直後と呼ばれます with
ブロック。
たとえば、クラシックをご覧ください open()
例:
with open('temp.txt', 'w') as f:
f.write("Hi!")
オープンリターンa File
実装するオブジェクト __enter__
多かれ少なかれ return self
と __exit__
お気に入り self.close()
.
コンテキストマネージャーのコンポーネント
- andを実装する必要があります __入力__ オブジェクトを返す方法
- a __出口__ 方法。
例
コンテキストマネージャーが必要な理由を示す簡単な例を示します。中国の新jiangの冬の間、ドアを開けるときはすぐにドアを閉めるべきです。閉じるのを忘れた場合、寒くなります。
class Door:
def __init__(self):
self.doorstatus='the door was closed when you are not at home'
print(self.doorstatus)
def __enter__(self):
print('I have opened the door')
return self
def __exit__(self,*args):
print('pong!the door has closed')
def fetchsomethings(self):
print('I have fetched somethings')
自宅で物事を取得するときは、ドアを開けて、何かを取得し、ドアを閉める必要があります。
with Door() as dr:
dr.fetchsomethings()
出力は次のとおりです。
the door was closed when you are not at home
I have opened the door
I have fetched somethings
pong!the door has closed
説明
ドアクラスを開始すると、 __初期化__ 「家にいないときにドアが閉じられた」と印刷する方法と __入力__ 「私はドアを開けた」を印刷し、DRと呼ばれるドアインスタンスを返す方法。電話するとき self.fetchsomethings ブロックを使用して、メソッドは「私は何かを取得しました」を印刷します。ブロックが終了すると、コンテキストマネージャーが呼び出します __出口__方法とそれは「Pong!The Doorが閉じている」と印刷します。キーワードで使用しない場合、__入力__と __出口__ 呼び出されません!!!!
with
ステートメントまたはコンテキストマネージャーは、リソースを支援するためにそこにいます(ただし、さらに多くの場合に使用される場合があります)。
書くためのファイルを開いたとしましょう。
f = open(path, "w")
これで、オープンファイルハンドルができました。ファイルの処理中、他のプログラムはそれに書き込むことはできません。他のプログラムを書くには、ファイルハンドルを閉じる必要があります。
f.close()
しかし、ファイルを閉じる前にエラーが発生しました。
f = open(path, "w")
data = 3/0 # Tried dividing by zero. Raised ZeroDivisionError
f.write(data)
f.close()
今起こるのは、ファイルを開いたハンドルで残しながら、機能またはプログラム全体が終了することです。 (CPYTHONは終了時にハンドルをクリーニングし、ハンドルはプログラムと一緒に解放されますが、それを頼りにしてはいけません)
A声明では、インデントを離れるとすぐに、ファイルハンドルが閉じることが保証されます。
with open(path, "w") as f:
data = 3/0 # Tried dividing by zero. Raised ZeroDivisionError
f.write(data)
# In here the file is already closed automatically, no matter what happened.
with
声明は、さらに多くのことに使用される場合があります。例えば: threading.Lock()
lock = threading.Lock()
with lock: # Lock is acquired
do stuff...
# Lock is automatically released.
コンテキストマネージャーで行われたほとんどすべてが行うことができます try: ... finally: ...
しかし、コンテキストマネージャーは使用がより良い、より快適で、より読みやすく、実装して __enter__
と __exit__
使いやすいインターフェイスを提供します。
コンテキストマネージャーの作成は、実装することによって行われます __enter__()
と __exit__()
通常のクラスで。
__enter__()
コンテキストマネージャーが起動したときに何をすべきかを教えて __exit__()
コンテキストマネージャーが存在する場合( __exit__()
方法例外が発生した場合)
コンテキストマネージャーを作成するためのショートカットは、 ContextLib. 。コンテキストマネージャーとしてジェネレーターをラップします。