GeeksforGeeks
リソースの管理:どのプログラミング言語でも、ファイル操作やデータベース接続などのリソースの使用は非常に一般的 しかし、これらの資源は供給が限られています。 したがって、主な問題は、使用後にこれらのリソースを確実に解放することにあります。 それらが解放されなければ資源の漏出をもたらし、システムを減速するか、または衝突させるかもしれません。 ユーザーがリソースの自動設定とティアダウンのためのメカニズムを持っている場合、それは非常に参考になります。Pythonでは、リソースの適切な処理を容易にするコンテキストマネージャの使用によって達成することができます。 ファイル操作を実行する最も一般的な方法は、以下に示すようにwithキーワードを使用することです:
with
open
(
"test.txt"
) as f:
data
=
f.read()
Let’s take the example of file 管理。 ファイルが開かれると、限られたリソースであるファイル記述子が消費されます。 一度にプロセスで開くことができるファイルの数は、特定の数だけです。 次のプログラムはそれを示しています。
file_descriptors
=
for
x
in
range
(
100000
):
file_descriptors.append(
open
(
'test.txt'
,
出力:
Traceback (most recent call last): File "context.py", line 3, in OSError: Too many open files: 'test.txt'
開いているファイルが多すぎることを示すエラーメッセージ。 上記の例は、ファイル記述子のリークの場合です。 そこにあまりにも多くの開いているファイルがあり、それらが閉じられていないので、それが発生します。 プログラマが開いているファイルを閉じるのを忘れる可能性があります。
コンテキストマネージャを使用したリソースの管理 :
コードブロックが例外を発生させたり、複数の戻りパスを持つ複雑なアルゴリズムがある場合、すべての場所でファイルを閉じるのが面倒にな
一般的に他の言語では、ファイルを操作するときtry-except-finallyは、例外があっても使用後にファイルリソースが閉じられるようにするために使用されます。Pythonは、リソースを管理する簡単な方法を提供します。 Withキーワードが使用されます。 評価されると、コンテキスト管理を実行するオブジェクトが生成されます。 コンテキストマネージャは、クラスまたは関数(デコレータ付き)を使用して記述できます。 クラスを使用してコンテキストマネージャを作成する場合、ユーザーはクラスに__enter__()と__exit__()メソッドがあることを確認する必要があります。 __Enter__()は管理する必要があるリソースを返し、__exit__()はクリーンアップ操作を実行する以外は何も返しません。__exit__()は__exit__()を返します。__exit__()
まず、ContextManagerという単純なクラスを作成して、以下に示すように、クラスを使用してコンテキストマネージャを作成する基本的な構造を理解しましょう:
class
ContextManager():
def
__init__(
self
):
print
(
'init method called'
)
def
__enter__(
self
):
print
(
'enter method called'
)
return
self
def
__exit__(
self
, exc_type, exc_value, exc_traceback):
print
(
'exit method called'
)
with ContextManager() as manager:
print
(
'with statement block'
)
Output:この場合、ContextManagerオブジェクトが作成されます。 これは、asキーワード、つまりmanagerの後の変数に割り当てられます。 上記のプログラムを実行すると、次のgetが順番に実行されます。
- __init__()
- __enter__()
- ステートメント本体(withブロック内のコード)
- __exit__()
コンテキストマネージャを使用したファイル管理:
上記の概念を次のように適用してみましょう。ファイルリソース管理に役立つクラスを作成します。FileManagerクラスは、ファイルを開いたり、内容を書き込んだり、閉じたりするのに役立ちます。
class
FileManager():
def
__init__(
self
, filename, mode):
self
.filename
=
filename
self
.mode
=
mode
self
.
file
=
None
def
__enter__(
self
):
self
.
file
=
open
(
self
.filename,
self
.mode)
return
self
.
file
def
__exit__(
self
, exc_type, exc_value, exc_traceback):
self
.
file
.close()
with FileManager(
'test.txt'
,
'w'
) as f:
f.write(
'Test'
)
print
(f.closed)
出力:
True
コンテキストマネージャとwithステートメントを使用したファイル管理:
withブロックを実行すると、次の操作が順番に行われます。
- TestでFileManagerオブジェクトが作成されます。ファイル名としてtxt、__init__メソッドが実行されたときのモードとしてw(write)。
- __enter__メソッドはテストを開きます。書き込みモード(セットアップ操作)でtxtファイルを開き、FileManagerオブジェクトを変数fに返します。
- テキスト’Test’がファイルに書き込まれます。
- __exit__メソッドは、withブロックを終了するときにファイルを閉じる処理を行います(teardown操作)。print(f.closed)が実行されると、FileManagerはすでに明示的に実行する必要があるファイルを閉じる処理を行っているため、出力はTrueになります。
コンテキストマネージャを使用したデータベース接続管理:
簡単なデータベース接続管理システムを作成しましょう。 一度に開くことができるデータベース接続の数も(ファイル記述子と同様に)制限されています。 したがって、コンテキストマネージャは、プログラマが接続を閉じるのを忘れる可能性があるため、データベースへの接続を管理するのに役立ちます。
from
pymongo
import
MongoClient
class
MongoDBConnectionManager():
def
__init__(
self
, hostname, port):
self
.hostname
=
hostname
self
.port
=
port
self
.connection
=
None
def
__enter__(
self
):
self
.connection
=
MongoClient(
self
.hostname,
self
.port)
return
self
def
__exit__(
self
, exc_type, exc_value, exc_traceback):
self
.connection.close()
with MongoDBConnectionManager(
'localhost'
,
'27017'
) as mongo:
collection
=
mongo.connection.SampleDb.test
data
=
collection.find({
'_id'
:
1
})
コンテキストマネージャとwithステートメントを使用したデータベース接続管理:
withブロックを実行すると、次の操作が順番に行われます。
- mongodbconnectionmanagerオブジェクトは、localhostを使用して作成されます。__init__メソッドが実行されたときのポートとしてhostnamenameと27017。
- __enter__メソッドはmongodb接続を開き、MongoDBConnectionManagerオブジェクトを変数mongoに返します。
- SampleDbデータベースのテストコレクションにアクセスし、_id=1のドキュメントを取得します。 文書の名前フィールドが印刷されます。
- __exit__メソッドは、withブロックを終了するときに接続を閉じる処理を行います(teardown操作)。