ホームページ  >  記事  >  バックエンド開発  >  キーワード「with」とコンテキストマネージャーの詳細説明

キーワード「with」とコンテキストマネージャーの詳細説明

PHPz
PHPzオリジナル
2017-04-23 09:40:221326ブラウズ

ソース コードを読む習慣がある場合は、優れたコードの中に "with" キーワードを含むステートメントが頻繁に出現するのを目にすることがありますが、これは通常どのようなシナリオで使用されますか?今日は with およびコンテキスト マネージャーについて話しましょう。

ファイル、データベース接続、ソケットなどのシステム リソースの場合、アプリケーションがこれらのリソースを開いてビジネス ロジックを実行した後に行う必要があることの 1 つは、リソースを閉じる (切断する) ことです。

たとえば、Python プログラムはファイルを開き、コンテンツをファイルに書き込みます。書き込み後、ファイルを閉じる必要があります。そうしないとどうなりますか?極端な場合、システムが開くことを許可するファイルの最大数が制限されているために、「開いているファイルが多すぎます」エラーが発生することがあります。

同様に、データベースについても、接続が多すぎて時間内に閉じられない場合、「MySQLサーバーに接続できません。接続が多すぎます」というメッセージが表示されることがあります。データベース接続は非常に高価なリソースであり、使用できないためです。それらがなければ制限が生まれます。

ファイルを正しく閉じる方法を見てみましょう。

通常バージョン:

def m1():
    f = open("output.txt", "w")
    f.write("python之禅")
    f.close()

このように書くと潜在的な問題が発生し、write の呼び出し中に例外が発生し、後続のコードの実行を続行できない場合、close メソッドを正常に呼び出すことができないため、リソースが停止します。常にプログラムの占有者が解放されます。では、どうすればコードを改善できるでしょうか?

上級バージョン:

def m2():
    f = open("output.txt", "w")
    try:
        f.write("python之禅")
    except IOError:
        print("oops error")
    finally:
        f.close()

プログラムの改良バージョンでは、try/finally ステートメントを使用して、例外が発生する可能性のあるコードのキャプチャを試行します。つまり、try コード ブロック内のプログラムで例外が発生した場合に、の場合、後続のコードは実行されず、例外コード ブロックに直接ジャンプします。何があっても、finally ブロック内のコードは最終的に実行されます。したがって、finally コードに close が配置されている限り、ファイルは確実に閉じられます。

プレミアム バージョン:

def m3():
    with open("output.txt", "r") as f:
        f.write("Python之禅")

より簡潔でエレガントな方法は、 with キーワードを使用することです。 open メソッドの戻り値は変数 f に割り当てられます。with コード ブロックを終了すると、システムは自動的に f.close() メソッドを呼び出します。with の機能は try/finally ステートメントを使用するのと同じです。それでは、その実装原理は何でしょうか? with の原則について説明する前に、コンテキスト マネージャーという別の概念について説明する必要があります。

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

enter() メソッドと exit() メソッドを実装するあらゆる オブジェクト をコンテキスト マネージャーと呼ぶことができ、コンテキスト マネージャー オブジェクトは with キーワードを使用できます。明らかに、ファイル オブジェクトもコンテキスト マネージャーを実装します。

それでは、ファイル オブジェクトはこれら 2 つのメソッドをどのように実装するのでしょうか?独自のファイル クラスの実装をシミュレートし、そのクラスに

enter() メソッドと exit() メソッドを実装させることができます。

class File():

    def init(self, filename, mode):
        self.filename = filename
        self.mode = mode

    def enter(self):
        print("entering")
        self.f = open(self.filename, self.mode)
        return self.f

    def exit(self, *args):
        print("will exit")
        self.f.close()

enter() メソッドは、開こうとしているファイル オブジェクトであるリソース オブジェクトを返し、exit() メソッドはいくつかのクリーンアップ作業を処理します。

File クラスはコンテキスト マネージャーを実装しているため、with ステートメントを使用できるようになりました。

with File('out.txt', 'w') as f:
    print("writing")
    f.write('hello, python')

このように、明示的に close メソッドを呼び出す必要はなく、途中で例外が発生してもシステムが自動的に close メソッドを呼び出します。

contextlib

Python は、コンテキスト マネージャーの実装をさらに簡素化する contextmanager デコレータも提供します。

関数は、yieldによって2つの部分に分割され、yieldの前のステートメントはenterメソッドで実行され、yieldの後のステートメントはexitメソッドで実行されます。 yield の直後の値が関数の戻り値になります。

from contextlib import contextmanager

@contextmanager
def my_open(path, mode):
    f = open(path, mode)
    yield f
    f.close()

Call

with my_open('out.txt', 'w') as f:
    f.write("hello , the simplest context manager")

概要

Python は、その後のリソース操作のクリア操作を簡素化するための with 構文を提供します。実装原理はコンテキスト マネージャーに基づいています。さらに、Python は、コンテキスト マネージャーの実装をさらに簡素化するために、コンテキスト マネージャー デコレーターも提供します。

以上がキーワード「with」とコンテキストマネージャーの詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。