🗂

Python の with ~ as 構文

2025/02/09に公開

珍しく Python のコードを読む機会があったんですが

with open('./test.txt') as f:
	print(f.read());

みたいに with ~ as みたいなコードを見かけて『これってどういう構文なんだろう』と思ったので覚書です。

with ~ as 構文

さらっと書いちゃうんですが

with EXPRESSION as TARGET:
    SUITE

manager = (EXPRESSION)
enter = type(manager).__enter__
exit = type(manager).__exit__
value = enter(manager)
hit_except = False

try:
    TARGET = value
    SUITE
except:
    hit_except = True
    if not exit(manager, *sys.exc_info()):
        raise
finally:
    if not hit_except:
        exit(manager, None, None, None)

と等価になります。
もう少し簡略的に書いてしまうと

manager = EXPRESSION
TARGET = manager.__enter__()

try:
    SUITE
finally:
	manager.__exit__()

みたいに EXPRESSION を評価しつつ SUITE の前後で __enter__()__exit__() を呼び出す構文になります。
参照: Pythonのwith文の正体

元のコードでは __exit__() のタイミングで f.close() を呼び出すことが担保されている感じですねー。
要は RAII みたいな手法を構文で実現している感じですかね?
参照: RAII - Wikipedia

これは以下のようにユーザが拡張して利用することもできます。

class Wrap:
    def __enter__(self):
        print(">>>>>>>>>>>>>>")

    def __exit__(self, *args):
        print("<<<<<<<<<<<<<<")

with Wrap() as f:
    print("Hello, World!!")
j>>>>>>>>>>>>>>
Hello, World!!
<<<<<<<<<<<<<<

Ruby だと構文ではなくてブロックでこういう仕組みをメソッド側で実現していることが多いと思いますが、他言語でこういう構文を見るのは単純に面白い。

関連

GitHubで編集を提案

Discussion