🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Python 3.x

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

Q&A

解決済

6回答

2580閲覧

【Python3】UnboundLocalError解決において、変数の位置が関数内でいけないのはなぜでしょうか?

退会済みユーザー

退会済みユーザー

総合スコア0

Python 3.x

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

0グッド

0クリップ

投稿2021/03/17 21:39

編集2021/03/18 22:34

こんにちは。
Pythonでのアルゴリズム入門を学習していて、苦手な部分で詰まっています。
助言をいただきたく、質問しています。

【追記】いただいたご回答に対して

昨日はみなさん、たくさん回答をしていただき、ありがとうございます。
また、ご回答が遅くなっておりますこと、申し訳ございません。
時間が取りにくい、一つ一つ考えて取り組ませていただいており、時間がかかってしまっております。
近日中にみなさんにはコメントにて返信いたしますので、
もう少しお待ちください。

前提・実現したいこと

グローバル変数とローカル変数についてです。
関数外で定義した変数(今回はresult2とします。)を
関数内で使用した場合、実行時にエラーがでました。

result2を関数外で定義したまま、エラーなく処理できる方法があれば教えてください。

※実行している内容は、10進数のものを〇進数へ変換するという内容です。

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

UnboundLocalError: local variable 'result2' referenced before assignment

該当のソースコード

Python

1# nは10進数の値(変換対象)、baseは〇進数(下記は変換する2進数)を記載 2 3n = 18 4 5result2 = "" 6 7def convert(n, base): 8 while n > 0: 9 result2 = str(n % base) + result2 10 n //= base 11 12 13print(convert(n, 2))

以下はテキストの回答になります。

python

1n = 18 2 3def convert(n, base): 4 result2 = "" 5 6 while n > 0: 7 result2 = str(n % base) + result2 8 n //= base 9 return result2 10 11print(convert(n, 2)) 12

試したこと

ローカル変数・グローバル変数の取り扱いに誤りがあると思ったので、
以下の内容を実施しました。

globalの記述を関数外へ追加(2パターン実行)
>>結果、そもそも関数外で定義した変数は、グローバル変数だから無意味

python

1# パターン1 2global result2 = "" # 左のように、関数外の変数を変更 3>> SyntaxError: invalid syntax 4# 変数名にスペース利用しているため

python

1# パターン2 2result2 = "" 3global result2 # results2をグローバル関数にする

globalの記述を関数内で行う。

python

1# パターン1 2def convert(n, base): 3 while n > 0: 4 result2 = str(n % base) + result2 5 global result2 # 追記 6 n //= base 7>> SyntaxError: name 'result2' is used prior to global declaration

「result2は既にglobalで宣言されている」とでたので、

python

1# パターン2 2def convert(n, base): 3 while n > 0: 4 global result2 5 result2 = str(n % base) + result2 6 n //= base 7>> None # printでの出力結果

python

1# パターン3 2def convert(n, base): 3 while n > 0: 4 global result2 5 result2 = str(n % base) + result2 6 n //= base 7 return result2 # returnを追記 8>> 0 # printでの出力結果

補足情報(FW/ツールのバージョンなど)

Google Colab(Python 3.7.10)

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

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

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

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

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

guest

回答6

0

ベストアンサー

公式ドキュメントのよくある質問

Python のローカルとグローバル変数のルールは何ですか?

Python では、関数内で参照されるだけの変数は暗黙的にグローバルとなります。 関数の本体のどこかで値が変数に代入されたなら、それは明示的にグローバルであると宣言されない限り、ローカルであるとみなされます。

とその一つ上

なぜ変数に値があるのに UnboundLocalError が出るのですか?

がよくまとまっていると思います。(まさによくある質問であるからでしょう)

投稿2021/03/17 23:37

quickquip

総合スコア11231

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

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

退会済みユーザー

退会済みユーザー

2021/03/23 01:25

なるほど。 特に「なぜ変数に値があるのに UnboundLocalError が出るのですか?」の記述が一番しっくりきました。
guest

0

公式リファレンスを見ましょう。

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

global 文で列挙する名前は、同じコードブロック中で、プログラムテキスト上 global 文より前に使ってはなりません。

global 文で列挙する名前は、 for ループのループ制御ターゲットや、 class 定義、関数定義、 import 文、変数アノテーションで仮引数として使ってはなりません。

7. 単純文 (simple statement) — Python 3.9.2 ドキュメント

投稿2021/03/17 23:09

Daregada

総合スコア11990

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

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

退会済みユーザー

退会済みユーザー

2021/03/23 01:36

ご回答ありがとうございます。 特に今回のケース、ループのターゲットとして記述しているのがまずかったようですね。 ありがとうございます。
guest

0

結論
ローカル変数とグローバル変数の違いは、
関数の中で定義されているかどうかで決まる。
外:グローバル
中:ローカル

ただし、外で定義した関数について、
再度関数の中で値を再代入などを行うと、ローカルの判定をしてしまう。

今回は、再代入を行ってしまったために、ローカルと判定されてしまっていたということですね。

投稿2021/03/23 01:30

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

0

ためになるスコープの話はたくさん回答されてるので、違うやり方で。

result2を関数外で定義したまま、エラーなく処理できる方法

の意図と違ってしまっているかもですが。引数として明示したほうが間違えにくい気がします(体感

python3

1# nは10進数の値(変換対象)、baseは〇進数(下記は変換する2進数)を記載 2 3n = 18 4 5result2 = "" 6 7def convert(result2, n, base): 8 while n > 0: 9 result2 = str(n % base) + result2 10 n //= base 11 return result2 12 13print(convert(result2, n, 2))

投稿2021/03/18 00:17

jeanbiego

総合スコア3966

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

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

退会済みユーザー

退会済みユーザー

2021/03/23 01:34

ご回答ありがとうございます。 また、引数として明示しておくと、可読性も上がりそうですね。 あと、このコードのおかげで、自分のインデントがおかしいところにも気づけました。 ありがとうございます。 (returnがwhileに含まれるように記述していた。)
guest

0

パターン2 のあとで

result2 を表示すれば

python

1>>> print(result2) 210010

と結果が出ています。つまりこの方法で動いています。

しかし、模範解答にあるように関数の値として返す方が使いやすいので、globalはなるべく使わないようにしましょう。

投稿2021/03/17 23:08

ppaul

総合スコア24670

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

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

退会済みユーザー

退会済みユーザー

2021/03/23 01:37

ご回答ありがとうございます。 わかりました! 利便性的にも模範解答のよう、globalを活用しないような記述を心掛けていきます。
guest

0

グローバル変数を関数内で変更する場合は、その関数内でglobal 宣言を行う必要があります
変数変更の前に宣言しとけばいいだけの話ですね

投稿2021/03/17 22:37

編集2021/03/17 22:39
y_waiwai

総合スコア88038

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

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

退会済みユーザー

退会済みユーザー

2021/03/23 01:43

ご回答ありがとうございます。 今回は関数内外で、同様の変数を活用していたため、そのような動作ができなかったようです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問