Python の with ステートメントとコンテキスト マネージャー

高洛峰
リリース: 2017-03-01 14:15:40
オリジナル
1235 人が閲覧しました

Python のコンテキスト マネージャー オブジェクトとして、with ステートメントを使用できます。コンテキスト マネージャーを提供する contextlib モジュールの使用は、Python プログラミングの高度なスキルです。Python での with ステートメントとコンテキスト マネージャーの学習を詳しく見てみましょう。概要:

0. コンテキストマネージャーについて
コンテキストマネージャーは with ステートメントで使用できるオブジェクトであり、__enter__ メソッドと __exit__ メソッドがあります。

with manager as var:
  do_something(var)
ログイン後にコピー

は、次の簡略化に相当します。

var = manager.__enter__()
try:
  do_something(var)
finally:
  manager.__exit__()
ログイン後にコピー

つまり、PEP 343 で定義されているコンテキスト マネージャー プロトコルを使用すると、退屈な try...excited...finally 構造を単一の構造に抽象化できます。クラスには、懸念される do_something の部分だけが残ります。

__enter__ メソッドが最初に呼び出されます。 var に割り当てられた値を返すことができます。 as 部分はオプションです。これが表示されない場合、enter の戻り値は単に無視されます。
with ステートメントの下のコードが実行されます。 try 句と同様に、これらは正常に実行されるか、中断、継続、または戻るか、または例外をスローする可能性があります。どちらの場合も、ブロックが終了すると、__exit__ メソッドが呼び出されます。例外がスローされた場合、例外情報は __exit__ に渡されます。これについては次のセクションで説明します。通常、例外は、finally 句のように無視でき、__exit__ の終了後に再スローされます。
書き込み操作が完了した直後にファイルが閉じられるようにしたいとします:

>>> class closing(object):
...  def __init__(self, obj):
...   self.obj = obj
...  def __enter__(self):
...   return self.obj
...  def __exit__(self, *args):
...   self.obj.close()
>>> with closing(open('/tmp/file', 'w')) as f:
...  f.write('the contents\n')
ログイン後にコピー

ここでは、with ブロックが終了するときに f.close() が呼び出されることを確認します。ファイルを閉じることは非常に一般的な操作であるため、このサポートはファイル クラスにすでに存在しています。これには、close を呼び出し、コンテキスト マネージャー自体として機能する __exit__ メソッドがあります。

>>> with open('/tmp/file', 'a') as f:
...  f.write('more contents\n')
ログイン後にコピー

try...finally の一般的な使用法は、リソースを解放することです。さまざまな状況は同様に実装されます。リソースは __enter__ フェーズで取得され、 __exit__ フェーズで解放され、例外がスローされた場合には例外も渡されます。ファイル操作と同様、これは多くの場合、オブジェクトを使用した後の自然な操作であり、組み込みのサポートによって便利になります。バージョンが上がるごとに、Python がサポートされる場所が増えています。

1. コンテキストマネージャーの使用方法:

ファイルを開いて「hello world」を書き込む方法

filename="my.txt"
mode="w"
writer=open(filename,mode)
writer.write("hello world")
writer.close()
ログイン後にコピー

例外が発生した場合(ディスクがいっぱいであるなど)、チャンスはありません。ステップ 5 を実行します。OK。もちろん、パッケージ化に try-finally ステートメント ブロックを使用できます:

writer=open(filename,mode)
try:
  writer.write("hello world")
finally:
  writer.close()
ログイン後にコピー

複雑な操作を実行すると、try-finally ステートメントは醜くなり、with ステートメントを使用して書き換えられます:

with open(filename,mode) as writer:
  writer.write("hello world")
ログイン後にコピー

as は、open() 関数から返されたコンテンツを参照し、それを新しい値に割り当てます。 with は try-finally のタスクを完了します。

2. カスタム コンテキスト マネージャー

with ステートメントは try-finally に似ており、コンテキスト メカニズムを提供します。 with ステートメントを適用するには、クラスで 2 つの組み込み関数 __enter__ と __exit__ を提供する必要があります。前者はメインコードが実行される前に実行され、後者はメインコードが実行された後に実行されます。 as の後の変数は __enter__ 関数で返されます。

class echo():
  def output(self):
    print "hello world"
  def __enter__(self):
    print "enter"
    return self #可以返回任何希望返回的东西
  def __exit__(self,exception_type,value,trackback):
    print "exit"
    if exception_type==ValueError:
      return True
    else:
      return Flase
 
>>>with echo as e:
  e.output()
ログイン後にコピー


出力:

enter
hello world
exit
ログイン後にコピー

完全な __exit__ 関数は次のとおりです:

def __exit__(self,exc_type,exc_value,exc_tb)
ログイン後にコピー

その中で、exc_type: exc_value:例外値; exc_tb: 例外の追跡情報

__exit__ が True を返す場合、例外は伝播されません

3. contextlib モジュール

contextlib モジュールの役割は、Generator を通じて実装される、使いやすいコンテキスト マネージャーを提供することです。 contextlib の contextmanager は、関数レベルのコンテキスト管理メカニズムを提供するデコレーターとして機能します。一般的に使用されるフレームワークは次のとおりです。

from contextlib import contextmanager
@contextmanager
def make_context():
  print 'enter'
  try:
    yield "ok"
  except RuntimeError,err:
    print 'error',err
  finally:
    print 'exit'
    
>>>with make_context() as value:
  print value
ログイン後にコピー


出力は次のとおりです。 try-finally として記述されます。例外の安全性を確保する (例外を処理できる) ため、as の後の変数の値が yield によって返されます。 yield より前のステートメントはコード ブロックが実行される前の操作とみなすことができ、yield の後の操作は __exit__ 関数内の操作とみなすことができます。

スレッドロックを例に挙げます:

  enter
  ok
  exit
ログイン後にコピー

4. contextlib.nested: ネストを減らす

対象:

@contextlib.contextmanager
def loudLock():
  print 'Locking'
  lock.acquire()
  yield
  print 'Releasing'
  lock.release()
 
with loudLock():
  print 'Lock is locked: %s' % lock.locked()
  print 'Doing something that needs locking'
 
#Output:
#Locking
#Lock is locked: True
#Doing something that needs locking
#Releasing
ログイン後にコピー

はcontextlib.nestedで簡素化できます:

りー

Python 2.7 以降では、新しい構文に置き換えられます:

with open(filename,mode) as reader:
  with open(filename1,mode1) as writer:
    writer.write(reader.read())
ログイン後にコピー

5, contextlib.closed()

ファイル クラスはコンテキスト マネージャー API を直接サポートしていますが、一部のオブジェクトはオープン ハンドルを表します サポートされていませんurllib.urlopen() によって返されるオブジェクトなど。 close() メソッドを使用するが、コンテキスト マネージャー API をサポートしていないレガシー クラスもいくつかあります。ハンドルが確実に閉じられるようにするには、closed() (クラスの close メソッドを呼び出す) を使用してハンドルのコンテキスト マネージャーを作成する必要があります。

with contextlib.nested(open(filename,mode),open(filename1,mode1)) as (reader,writer):
  writer.write(reader.read())
ログイン後にコピー

出力:

with open(filename,mode) as reader,open(filename1,mode1) as writer:
  writer.write(reader.read())
ログイン後にコピー



Python の with ステートメントとコンテキスト マネージャーに関連するその他の記事については、PHP 中国語 Web サイトに注目してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!