2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

python with句が便利な事例 / with が使える class の使い方

Last updated at Posted at 2021-07-04

python の with って何に使うのかずっとわからなかった。やっと意味がわかったのでメモ。

with って便利なの?

この神記事にすべてがありました

[Python] with構文で使用できるクラスを実装する

database 接続 / file開く など、何かしら connection close などの後始末が必要なときは with が最高に便利です! 

何がいいの?

コードがシンプルになります

コードがきれいになる例

残念な例

try:
    obj = SomeClass()
    obj.do_something()
finally:
    obj.close()

5行あります。

Cool な例

with SomeClass() as obj:
    obj.do_something()

以上! 2行で終わりました! ちゃんとclose()処理はされてますよ :)

with で使える class とは

最初にいっとくと、関数では with ができません。必ず class にしましょう。

関数 → class への変換方法

# 関数の宣言
def some(arg1):
   return do_something(arg1)

# 関数使い方
some('arg1')

# classの宣言
class SomeClass:
    def __init__(self, arg1):
        do_something(arg1)

# class 使い方
SomeClass('arg1')

with で使える class の作り方

↑ の例のように、普通に class 作るだけだとwithで使えません。
__enter__ または __exit__ がないぞ、的なエラーが出ます。

class W:
    def __init__(self):
        print('init')

with W() as w:
    print(w)

result

AttributeError: __enter__

これは with句で呼び出されたclassは、暗黙的に __enter__() __exit__() を呼び出されるからです。エラーを消すには、この関数を作ってあげればよいです。

withで使わない場合

class W:
    def __init__(self):
        print('init')
    def __enter__(self):
        print('enter')
        return self
    def __exit__(self, exception_type, exception_value, traceback):
        print('exit')

w = W()
print('===')

result

init
===

withで使う場合

class W:
    def __init__(self):
        print('init')
    def __enter__(self):
        print('enter')
        return self
    def __exit__(self, exception_type, exception_value, traceback):
        print('exit')

with W() as w:
    print(w)

print('===')

result

init
enter
<__main__.W object at 0x10347bfd0>
exit
===

悩んだエラー TypeError: __exit__()

__exit__()の引数をちゃんとしないと、エラー

TypeError: __exit__() takes 1 positional argument but 4 were given

# wrong
    def __exit__(self):

# right    
    def __exit__(self, exception_type, exception_value, traceback):

with class をインスタンスで返す関数の場合

問題なく動く

class W:
    def __init__(self):
        print('init')
    def __enter__(self):
        print('enter')
        return self
    def __exit__(self, exception_type, exception_value, traceback):
        print('exit')

def func():
    return W()

with func() as w:
    print(w)

result

init
enter
<__main__.W object at 0x10bddbfd0>
exit

with class を class のままで返す関数の場合

無茶苦茶だけど動く

class W:
    def __init__(self):
        print('init')
    def __enter__(self):
        print('enter')
        return self
    def __exit__(self, exception_type, exception_value, traceback):
        print('exit')

def get_class():
    return W

with get_class()() as w:      #<--- ()() ってひどい.顔文字か。
    print(w)

result

init
enter
<__main__.W object at 0x10bdc0fd0>
exit

summary

__enter__, __exit__ は with で使ったときだ だけ 呼び出される

__exit__() は必ず4つ引数を受け取る

2
2
0

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
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?