なんかググって出てくる __enter__
のサンプルとかってだいたい
with WithClass() as x:
x.hoge()
みたいに with
の中でコンストラクタ呼んで即使い捨ててるけど、
別に使い回すこともメンバ変数持たせることもできるんですよね。
a.py
class Enterable:
def __init__(self, *args, **kwargs):
print("init")
self.args = args
self.kwargs = kwargs
self.count = 0
def hoge(self):
print("hoge", self.count, self.args, self.kwargs)
def __enter__(self):
self.count += 1
print("-" * 10)
print("enter", self.count)
return self
def __exit__(self, ex_type, ex_value, trace):
print("exit", self.count)
x = Enterable(1, 2, foo=3, bar=4)
with x: x.hoge()
with x: x.hoge()
with x: x.hoge()
$ python a.py
init
----------
enter 1
hoge 1 (1, 2) {'foo': 3, 'bar': 4}
exit 1
----------
enter 2
hoge 2 (1, 2) {'foo': 3, 'bar': 4}
exit 2
----------
enter 3
hoge 3 (1, 2) {'foo': 3, 'bar': 4}
exit 3
おまけ:__enter__
に引数を渡したいとき
@contextlib.contextmanager
使うとそれ相当のことができます。
この場合、 class 自体は __enter__
無しの普通のクラスになって、メンバ関数をデコレートすることで実現されます。
yield
の引数は as
で指定した変数に渡ってきます。
例外補足する場合は yield
を try - except すればOK。
b.py
import contextlib
class EnterableWithArgs:
def __init__(self, *args, **kwargs):
print("init")
self.args = args
self.kwargs = kwargs
self.count = 0
@contextlib.contextmanager
def hoge(self, arg_with_context):
print("-" * 10)
self.count += 1
print("hoge", self.count, self.args, self.kwargs, arg_with_context)
yield self
x = EnterableWithArgs(1, 2, foo=3, bar=4)
with x.hoge(100) as y: print(y)
with x.hoge(200) as y: print(y)
with x.hoge(300) as y: print(y)
$ python b.py
init
----------
hoge 1 (1, 2) {'foo': 3, 'bar': 4} 100
<__main__.EnterableWithArgs object at 0x1070c22e0>
----------
hoge 2 (1, 2) {'foo': 3, 'bar': 4} 200
<__main__.EnterableWithArgs object at 0x1070c22e0>
----------
hoge 3 (1, 2) {'foo': 3, 'bar': 4} 300
<__main__.EnterableWithArgs object at 0x1070c22e0>
っていう話。