LoginSignup
57
35

More than 5 years have passed since last update.

Python の with 文のためのクラス

Last updated at Posted at 2018-02-02

処理を終える際に実行すべき処理を書く構文が多くの言語にある。

Java なら try with resources。
C# なら using ステートメント。

Python には with ステートメントがある。

with ステートメントに供するクラスは2つのメソッド __enter____exit__ を用意する必要がある。

with + コンストラクタ

python
class WithClass:
  def __init__(self):
    print("init")

  def hoge(self):
    print("hoge")

  def __enter__(self):
    print("enter")
    return self

  def __exit__(self, ex_type, ex_value, trace):
    print("exit: ", ex_type, ex_value, trace)

with WithClass() as w:
  w.hoge()

こんな感じになる。

実行すると

init
enter
hoge
exit:  None None None

と出力される。

私が最初気づかなかったのは、 __enter__(self) の返戻値が w の値になるという点。
だから、 return self は必須。

with + 非コンストラクタ

もうひとつのパターンは、with open(filename) as f: のように、コンストラクタではないメソッドがある場合。

python
class WithClass:
  def __init__(self):
    print("init")

  def hoge(self):
    print("hoge")

  def __enter__(self):
    print("enter")
    return self

  def __exit__(self, ex_type, ex_value, trace):
    print("exit: ", ex_type, ex_value, trace)

def creator():
  return WithClass()

with creator() as w:
  w.hoge()

こんな具合。
このパターンでも __enter__(self) は必須。
wの値は __enter__(self) の返戻値になる。 create() の返戻値ではない。

というわけで、出力されるのは

init
enter
hoge
exit:  None None None

と、最初の例と同じになる。

__enter__(self) の返戻値を self 以外にしたくなる局面が思いつかないんだけど、きっとなにかあるんだろう。

例外が起きる場合

で。例外を起こしてみる:

python
class WithClass:
  def __init__(self):
    print("init")

  def hoge(self):
    print(1/0) # ゼロ除算!

  def __enter__(self):
    print("enter")
    return self

  def __exit__(self, ex_type, ex_value, trace):
    print("exit: ", ex_type, ex_value, trace)
    print("---")

with WithClass() as w:
  w.hoge()

すると、出力はこんな風に

init
enter
exit:  <class 'ZeroDivisionError'> division by zero <traceback object at 0x1092539c8>
---
Traceback (most recent call last):
  File "with3.py", line 16, in <module>
    w.hoge()
  File "with3.py", line 6, in hoge
    print(1/0)
ZeroDivisionError: division by zero

なる。
ここで、 __exit__(self,略)True を返すと例外を握りつぶしてくれる。

こんな具合:

python
class WithClass:
  def __init__(self):
    print("init")

  def hoge(self):
    print(1/0) # ゼロ除算!

  def __enter__(self):
    print("enter")
    return self

  def __exit__(self, ex_type, ex_value, trace):
    print("exit: ", ex_type, ex_value, trace)
    print("---")
    return True

with WithClass() as w:
  w.hoge()

出力は

init
enter
exit:  <class 'ZeroDivisionError'> division by zero <traceback object at 0x10885e9c8>
---

となっていて、例外が握りつぶされていることがわかる。

参考サイト:

http://shin.hateblo.jp/entry/2013/03/23/211750
http://reiki4040.hatenablog.com/entry/20130331/1364723288

57
35
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
57
35