なんとなく使っていたPythonのwith文の仕組みと使い方を調べてみた!
こんにちは、AIQ株式会社のフロントエンドエンジニアのまさぴょんです!
今回は、なんとなく使っていたPythonのwith文の仕組みと使い方を調べてみたので、解説します。
with文、なんとなく使っていませんか?
Pythonを使っていると結構な頻度で、目にするのが、with
構文だと思います。
他の言語で、with
というkeywordを見たことがない私にとっては、最初に見た時は「これ何?」って、なりました。
その時は、ちょっと調べて、ファイル操作の時にこれを使えばいいのね〜ぐらいの感じで使っていました。
with open('sample.txt', 'r') as f:
result = f.read()
print(result)
with文の仕組みとは?
ファイル操作のための構文ぐらいに思ってしまっていた、with
文ですが、ちゃんと仕組みを調べてみたら、次のような事実が判明しました。
-
with
文は最初に何か(前処理)して最後に必ず何か(後処理)する(try/finally文
)の処理をまとめたもの。- 「最初と最後に何かをする」は、コンテキストマネージャ と呼ばれる
__enter__()
と__exit__()
の2つのメソッドを持つ型で表される。
- 「最初と最後に何かをする」は、コンテキストマネージャ と呼ばれる
-
with
文のwith xxx
のxxx
部分は、コンテキストマネージャを指している。-
as xx
の部分は、実行結果の返り値(大抵は、そのClassのインスタンス)を受け取っている。
-
-
ファイルオブジェクトなど、一部の組み込みClassは、コンテキストマネージャだから
with
文が使える。 -
with
文に対応するClass
は、ユーザー定義で作成することができる。-
__enter__()
と__exit__()
の2つのメソッドを追加すれば、どんなObject
もwith
文対応のClass
にすることができる。
-
with open('sample.txt', 'r') as f:
result = f.read()
print(result)
with文の使い方(with文を使わない場合と使う場合のファイル操作)
with
文の仕組みの概要を理解したところで、with
文を使わない場合と使う場合のファイル操作を例にCodeを見ていきたいと思います。
with文を使わない場合のファイル操作
with文を使用しない場合は、次のように、定型の前処理・後処理が必要で、Codeが長くなってしまいます。
# 1. with文を使用しない場合: 定型の前処理・後処理が必要で、Codeが長くなる。
try:
# 前処理: ファイルを開く処理
f = open('sample.txt', 'r')
# 本処理: ファイルの内容を読み込む
result = f.read()
print(result)
finally: # finally は、処理の成功/失敗に関わらず、必ず実行する処理を記述する
# 後処理: ファイルを閉じる
f.close()
with文を使う場合のファイル操作
ファイルを開くopen()
という関数はwith
文の処理に対応しているので、次のように書き直すことができます。
# 2. with文を使用する場合: 定型の前処理・後処理が省略されるので、Codeがコンパクトになる。
with open('sample.txt', 'r') as f:
result = f.read()
print(result)
2つを比較した結果から、定型の前処理と後処理を省略したいときは、with
文を活用するといいことがわかります。
with文に対応する Class を定義する
with
文に対応するようなObject
は、次のように__enter__()
と__exit__()
の2つのメソッドを追加すれば、自分でも独自に作成することができます。
class CustomFileReader:
def __init__(self, filename):
print('init Block')
self.filename = filename
self.file = None
# 1. __enter__(): with文で利用されるオブジェクトの前処理を定義する
def __enter__(self):
""" with文で最初に呼ばれる処理 """
print('enter Block')
self.file = open(self.filename, 'r')
return self.file
# 2. __exit__(): with文で利用されるオブジェクトの後処理を定義する
def __exit__(self, exc_type, exc_value, traceback):
""" withブロックから抜ける時の処理 """
print(f'exit Block: {exc_type}, {exc_value}, {traceback}')
self.file.close()
if __name__ == '__main__':
with CustomFileReader('sample.txt') as f:
print(f.read())
__enter__()
と__exit__()
の2つのメソッドの仕組みをまとめると次のようになります。
まとめ
Pythonのwith
文は、処理の前処理と後処理を設定する(__enter__()
と__exit__()
を追加する)ことで、その処理をよりコンパクトに利用できるようにする書き方であることがわかりました。
定型の処理の前処理と後処理を省略したいときは、with
文を活用してみようと思いました。
個人で、Blogもやっています、よかったら見てみてください。
注意事項
この記事は、AIQ 株式会社の社員による個人の見解であり、所属する組織の公式見解ではありません。
求む、冒険者!
AIQ株式会社では、一緒に働いてくれるエンジニアを絶賛、募集しております🐱🐹✨
詳しくは、Wantedly (https://www.wantedly.com/companies/aiqlab)を見てみてください。
参考・引用
AIQ 株式会社 に所属するエンジニアが技術情報をお届けします。 ※ AIQ 株式会社 社員による個人の見解であり、所属する組織の公式見解ではありません。 Wantedly: wantedly.com/companies/aiqlab
Discussion