with
このキーワードは、Pythonを学ぶすべての人によく知られています。
テキストオブジェクトを操作するとき、ほとんどの人がそれらを使用できるようにしますwith open
。これはコンテキスト管理の例です。あなたはそれをかなりよく知っているに違いありません、そして私はもうナンセンスを話しません。
with open('test.txt') as f:
print f.readlines()
1.どのコンテキストマネージャー?
基本的な文法
with EXPR as VAR:
BLOCK
まず、いくつかの概念を明確にします
1. 上下文表达式:with open('test.txt') as f:
2. 上下文管理器:open('test.txt')
3. f 不是上下文管理器,应该是资源对象。
2.どのようにコンテキストマネージャー?
このようなコンテキスト管理を自分で実装するには、最初にコンテキスト管理プロトコルを知っている必要があります。
簡単に言うと、__enter__
and__exit__
メソッドはクラスに実装されており、このクラスのインスタンスはコンテキストマネージャーです。
たとえば、次の例:
class Resource():
def __enter__(self):
print('===connect to resource===')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('===close resource connection===')
def operate(self):
print('===in operation===')
with Resource() as res:
res.operate()
それを実行して、ログの印刷シーケンスを見てみましょう。実行プロセスを知ることができます。
===connect to resource===
===in operation===
===close resource connection===
この例から、コードを作成するときに__enter__
、リソースの接続または取得をに入れて、リソースの終了をに書き込むことができることは明らかです__exit__
。
3.なぜコンテキストマネージャー?
勉強するときは、もう少し理由を自問し、知識のポイントについての理解を深めるのに役立つ詳細について考えてください。
なぜコンテキストマネージャーを使用するのですか?
私の意見では、これはPythonが提唱するエレガントなスタイルに関連しています。
- ファイル操作やデータベース接続など、より洗練された方法でリソースを操作(作成/取得/解放)できます。
- よりエレガントな方法で例外を処理できます。
1つ目は、すでにリソース接続を例として取り上げています。
2番目のタイプはほとんどの人に無視されます。ここで焦点を当てます。
ご存知のとおり、例外のtry...execept..
処理は通常、プロセスのキャプチャに使用されます。これの欠点の1つは、コードのメインロジックに多数の例外処理エージェントが存在することです。これは、読みやすさに大きく影響します。
もう少し良いことは、with
隠された例外を処理するために使用できます。
上記のコード例に基づいて、1/0
これを次のように一定会抛出异常的代码
記述operate
します。
class Resource():
def __enter__(self):
print('===connect to resource===')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('===close resource connection===')
return True
def operate(self):
1/0
with Resource() as res:
res.operate()
それを実行した後、エラーが報告されていないことに驚いた。
これは、コンテキスト管理プロトコルの強力な側面です。例外を__exit__
キャッチして、それらをスローするか、ここで解決するかを決定できます。その__exit__
見返りとしてTrue
(Falseを返すためにデフォルトに戻らない)、Pythonインタープリターに通知するのと同じように、例外をキャプチャしました。破棄する必要はありません。
__exit__
関数を作成するときは、それに注意を払う必要があります。関数には、次の3つのパラメーターが必要です。
- exc_type:例外タイプ
- exc_val:異常値
- exc_tb:異常なエラースタック情報
メインロジックコードが例外を報告しない場合、これら3つのパラメーターはすべてNoneになります。
4.どのようにcontextlib?
上記の例では、コンテキストマネージャーを構築するためのクラスを作成しました。単純な関数を実装したいだけの場合、クラスの作成は少し複雑すぎます。現時点では、コンテキストマネージャーを実装するために1つの関数しか記述できないと考えました。
Pythonはこの点について長い間考えてきました。デコレータを提供します。コードプロトコルに従って関数コンテンツを実装する限り、この関数オブジェクトをコンテキストマネージャに変えることができます。
contextlibプロトコルに従って、ファイルを開くためのコンテキストマネージャーを実装します(開いた状態で)。
import contextlib
@contextlib.contextmanager
def open_func(file_name):
# __enter__方法
print('open file:', file_name, 'in __enter__')
file_handler = open(file_name, 'r')
# 【重点】:yield
yield file_handler
# __exit__方法
print('close file:', file_name, 'in __exit__')
file_handler.close()
return
with open_func('/Users/MING/mytest.txt') as file_in:
for line in file_in:
print(line)
装飾された関数では、ジェネレーター(yield付き)である必要があり、yieldの前のコードは__enter__
内部のコンテンツと同等です。イールド後のコードは__exit__
、のコンテンツと同等です。
上記のコードは、コンテキストマネージャーの最初の目的(リソースの管理)のみを達成でき、2番目の目的(例外の処理)は達成できません。
例外を処理する場合は、次のように変更できます。
import contextlib
@contextlib.contextmanager
def open_func(file_name):
# __enter__方法
print('open file:', file_name, 'in __enter__')
file_handler = open(file_name, 'r')
try:
yield file_handler
except Exception as exc:
# deal with exception
print('the exception was thrown')
finally:
print('close file:', file_name, 'in __exit__')
file_handler.close()
return
with open_func('/Users/MING/mytest.txt') as file_in:
for line in file_in:
1/0
print(line)
コンテキストマネージャーが言及されている限り、ほとんどの人はファイルを開く典型的な例について話すようです。
しかし、実際の開発では、使用できるコンテキストマネージャーの例がたくさんあります。私自身の例を挙げましょう。
OpenStackでは、仮想マシンのスナップショットを作成するときに、ローカルスナップショットイメージを保存するための一時フォルダーを作成する必要があります。ローカルスナップショットイメージが作成されたら、イメージをGlanceにアップロードします。次に、この一時ディレクトリを削除します。
このコードの主なロジックは创建快照
、であり创建临时目录
、前提条件删除临时目录
に属し、最後の仕上げです。
コードの量は少なく、ロジックは複雑ではありません创建临时目录,使用完后再删除临时目录
が、プロジェクトの多くの場所で「」関数が必要です。このロジック処理をコンテキストマネージャーとしてツール関数として記述できる場合、コードの再利用レートも大幅に向上します。
コードはこんな感じ
要約すると、コンテキストマネージャを使用することには3つの利点があります。
- コードの再利用率を向上させます。
- コードの優雅さを向上させます。
- コードの読みやすさを向上させます。
多数(300)のイラストが含まれているオリジナルの「PyCharmChinese Guide」e-bookをお勧めします。これはよくできていて、すべてのPythonエンジニアによるコレクションに値します。
アドレスは次のとおりです:http://pycharm.iswbm.com