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

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

新規登録して質問してみよう
ただいま回答率
85.35%
関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

729閲覧

関数内のglobalキーワードの役目が理解できません

swing

総合スコア3

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/04/29 05:23

前提・実現したいこと

参考書片手に勉強を始めました
下記のコードについて、3つ質問致します
素人な質問でお手数を取って申し訳ないのですが、ご教授願います

python

1 2x = 100 3 4def f(): 5 6 global x 7 8 x += 1 9 10 print(x) 11 12f() 13

発生している問題・エラーメッセージ

【質問1】
実行をすると、
101
となります。合っています。
試しに、f()の次の行にprint(x)と書くと
101
となります
関数外なので、100と表示され
101
100
と連なるものだと想定していました
なぜ101になるのでしょうか?

【質問2】
試しに

python

1x=100 2 3def f(x): 4 x+=1 5 print(x) 6 7f(x) 8 9print(x) 10

と書いて実行すると、
101
100
が得られました。
また、

python

1x=100 2 3def f(): 4 a=x+1 5 print(a) 6 7f() 8 9print(x) 10 11

と書いても同様に
101
100
が得られました
globalキーワードが理解できない場合、これらのやり方で逃げても今後、差支えないのでしょうか?

【質問3】
そもそも、globalを用いずに、

python

1x=100 2 3def f(): 4 x+=1 5 print(x) 6 7f() 8

と書いて、
Traceback (most recent call last):
File "C:/Users/tokumoto/Documents/Python Scripts/def-glo-A.py", line 16, in <module>
f()
File "C:/Users/tokumoto/Documents/Python Scripts/def-glo-A.py", line 8, in f
x += 1
UnboundLocalError: local variable 'x' referenced before assignment

なぜ上記のようなエラーになるのかが、わかりません。
関数内のxに外から100を代入すれば、計算可能に思えます
関数内で一旦、xを定義する必要があるのでしょうか?
で、あれば下記は何故、正常に実行(100)されるのでしょうか?

python

1x=100 2 3def f(): 4 print(x) 5f() 6

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

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

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

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

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

maisumakun

2020/04/29 05:25

ところどころ、コード内の記号が全角になっています。意図的でないなら修正をお願いします。
swing

2020/04/29 05:27

すみません修正します
guest

回答2

0

ベストアンサー

参照代入識別子の束縛 を意識する必要があります。
質問1, 2, 3に対して直接の回答ではなく説明になりますがご理解ください。

global 文 - Python 言語リファレンス

global 文は、列挙した識別子をグローバル変数として解釈するよう指定することを意味します。 global を使わずにグローバル変数に代入を行うことは不可能ですが、自由変数を使えばその変数をグローバルであると宣言せずにグローバル変数を参照することができます。

  • global文で宣言しなくてもグローバル変数を参照することはできます。
  • global文で宣言した識別子(変数名)への代入はグローバル変数に対して行われます。

変数の参照は以下の順番に解決されます。

  1. ローカルスコープ: 現在のスコープ、関数内で宣言されたローカル変数。
  2. 外側の関数のスコープ: ネストした一つ外側の関数で宣言されたローカル変数。さらにネストしている場合は順次外側を参照する。
  3. グローバルスコープ: モジュールファイル(一つの__.py__ファイル)のトップレベルで宣言されたグローバル変数。
  4. ビルトインスコープ: 組み込み関数、組み込み変数。宣言は不要。

参照はすでに存在する変数を探索するので上記のように解決できます。
代入はどのスコープに対して行おうとしているのかを指示しないと解決できません。

以下の指示によって代入先が判別されます。

  • 何も宣言しない(いきなり代入しようとした)場合: ローカルスコープに対しての代入
  • global文で宣言した場合: グローバルスコープに対しての代入
  • nonlocal文で宣言した場合: 外側の関数のスコープに対しての代入(外側の関数で先にローカル変数の宣言(代入)を行っておく必要がある。)

UnboundLocalError: local variable 'x' referenced before assignment

上記のエラーの意味は「ローカル変数 x が割り当て前に参照された」ということです。

python

1x = 100 2 3def f1(): 4 x += 1 5 6def f2(): 7 x = x + 1 8 9def f3(): 10 global x 11 x = x + 1

上記のプログラムで f1f2 と同じです。

関数 f2 のパース処理は以下のように行われます。

  1. x = ... の部分で識別子 x がローカル変数として束縛される。
  2. ... = x + 1 の部分で識別子 x の参照を解決するが、(1)でローカル変数として束縛されているため、参照先はローカルスコープとなる。
  3. 未割当(まだ値を代入していない)のため UnboundLocalError が発生する。

関数 f3 のパース処理は以下のように行われます。

  1. global x の部分で識別子 x がグローバル変数として束縛される。
  2. x = ... の部分で識別子 x は(1)でグローバル変数として束縛されているため、代入先はグローバルスコープとなる。
  3. ... = x + 1 の部分で識別子 x の参照を解決するが、(1)でグローバル変数として束縛されているため、参照先はグローバルスコープとなる。

投稿2020/04/29 06:42

Milly

総合スコア167

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

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

swing

2020/04/29 08:31

ご回答ありがとうございます 返信遅くなりすみません >global 文 - Python 言語リファレンス リンクありがとうございます 今後も参考にさせて頂きます また、コードまで書くお手数をとって頂き申し訳ありません ご教授いただきました、「参照か代入か」、「ローカル変数として束縛」の概念なかった事、 グローバル変数は関数外の値を変えずに計算するためのキーワード、と思い込んでいたための質問でした。 (外の値は変えずに、外の値を使って一時的に別の値を得るのだと考えていました) 少しは理解できたと思います、ありがとうございました。
guest

0

質問の内容については、変数のスコープの話です。 プログラミング言語の性質として、この変数スコープがどのようになっているかというのは、その言語を理解する上でとても大事なことです。
詳しいことは、言語の仕様や、書籍・Web記事などで勉強していただくとして、参考程度の話を書きます。

  1. リストpythonの関数は、1つのスコープを作っていて、その中で定義された変数は、その関数内でのみ参照が可能です。
  2. pythonでは、変数に値を代入することで変数を作ることができます(C言語のように、変数定義は必要ない)。
  3. スコープ外の変数は、参照のみ可能です。
  4. 変数をglobalで宣言することで、スコープ外の変数を操作することが可能です。

質問1は、4.で、スコープ外の変数の値が変っています。
質問2は、ちょっと複雑ですが、2.のとおり、引数で渡されたxを使って計算した値を 関数内部で新たに定義した変数x(外部のxとは別)に保存しています。
質問3のエラーは、 x+=1x=x+1であり、 左辺のxがあるため、xは関数内のみの変数であることになり、右辺のxがこの時点で値を持っていないことから発生するエラーです。

お役にたてば

投稿2020/04/29 05:48

TakaiY

総合スコア13790

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

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

swing

2020/04/29 08:03

ご回答ありがとうございます 返信遅くなりすみません >質問1は、4.で、スコープ外の変数の値が変っています。 理解しました。「globalは関数の外の変数を変えない為のモノ」と捉えていました。 外側の変数が変わったらその他にも影響を及ぼすから、変えない方が良いよねと思い込んでしまい、参考書の文脈を早とちりしたようです。実務的にも変えたい時があるのですね。 質問2は関数内で再定義したから実行された 質問3はxが定義されていない状態なのですね 大変、助かりました ありがとうございます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問