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

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

Y2J
Y2Jオリジナル
2017-05-02 16:04:231381ブラウズ

この記事では、主に Python のキーワード「with」とコンテキストマネージャーに関する情報を紹介しています。この記事の紹介は、Python を学習したり使用したりする人にとって、一定の参考になると思います。一緒に見てください。

はじめに

ソースコードを読む習慣がある人は、優れたコードの中に "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", "w") as f:
 f.write("Python之禅")

より簡潔でエレガントな方法は、 with キーワードを使用することです。 open メソッドの戻り値は変数 f に割り当てられます。with コード ブロックを終了すると、システムは自動的に f.close() メソッドを呼び出します。with の機能は使用する場合と同じです。 try/finally ステートメント。それでは、その実装原理は何でしょうか? f.close() 方法, with 的作用和使用 try/finally 语句是一样的。那么它的实现原理是什么?

在讲 with 的原理前要涉及到另外一个概念,就是上下文管理器(Context Manager)。

上下文管理器

任何实现了 __enter__() __exit__() 方法的对象都可称之为上下文管理器,上下文管理器对象可以使用 with 关键字。显然,文件(file)对象也实现了上下文管理器。

那么文件对象是如何实现这两个方法的呢?我们可以模拟实现一个自己的文件类,让该类实现 __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 将函数分割成两部分,yield 之前的语句在 __enter__ 方法中执行,yield 之后的语句在 __exit__

with の原則について話す前に、コンテキスト マネージャーという別の概念について説明する必要があります。

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

__enter__() メソッドと __exit__() メソッドを実装するオブジェクトはすべて、コンテキストマネージャーと呼ぶことができます。 オブジェクトが使用できるコンテキストマネージャー。 with キーワード。明らかに、ファイル オブジェクトもコンテキスト マネージャーを実装します。 🎜🎜それでは、ファイル オブジェクトはこれら 2 つのメソッドをどのように実装するのでしょうか?独自のファイル クラスの実装をシミュレートし、そのクラスに __enter__() メソッドと __exit__() メソッドを実装させることができます。 🎜
from contextlib import contextmanager

@contextmanager
def my_open(path, mode):
 f = open(path, mode)
 yield f
 f.close()
🎜 __enter__() メソッドは、開こうとしているファイル オブジェクトであるリソース オブジェクトを返します。 __exit__() メソッドは、いくつかのクリーンアップ作業を処理します。 🎜🎜File クラスはコンテキスト マネージャーを実装しているため、with ステートメントを使用できるようになりました。 🎜
with my_open('out.txt', 'w') as f:
 f.write("hello , the simplest context manager")
🎜こうすることで、明示的に close メソッドを呼び出す必要がなく、途中で例外が発生した場合でもシステムが自動的に close メソッドを呼び出します。 🎜🎜🎜🎜contextlib🎜🎜🎜🎜Python は、コンテキスト マネージャーの実装をさらに簡素化する contextmanager デコレーターも提供します。関数は、yield によって 2 つの部分に分割されます。yield の前のステートメントは __enter__ メソッドで実行され、yield の後のステートメントは __exit__ メソッドで実行されます。 yield の直後の値が関数の戻り値になります。 🎜rrreee🎜電話🎜rrreee🎜🎜🎜概要🎜🎜🎜

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

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