福岡県だけどPythonを勉強する!

他言語を積極的に推奨する福岡県でPythonを勉強していく記録。

制御構文 - with

■■with

・withはwithブロックに入る時と出る時に__enter__メソッドと__exit__メソッドを呼ぶ。

・withは続く式を評価した結果をコンテキストマネージャとして利用する。

 

>>> with open('test.txt', 'a') as f:

...     f.write('テスト')

... 

3

>>>

 

コンテキストマネージャになれる

__init__(self,file_name)と

__enter__(self)と

__exit(self,type,traceback)

という3つのメソッドが定義された

WriteFileクラスをつくる。

 

>>> class WriteFile(object):

...     def __init__(self, file_name):

...         print('__init__が呼ばれました')

...         self.file_name = file_name

...     def __enter__(self):

...         print('__enter__が呼ばれました')

...         self.f = open(self.file_name, 'w')

...         print('ファイルが開きました')

...         return self.f

...     def __exit__(self, type, value, traceback):

...         print('__exit__が呼ばれました')

...         self.f.close()

...         print('ファイルが閉じました')

... 

>>>

 

 

withに続けてクラスを生成すると、

クラスの仕組みにより__init__が自動で呼ばれ、

引数(ファイル名を表す文字列)が渡される。

 

withはコンテキストマネージャを得ると、

コンテキストマネージャの__enter__を呼び出す。

 

__enter__は初期化コードを記述し、

必要に応じて値を返す。

(値は複数個返す事も可)

 

withは返された値(オブジェクト)をasに続けた一時変数に格納する。

 

__enter__で問題が無ければ処理がwithブロックへ移る。

 

withブロック終了後に__exit__が呼び出される。

(__enter__が正常終了した時点で__exit__の呼び出しが保証されている)

 

 

 

>>> with WriteFile('test3.txt') as f:

...     print('withのブロックに入りました')

...     f.write('寿限無寿限無・・・')

...     print('withのブロックから出ます')

... 

__init__が呼ばれました

__enter__が呼ばれました

ファイルが開きました

withのブロックに入りました

9

withのブロックから出ます

__exit__が呼ばれました

ファイルが閉じました

>>>

 

正常終了した場合はtype、value、tracebackにNoneが設定されて呼び出される。

例外が発生した場合は、

・typeに例外の種類

・valueに例外のインスタンス

・tracebackにトレースバック

が設定されて呼び出される。

 

例外の伝搬を抑制したい場合は__exit__からTrueを返す必要がある。

 

■closeする何かを簡単に扱う

ファイルのようにcloseして終了したいものには

closingというコンテキストマネージャを使う。

 

>>> from contextlib import closing

>>> with closing(open('test3.txt', 'w')) as f:

...     f.write('寿限無寿限無・・・')

... 

9

>>>

 

■ジェネレータを使うプログラムを簡単に扱う

 

>>> from contextlib import contextmanager

>>> @contextmanager

... def range_generator(max):

...     print('初期化コード')

...     try:

...         yield range(max)

...     finally:

...         print('終了コード')

... 

>>> with range_generator(5) as g:

...     for i in g:

...         print(i)

... 

初期化コード

0

1

2

3

4

終了コード

>>>

 

イマイチ理解出来ないのであとから復習する。

 

パーフェクトPython (PERFECT SERIES 5)

パーフェクトPython (PERFECT SERIES 5)