質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

3回答

4201閲覧

with構文の必要性がわからない

退会済みユーザー

退会済みユーザー

総合スコア0

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

2クリップ

投稿2017/04/08 13:46

編集2017/04/08 13:46

CIFAR-10形式のデータセットを読み込むプログラムを書いています。

# coding: utf-8 from __future__ import absolute_import from __future__ import division from __future__ import print_function import tensorflow as tf NUM_CLASSES = 10 def _get_weights(shape,stddev=1.0): var = tf.get_variable( 'weights', shape, initializer=tf.truncated_normal_initializer(stddev=stddev) ) return var def _get_biases(shape,value=0.0): var = tf.get_variable( 'biases', shape, initializer=tf.constant_initializer(value) ) return var def inference(image_node): # conv1 with tf.variable_scope('conv1') as scope: weights = _get_weights(shape=[5,5,3,64],stddev=1e-4) conv = tf.nn.conv2d(image_node,weights,[1,1,1,1],padding='SAME') biases = _get_biases([64],value=0.1) bias = tf.nn.bias_add(conv,biases) conv1 = tf.nn.relu(bias,name=scope.name) # pool pool1 = tf.nn.max_pool(conv1,ksize=[1,3,3,1],strides=[1,2,2,1],padding='SAME',name='pool1') # conv2 with tf.variable_scope('conv2') as scope: weights = _get_weights(shape=[5,5,64,64],stddev=1e-4) conv = tf.nn.conv2d(pool1,weights,[1,1,1,1],padding='SAME') biases = _get_biases([64],value=0.1) bias = tf.nn.bias_add(conv,biases) conv2 = tf.nn.relu(bias,name=scope.name) # pool2 pool2 = tf.nn.max_pool(conv2,ksize=[1,3,3,1],strides=[1,2,2,1],padding='SAME',name='pool2') reshape = tf.reshape(pool2,[1,-1]) dim = reshape.get_shape()[1].value # fc3 with tf.variable_scope('fc3') as scope: weights = _get_weights(shape=[dim,384],stddev=0.04) biases = _get_biases([384],value=0.1) fc3 = tf.nn.relu( tf.matmul(reshape,weights) + biases, name=scope.name ) # fc4 with tf.variable_scope('fc4') as scope: weights = _get_weights(shape=[384,192],stddev=0.04) biases = _get_biases([192],value=0.1) fc4 = tf.nn.relu(tf.matmul(fc3,weights) + biases,name=scope.name) # output with tf.variable_scope('output') as scope: weights = _get_weights(shape=[192,NUM_CLASSES],stddev=1/192.0) biases = _get_biases([NUM_CLASSES],value=0.0) logits = tf.add(tf.matmul(fc4,weights),biases,name='logits') return logits

このコードに所々に出てくるwith構文の必要性がわかりません。
私は、with構文はファイルオープン・クローズの時に使い、with構文を使わない書き方の時に使うclose()メソッドを書かなくてもいい点が便利、という解釈をしています。
http://reiki4040.hatenablog.com/entry/20130331/1364723288

しかし、上記のコードのwith構文はファイルオープン・クローズに関係あるわけではないので、どうしてwith構文を使っているのかわかりません。
私のwith構文の解釈が間違っているのでしょうか?
解説をお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

8.5. with 文

with 文は、ブロックの実行を、コンテキストマネージャによって定義されたメソッドでラップするために使われます (with文とコンテキストマネージャ セクションを参照してください)。これにより、よくある try...except...finally 利用パターンをカプセル化して便利に再利用することができます。

close() を省略する楽な書き方ではありません。例外が起こっても必ず close() のような最終処理が呼ばれるようにするための仕組みです。
ファイルのオープン・クローズだけでなく、コンテキストマネージャは様々な場面で使います。

追記

どこからどこまで解説すればいいのかわかりませんが、解決してないようなのでやってみましょうか。

まずは「例外」というものがあるのをご存知ですか?

例えば 3 / i という計算を行うとします。通常はこれでいいのですが、i0 の場合、答えは未定義になってしまいます。ですから、i0 にならないよう、事前にチェックしてはねておかなければいけません。

ところがプログラマーが i0 になる場面を想像していなかったとします。この時、C などの昔の言語であれば、エラーメッセージを出して停止するか、または暴走していました。

このため、例外的なデータをチェックするコードが何重にも書かれることになり、主なアルゴリズムがそれに隠れて読みにくくなっていました。

これを改善するために生まれたのが例外と例外処理です。

不正な処理が行われると、例外が発生します。例外のデフォルトの動作は、メッセージを出し、以降の関連する処理を必要なところまでスキップすることです。

例外が起きそうなところを try catch ブロックで囲むと、このデフォルトの動作を上書きできます。

これによって事前に何重ものチェックをしなくても、実際に不正なデータが入力された段階で一度のチェックで済ませることができるようになり、コードの可読性が向上します。

また、finally を使えば、スキップしてはいけない部分を明示的に指示できます。これにより、例えばオープンしたファイルが必ずクローズされるよう保証できます。

この try catch finally ブロックはプログラマーが書く必要がありますが、多くの場合、同じ処理を書くことになります。例えば、ファイルを開いた時には必ず finally で閉じます。

このようにオブジェクトによって例外処理が決まっているなら、オブジェクト自身が処理方法を知っていればいいじゃないかという考えが出てきます。そうすれば何度も何度も同じことを書かずに済みます。

一連の文から成る一定の処理を文脈(コンテキスト)と言いますが、この例外処理を行う文脈(コンテキスト)を管理(マネージメント)するのがコンテキストマネージャーです。

コンテキストマネージャーとは、例外が起こった時の処理方法を知っているオブジェクトのことです。
具体的には、__enter____exit__ を実装したオブジェクトのことです。

__enter__with 文に入る時に呼ばれ、初期化を担当します。__exit__ は出るときに呼ばれます。出る時というのは例外が起こった時も含みます。したがって __exit__ に書くべきは finally ブロックに書いていた処理です。

投稿2017/04/08 14:16

編集2017/04/09 23:35
Zuishin

総合スコア28656

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/04/08 14:33

ありがとうございます。コンテキストマネージャについて解説してもらっても良いでしょうか?どういう構文をコンテキストマネージャと呼ぶのでしょうか?また、コンテキストマネージャを使うべき時はどういった時になるのでしょうか? 検索すると、 Pythonではwith文で前処理、後処理を行えるようにする場合、そのオブジェクトはコンテキストマネージャである必要があります。 とありましたが、この説明がさっぱり....
Zuishin

2017/04/08 14:38

私などが余計な説明を加えなくても、リンク先に説明がありますので、一度読んでみてください。 わかりにくければ、こちらも並べて読んでみてください。より実践的に書いてあります。 http://python.keicode.com/lang/context-manager.php
退会済みユーザー

退会済みユーザー

2017/04/12 03:42

丁寧な説明をありがとうございます。1点まだわからない場所があるのですが、例えば with tf.variable_scope('fc3') as scope: で、この全体のコード中でfc3をどこにも定義していません。このfc3や全体のコード中の'fc4'や'output'などのwith~~()の()の中身はどこからきているのでしょうか?この中身はどういう役割なのでしょうか?
Zuishin

2017/04/12 03:46

そこで初めてスコープ名として定義されているのですが、それはまた別の質問です。
退会済みユーザー

退会済みユーザー

2017/04/12 03:47

なるほど!丁寧にありがとうございました。
guest

0

withは__enter__と__exit__というメソッド(?)でオブジェクトに関する開始と終了の処理を挟める便利な仕組みと理解すると良いです。

with XYZ() as xyz: となっていればここでxyzに関して何らかの開始処理が行われて、なおかつこのブロックを抜けるときには対になる終了処理が必ず走ります。

with tf.variable_scope('conv1') as scope: も同じです。

投稿2017/04/09 17:31

YouheiSakurai

総合スコア6142

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

TensorFlow上の変数(Variable)を区別するためです。TensorFlowでは名前空間(scope)を与えて各レイヤの変数を区別しています。詳しくは、以下をご覧ください。
https://www.tensorflow.org/programmers_guide/variable_scope

投稿2017/04/08 22:39

編集2017/04/08 22:39
MasashiKimura

総合スコア1150

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問