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

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

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

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

Q&A

解決済

4回答

187閲覧

python 変数 宣言

eggpol

総合スコア60

Python 3.x

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

2グッド

3クリップ

投稿2019/01/12 13:16

編集2019/01/13 09:47

スコープ外の変数には宣言&代入がOK
関数内のグローバルに宣言&代入がNO
ローカル変数に宣言&代入がOK

関数内でグローバル変数に宣言と当時に代入できない仕様の意図が理解できません
誰か教えて下さい

aaa=[]//ok def method(): global a//ok global aa=[]//SyntaxError       aaaa=12//ok
firedfly, tmykbys👍を押しています

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

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

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

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

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

guest

回答4

0

ベストアンサー

これ、「仕様の意図」という切り口で追うとめっちゃ難しい質問ですよ。

まぁ兎にも角にもまずは、globalと同じような位置づけで追加された時期が新しいnonlocalについて実装の経緯(PEP)を探してみました。で、やっぱりPEPがありました。

PEP 3104 -- Access to Names in Outer Scopes

そうすると驚くことにこのPEP-3104のProposed Solutionには、

A shorthand form is also permitted, in which nonlocal is prepended to an assignment or augmented assignment:

nonlocal x = 3

nonlocal_stmt ::= "nonlocal" identifier ("," identifier)* ["=" (target_list "=")+ expression_list] | "nonlocal" identifier augop expression_list

と記述されていました。でもこのshorthand form(短い書き方)はPython 3.7で試してもSyntaxErrorですし、何よりGrammer的にもそのような書き方は許容されていないので、このPEP-3104の内容とPythonの実装実体が異なるという奇妙な事態が発生しているように見受けられます。そこで私はこのPEP-3104がRejectされた代物なのかと思って確認してみましたが、ココを見る限りそうでもないようで最初は私も状況がうまくつかめませんでした。でもPEP-3104をちゃんと読むと、

Note

The shorthand syntax was not added in the original implementation of the PEP. Later discussions [29] [30] concluded this syntax should not be implemented.

と書いてありました。そして以下2つの内容を確認すると最終的にはGuido van Rossumの発した一文にその「仕様の意図」がありました。

  • [29] Issue 4199: combining assignment with global & nonlocal (Guido van Rossum)
  • [30] Whatever happened to 'nonlocal x = y'? (Guido van Rossum)

I think it's needless added complexity (それは不必要に追加された複雑性だと私は考える)
that helps save one line of code in very few use cases. (【ちょっと意訳】非常に限られた局面でコードを1行短く書けるようにするという複雑性)

nonlocal x = 3global aa=[]と書けるようにしないことによってPythonの中に守られるsimplicity(シンプルさ)があるということなんだと思います。書く側がglobal aa=[]ではなくglobal aa; aa=[]と書くほうが多分Pythonicなんだと思います。

投稿2019/01/12 14:38

編集2019/01/12 14:53
YouheiSakurai

総合スコア6142

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

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

KSwordOfHaste

2019/01/12 15:05

具体的根拠が挙げられていてとても参考になるなぁ(回答のしかたそのもの含めて!)と感じました。 読み物としてもおもしろいですね~
YouheiSakurai

2019/01/12 15:14

いえいえ、とんでもないです、恐縮です、褒めていただきありがとうございます。KSwordOfHasteさんの回答も、逆にPEPを頼らずに複雑性にまで考えがたどり着いていて感嘆しました。こちらも勉強になりました。
guest

0

関数内でグローバル変数に宣言と当時に代入できない仕様の意図

個人的な推測にすぎず、どこかでその根拠を見聞きしたわけではないですが・・・

Pythonの代入文は結構複雑な構文と機能を持っています。

https://docs.python.org/ja/3.7/reference/simple_stmts.html#assignment-statements

特に複数の変数に対して一つの代入文で値を設定できる点を考えますと、仮に「global/nonlocal宣言」と「代入」を同時に許すなら仕様の連続性(整合性)から

a, global b, nonlocal c = 1, 2, 3
global (a, b), nolocal (c, *d) = 1, 2, 3, 4, 5

なぁんて代入文もゆるさなくてはならず、(できなくはないのでしょうが)どれがglobal(あるいはnonlocal)なのか少々見づらいため、もともと変数を宣言せずにいきなり代入するのが普通なpythonでglobal/nonlocalという特殊な変数宣言だけのために代入文の構文をこれ以上複雑にしたくなかったのではないかと思いました。

さらにいえば、代入に付けられるなら「参照と宣言を同時に行う」ようなことを望む人がでやしないでしょうか?それがわるい構文かどうか総合的に言えるほどの知見がないですが、それを導入してしまうと構文規則がややこしいことになりそうな予感はします。

python

1def foo(): 2 ... 3 a = global g # うわぁ・・・ 4 a += 1 5 g = a * 2

また、Pythonの変数スコープは主として関数全体にわたる(lambda式の仮引数や内包表記やジェネレーター式など一部そうでないものがあるが)が基本であり、

python

1def foo(): 2 i = 0 3 for i in range(10): 4 print(i) 5 print(i)

上記のiのように有効範囲が広くなりがちなので「なるべくなら関数先頭に変数の種類の宣言のみ行う」方が見やすい(分かり易い)という狙いがあったのかも知れません。

投稿2019/01/12 14:54

編集2019/01/12 16:07
KSwordOfHaste

総合スコア18392

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

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

0

grobal付きは、変数宣言ではなく、グローバル変数を参照する定義、なので初期化できません

変数宣言してるところでしか初期化できません

投稿2019/01/12 13:23

y_waiwai

総合スコア87719

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

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

eggpol

2019/01/12 13:29 編集

早速のご回答ありがとうございます 2つさらに聞きたいことができたのですがよろしいでしょうか。 1. この仕様の背景としてメソッドでグローバル変数を使うということを 明示したいため初期化できないようになっているのでしょうか 2. このようになPython言語の仕様を説明しているおすすめのサイトや書籍などありますでしょうか (公式のリファレンスを見てもさっぱりわからないのでかみ砕いたものが良いです) 注文が多くて申し訳ないですがよろしくお願いします
y_waiwai

2019/01/12 13:47

いや、global付きは変数宣言ではないんですよ。 どこか別のところにある変数を、ここでグローバル変数として使いますという定義なだけで、このコードでなにか処理が発生するもんではないため、ここで「初期化」はできない、と理解してます なにか資料を見てこういう理解した、というわけではないので具体的な資料は示せませんです
guest

0

構文リファレンスを見てください。

https://docs.python.jp/3/reference/simple_stmts.html?highlight=global#the-global-statement

構文の定義

global_stmt ::= "global" identifier ("," identifier)*

意味

global 文は、列挙した識別子をグローバル変数として解釈するよう指定することを意味します。


代入できない理由ですが、そもそもpythonのスコープはレキシカルスコープといって構文を見ればスコープが決定されるような仕様になっています。なので、global文は構文解析の時点で処理されます(リファレンスにもそう書いてある)。

代入文はもちろん実行時に実行されるので、一緒に処理できないですね。


ところで質問文のコード、methodといいつつやっていることはトップレベル関数の定義なので、functionとでもした方が個人的には好みかな・・・

投稿2019/01/12 13:52

hayataka2049

総合スコア30933

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問