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

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

詳細はこちら
スコープ

スコープとは、プログラム内で変数名など、参照可能な有効範囲のことを指します。

関数

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

Python

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

Q&A

解決済

3回答

1678閲覧

pythonの関数のスコープの制限がしたい

fkubota

総合スコア42

スコープ

スコープとは、プログラム内で変数名など、参照可能な有効範囲のことを指します。

関数

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

Python

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

0グッド

0クリップ

投稿2020/12/06 04:14

前提・実現したいこと

以下の例で説明します

aaa = 1 def hoge(b): c = aaa + b return c print(hoge(2)) # >> 3

hoge関数を実行したときにエラーが出るようにしたいです。
hoge関数内にglobal変数aaaがありますが、これは、引数で渡したわけでもなく、関数内で定義したローカル変数でもありません。
この時にエラーが出るようにしたいです。

hoge関数への影響は、引数の入力のみに依存するような仕様にしたいためです。
なにかいい方法はないでしょうか?

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

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

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

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

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

guest

回答3

0

ベストアンサー

hoge関数への影響は、引数の入力のみに依存するような仕様にしたいためです。

他で定義したモジュール、関数やクラスも使えなくなりますが、
そのような仕様で大丈夫ですか?

python

1def no_globals(func): 2 import types 3 return types.FunctionType(func.__code__, {}, func.__name__) 4 5 6aaa = 1 7 8@no_globals 9def hoge(b): 10 c = aaa + b 11 return c 12 13hoge(1) # NameError: name 'aaa' is not defined

問題点: 外部の関数、クラス、モジュールも使えなくなる。
Pythonでは関数等も変数に格納されるオブジェクトです。

FunctionTypeの第二引数に許可するグローバル変数の辞書を与えることで回避できますが、
不用意に使われるグローバル変数の抑制にはなりません。変数辞書の管理が発生します。

※ 複雑になるのでコードは割愛しますが、
「外部の変数」がネストした関数内で作られる変数を参照する場合は、
グローバル変数ではなくクロージャです。


質問の意図としては、グローバル変数を全て禁止ではなく、
グローバル変数の乱用を抑制したいのだと思うので、

どちらかというと実行時のエラーよりも
コーディング規約や静的検査ツールで対応すべきだと思います。

解決策、提案できるとしたらプロジェクトの運用方法での対策

  • 定数は大文字のみにする。mypy での定数宣言、等のコーディング規約の導入。
  • コーディング規約を検査するコードの静的検査ツールの導入
  • コードレビューの実施 (github 等を使っていれば、プルリクエスト時にレビューするような運用方法を決める)

投稿2020/12/06 05:50

teamikl

総合スコア8722

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

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

fkubota

2020/12/06 09:08

ありがとうございます! 頂いた方法をもとに調査してみたところ、 こちらの方法が見つかりました! https://gist.github.com/raven38/4e4c3c7a179283c441f575d6e375510c 意図としては、jupyter notebook利用を想定しておりglobal変数はどうしてもでてきてしまうので解決したいということでした。 解決できました。ありがとうございました!
teamikl

2020/12/06 10:42 編集

コピーするグローバル変数の辞書は、宣言時のものなので 後方で定義する関数は含まれない点には注意です。 (副作用として、グルーバル変数以外への影響もある) jupyter notebook での利用に限定するなら、 後ろのセルから実行することは稀なので、 あまり問題ないかもしれませんね。 代案としては、applyデコレータで関数を定義時に実行する方法。 https://wiki.python.org/moin/PythonDecoratorLibrary#Creating_decorator_with_optional_arguments ※ python2 にあった組込関数のapply は python3で廃止されました。 他にwith ステートメントで擬似的にスコープを作る方法等も 試したことありますが、このようなデコレータの類は使わなくとも、 名前空間を汚したくない場合は、スコープの為だけでも 関数を作って実行という形にしたほうが良いです。
guest

0

やりたいことと違うかもしれませんが、モジュールに分けるのはどうでしょう。

別ファイル(fuga.py)で関数を定義して、

fuga.py

1def hoge(b): 2 c = aaa + b 3 return c 4

本体のスクリプトからimportして使います。

main.py

1from fuga import hoge 2 3aaa = 1 4 5hoge(0) 6# エラー

他には、stackoverflowで探すと、こんな方法もあるようです。
https://stackoverflow.com/a/31047259

投稿2020/12/06 05:59

bsdfan

総合スコア4794

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

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

0

pythonの言語仕様上、そのような方法はないと思います。

上記の場合、hoge関数内のローカル変数として使うつもりの「aaa」を、
・hoge関数内で初期化せず
・誤ってグローバル変数と同じ名前で使ってしまったこと
の2つがバグの原因ということになります。
hoge関数内で初期化(例:aaa=0)していさえすれば、グローバルスコープにあるものと同じ名前でもhoge関数のローカル変数として扱われるはずですので。

上記を回避するには

・そもそも、グローバル変数を使わない。
・グローバル変数の命名に一定の規則を設け、ローカルとグローバルで名前が絶対に重ならないようにする
・linterを使う

等になるでしょうか。
https://stackoverflow.com/questions/31023060/disable-global-variable-lookup-in-python

投稿2020/12/06 05:16

編集2020/12/06 05:16
sfdust

総合スコア1137

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問