ステートメントとコンテキストマネージャーでPythonを理解しようとしています

StackOverflow https://stackoverflow.com/questions/3693771

  •  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().

コンテキストマネージャーのコンポーネント

  1. andを実装する必要があります __入力__ オブジェクトを返す方法
  2. 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. 。コンテキストマネージャーとしてジェネレーターをラップします。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top