web-dev-qa-db-ja.com

モジュールのインポートを伴う名前空間

私はPython=を学習しており、まだ1年ほど勉強していますが、まだ初心者です。メインモジュール内で呼び出される関数のモジュールを記述しようとしています。それぞれ呼び出されたモジュールの関数を実行するには数学モジュールが必要です。呼び出されたモジュール内に数学モジュールをインポートせずにこれを行う方法があるかどうか疑問に思っています。

main.py

from math import *
import module1

def wow():

    print pi


wow()
module1.cool()

module1.py

def cool():

    print pi

main.pyを実行すると、次のようになります。

3.14159265359

Traceback (most recent call last):
  File "Z:\Python\main.py", line 10, in <module>
    module1.cool()
  File "Z:\Python\module1.py", line 3, in cool
    print pi
NameError: global name 'pi' is not defined

main.pyの実行時に名前エラーが発生するのはなぜですか。 piが変数にアクセスできるため、変数wowはインポート時にメインモジュールに対してグローバルになることを知っています。また、module1.coolを出力して<function cool at 0x02B11AF0>を取得できるため、coolがインポート時にメインモジュールに対してグローバルになることも知っています。したがって、coolはメインモジュールのグローバルネームスペース内にあるので、プログラムは最初に関数cool内で変数piを探し、次に、そうでない場合はtそこにそれを見つけて、mainモジュールの内部で変数piを探し、それを見つけるがありますか?

これを回避する唯一の方法は、数学モジュールをmodule1.py内にインポートすることです。私はそれの考えが好きではありません、なぜならそれは物事をより複雑にし、私はニースで単純なコードのファンだからです。名前空間の把握に近づいているような気がしますが、これについては助けが必要です。ありがとう。

17
SpencerAAA

トレースバックが示すように、問題はmain.pyではなくmodule1.pyにあります。

Traceback (most recent call last):
  File "Z:\Python\main.py", line 10, in <module>
    module1.cool()
  File "Z:\Python\module1.py", line 3, in cool
    print pi
NameError: global name 'pi' is not defined

つまり、in module1はインポートされていないため、グローバル名piはありません。 from math import *main.pyを実行すると、すべてがmathモジュールの名前空間からmainモジュールの名前空間にインポートされ、everyモジュールの名前空間にはインポートされません。

ここで欠落している重要な点は、各モジュールに独自の「グローバル」名前空間があるということです。 Cなどの言語では、すべてのextern変数と関数で共有される単一のグローバル名前空間があるため、これは最初は少し混乱する可能性があります。しかし、その仮定を通過すると、Pythonの方法は完全に理にかなっています。

したがって、module1piを使用する場合は、from math import *module1.pyを実行する必要があります。 (または、他の方法で注入することもできます。たとえば、module1.pyfrom main import *を実行でき、main.pymodule1.pi = piを実行できます。または、piを魔法のbuiltins/__builtin__モジュール、またはその他のさまざまなトリックを使用します。ただし、明らかな解決策は、インポートする場所でimportを実行することです。)


補足として、通常、対話型インタープリターや、場合によってはトップレベルのスクリプトを除いて、from foo import *を実行することは望ましくありません。例外があります(たとえば、いくつかのモジュールはそのように使用するように明示的に設計されています)。ただし、経験則ではimport fooまたは制限付きfrom foo import bar, bazを使用します。

23
abarnert

「明示的は暗黙的より良い」は、Python(launch python and run _import this_))の作成者が行った設計上の決定です。

したがって、module1.cool()を実行すると、Pythonはpiモジュールで未定義のmainを検索しません。


数式モジュールを使用するときはいつでも明示的にインポートする必要があります-これがPythonの動作方法です。

また、_from X import *_スタイルのインポートは避けてください。これも悪い習慣です。ここでは、次のことができます:_from math import pi_。

6
Thomas Orozco

@abarnertのコメントで言及されているexec(python 3)またはexecfile(python 2)の単純なアプローチは、一部のワークフローで役立つ場合があります。必要なのは、インポート行を次のものに置き換えるだけです。

exec( open("module1.py").read() )       # python 3

次に、cool()ではなくmodule1.cool()を使用して関数を呼び出すだけです。 cool()内では、OPが当初期待していたように、変数piはグローバルのように動作します。

簡単に言うと、これは、メインプログラムの上部に表示され、長所と短所の両方がある関数定義を単に隠すことです。複数のモジュールとインポートを含む大規模なプロジェクトでは、適切な名前空間の代わりにexecを使用するのはおそらく間違いです。これは、単一のグローバル名前空間内にあまり多くのものを保持したくないためです。

ただし、単純なケース(シェルスクリプトとしてPythonを使用する場合など)の場合、execを使用すると、グローバル名前空間を共有しながら共有関数を非表示にする簡単で簡潔な方法が得られます。この場合、関数の名前の付け方をさらに検討する必要があります(たとえば、v1_coolv2_coolを実行できないため、v1.coolv2.coolを使用して、異なるバージョンを追跡します)。

ここでexecを使用することの明らかでない欠点の1つは、これを回避することはできますが、実行されたコードのエラーがエラーの行番号を表示しない可能性があることです。 エラーの行番号を取得する方法execまたはPythonのexecfile

3
JohnE

他の人が言ったように、実際にはmodule1にグローバルpiはありません。 piからmathを1回だけインポートし、explicitlyをインポートするのが適切な解決策は、取得しているpimodule1から:

main.py

import module1

def wow():
    print module1.pi

wow()
module1.cool()

module1.py

from math import pi

def cool():
    print pi
2
askewchan

モジュール内では、単にfrom math import pi、これはpiを数学からインポートするだけで、数学モジュール全体はインポートしません。

1
Saucier