24

私はその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.")

これをコンテキストマネージャーに置き換えるにはどうすればよいですか?

4

5 に答える 5

30

withtry/を実際に置き換える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

于 2010-09-12T04:46:40.130 に答える
27

contextlib.contextmanager関数デコレータは、独自の本格的なクラスを作成する必要なしに、コンテキストマネージャを提供する便利な方法を提供します(メソッドを使用するため、メソッドへの引数を覚えておく必要はありません。メソッドは例外を抑制するために必要です)。代わりに、ブロックを実行するポイントで単一の関数を記述し、通常どおりに例外(事実上から発生する)をトラップします。ContextManager__enter____exit____exit____exit__return Trueyieldwithyield

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

なぜコンテキストマネージャーを書くという余分な問題に取り組むのですか?コードの再利用。例外処理を複製することなく、同じコンテキストマネージャーを複数の場所で使用できます。例外処理がその状況に固有である場合は、コンテキストマネージャーを気にしないでください。しかし、同じパターンが何度も現れる場合(または、ファイルを閉じる、ミューテックスのロックを解除するなど、ユーザーにとってはそうかもしれない場合)、追加の問題を起こす価値があります。また、例外処理がコードフローのメインラインから分離されるため、例外処理が少し複雑な場合に使用するのも適切なパターンです。

于 2013-08-01T19:48:18.633 に答える
15

Pythonのwithinは、リソースを設定して破棄または閉じる必要がある一連のステートメントをラップすることを目的としています。try...finallyこれは、例外の後でもfinally句が実行されるという点で似ています。

__enter__コンテキストマネージャーは、との2つのメソッドを実装するオブジェクトです__exit__withそれらは(それぞれ)ブロックの直前と直後に呼び出されます。

たとえば、古典的な例を見てみましょうopen()

with open('temp.txt', 'w') as f:
    f.write("Hi!")

Openは、多かれ少なかれlikeとlikeFileを実装するオブジェクトを返します。__enter__return self__exit__self.close()

于 2010-09-12T04:47:15.027 に答える
9

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

  1. オブジェクトを返す__enter__メソッドを実装する必要があります
  2. __exit__メソッドを実装します。

コンテキストマネージャーが必要な理由を示す簡単な例を示します。中国の新疆ウイグル自治区の冬の間は、ドアを開けたらすぐにドアを閉める必要があります。閉めるのを忘れると寒くなります。

 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

説明

Doorクラスを開始すると、「家にいないときにドアが閉じられました」と出力する__init__メソッドと、「ドアを開けました」と出力してdrというドアインスタンスを返す__enter__メソッドが呼び出されます。ブロックでself.fetchsomethingsを呼び出すと、メソッドは「I have fetchedsomethings」を出力します。ブロックが終了すると、コンテキストマネージャーは__exit__ メソッドを呼び出し、「pong!thedoorhasclosed」を出力します。キーワードと一緒に使用すると、__enter____exit__は呼び出されません!!!!

于 2017-03-06T10:42:24.290 に答える
5

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は終了時にハンドルをクリーンアップし、ハンドルはプログラムと一緒に解放されますが、それを当てにするべきではありません)

withステートメントは、インデントを残すとすぐにファイルハンドルを閉じることを保証します。

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にあります。ジェネレーターをコンテキストマネージャーとしてラップします。

于 2016-04-12T06:42:47.353 に答える