web-dev-qa-db-ja.com

Python: 'from <module> import *'を禁止する必要があるのはなぜですか?

あなたが持っている場合

from <module> import *

プログラム(またはモジュール)の途中で、次の警告が表示されます。

/tmp/foo:100: SyntaxWarning: import * only allowed at module level

理由を理解していますimport *は一般的に推奨されていませんが(名前空間の非表示)、特にコードが誰とも共有されていない場合は、便利であることがわかる状況がたくさんあります。

だから、誰もがなぜfrom <module> import *すべての可能な場合に禁止されるべきですか?

28
OTZ

「プログラムの途中」で、インポートについて話していると思いますinside関数定義:

def f():
    from module import *    # not allowed

関数の本体の最適化が難しくなるため、これは許可されていません。 Python実装は、関数をバイトコンパイルするときに関数ローカル変数のすべての名前を知りたいので、(CPython)仮想マシンのオペランドスタックでの操作への変数参照を最適化できます、または少なくとも外部名前空間でのルックアップではなく、ローカル変数スロット操作。モジュールの内容全体を関数のローカル名前空間にダンプできる場合、コンパイラはany nameと想定する必要があります。 from module import *によってもたらされる名前のリストは実行時にのみ認識されるため、関数内でモジュールグローバルを参照する可能性があります。

from module import *betweenトップレベルの宣言を置くのはスタイルが悪いですが、許可されています:

def f():
    ...

from module import *

def g():
    ...

2013年4月の編集:他のことを調べていると、この制限がPython 2.1、として "ネストされたスコープ"機能PEP 227 )の結果。リンクからの引用:

変更の副作用の1つは、from module import *およびexecステートメントが、特定の条件下で関数スコープ内で不正にされることです。 Pythonリファレンスマニュアルでは、from module import *はモジュールのトップレベルでのみ有効であると述べていますが、CPythonインタープリターはこれまでこれを強制したことはありません。の実装の一部としてネストされたスコープの場合、Pythonソースをバイトコードに変換するコンパイラは、包含スコープ内の変数にアクセスするために異なるコードを生成する必要があります。from module import *およびexecにより、コンパイラはこれを理解できません。 、コンパイル時に認識できない名前をローカル名前空間に追加するためです。したがって、関数に関数定義または空き変数を含むlambda式が含まれている場合、コンパイラはSyntaxError例外を発生させてこれにフラグを立てます。

これにより、コメントで説明されているPython 3.x vs 2.xの動作が明確になります。これは常に言語仕様に反しますが、CPython 2.1〜2.7はfrom module import *に対してのみエラーを発行します。変数がローカルにバインドされるか、それを含むスコープにバインドされるかを知るコンパイラーの機能に影響を与える可能性がある場合は、関数内。3.xでは、無条件エラーにプロモートされています。

SON OF EDIT:...そして明らかにflashkはこれを数年前に別の回答で指摘し、「What's New in Python 2.1 "まだ。Y'allは今それを賛成します。

24
zwol

あらゆる語彙レベルで、_from amodule import *_は、possibleを使用して、実際の生活で実際の災害を証明した「当時は良いアイデアのように思われた」設計上の決定です。インタラクティブなインタープリタープロンプトでの便利な探索を除いて(それでも、私はそれほど熱心ではありません-_import module as m_は、代わりに修飾名を使用するように2つの余分な文字のみを強制します[[ちょうど_m._プレフィックス]] 、and修飾名は、help(m)reload(m)などでmを使用できる探索的なインタラクティブな状況で非常に役立つことは言うまでもなく、常に裸の名前よりもシャープで柔軟性があります。 )。

この厄介な構造は、コードを読んでいる貧しい人(デバッグを助けるために運命づけられた試みで)が不思議に見える名前がどこから来ているのかを理解するのを非常に難しくします-構造が複数回使用されている場合は不可能です語彙レベル;しかし、一度だけ使用した場合でも、モジュール全体を毎回面倒に読み直す必要があります。そうすると、その困惑した裸の名前はモジュールからのものでなければならないことを確信できます。

さらに、モジュールの作成者は通常、問題の恐ろしい構造を「サポート」するために必要な極端な問題には行きません。たとえば、コードのどこかに_sys.argv_(そしてもちろんモジュールの最上部にある_import sys_)を使用している場合、どのようにknowsysは、あるべきモジュールです...または_... import *_?!からの完全に異なるモジュール(または非モジュール)です。これに使用しているすべての修飾名を掛けると、悲惨さが唯一の最終結果になります。それと、長くて骨の折れるデバッグを必要とする不思議なバグです(通常、を行う人のしぶしぶ助けを借りて)Pythonを「取得」...!-)。

関数内では、任意のローカル名を追加およびオーバーライドする方法はさらに悪くなります。初歩的ではあるが重要な最適化として、Pythonコンパイラは、各ベアネームの割り当てまたはその他のバインディングステートメントについて関数の本体を調べ、割り当てられた名前を「ローカル」と見なします(他の名前は_import *_を使用すると(名前付けとして使用する明示的なdictがない_exec somestring_の場合と同様)、突然、どの名前がローカルで、どの名前がグローバルであるかが完全に謎になります- -そのため、貧弱なコンパイラは、ローカル変数にdictを使用し(通常使用するコンパクトな「ベクトル」の代わりに)、参照されるベアネームごとに最大3つのdictルックアップを実行して、名前ルックアップごとに可能な限り遅い戦略に頼らなければなりません。 、 何度も。

任意のPythonインタラクティブプロンプト。タイプ_import this_。何が表示されますか?Pythonの禅。そのテキストの最後の、そしておそらく最大の知恵は何ですか...?

名前空間は素晴らしいアイデアの1つです。もっと多くのことをしましょう!

修飾名がsoである場合にベアネームの使用を強制することにより、基本的に、この賢明な推奨事項の非常に反対を実行します。名前空間の素晴らしさと優れた機能を賞賛し、それらをさらに実行すると、分解2つの完全に優れたすぐに使用できる名前空間(モジュールの名前空間)になります。再インポート、およびインポートするレキシカルスコープのインポート)を使用して、単一の、不潔で、バグが多く、遅く、硬く、使用できない混乱を引き起こします。

戻ってoneの初期の設計決定を変更できればPython(def、特にlambdaを使用するため、難しい選択です。 Javascriptがはるかに読みやすくfunctionと呼んでいるものはすぐ近くにあります;-)、Guidoの心から_import *_のアイデアをさかのぼって一掃します。申し立てられたの量はありません。 /インタラクティブプロンプトでの探索の利便性は、それが引き起こした悪の量のバランスをとることができます...!-)

16
Alex Martelli

Python 2.1 のリリースノートは、この制限が存在する理由を説明しているようです。

変更の副作用の1つは、fromモジュールのimport *およびexecステートメントが、特定の条件下で関数スコープ内で不正になったことです。 Pythonリファレンスマニュアルでは、モジュールのインポートから*はモジュールのトップレベルでのみ有効であると述べていますが、CPythonインタープリターはこれまでこれを強制したことはありません。ネストされた実装の一部としてスコープ、Pythonソースをバイトコードに変換するコンパイラは、含まれているスコープ内の変数にアクセスするために異なるコードを生成する必要があります。モジュールのインポート*とexecにより、コンパイラはこれを理解できなくなります。これらは、コンパイル時に認識できない名前をローカルネームスペースに追加します。したがって、関数に関数定義または自由変数を含むラムダ式が含まれている場合、コンパイラーはSyntaxError例外を発生させてこれにフラグを立てます。

12
flashk

禁止されていません。なぜなら...

...簡単なスクリプトやシェルの探索に便利です。

...しかし、深刻なコードでそれを保持するべきではありません

  1. 知らない名前をインポートしたり、ローカル名を消去したりする可能性があります
  2. コードで何が使用されているかを知ることはできません。スクリプトの依存関係を知ることは困難です。
  3. コード補完は正しく機能しなくなります
  4. 「この変数は宣言されていません」などのIDEの便利なチェックは機能しなくなりました
  5. 循環インポートの作成が簡単になります
4
e-satis

禁止されているわけではありません。正常に動作しますが、一般的に悪い考えであるため(他の人が行った理由により)、警告が表示されます。必要に応じて、警告を抑制することができます。警告モジュールは、そのために必要なものです。

1
kindall

他の人が詳細な答えを与えました、私は私の理解の簡単な概要の答えを与えます..あなたから使用するときは、modulename.functionameを実行せずにインポートしたモジュール内の任意の関数を直接呼び出すことができるようにします(あなたはただ呼び出すことができます"functionname")これは、異なるモジュールに同じ名前の2つの関数がある場合に問題を引き起こし、また、それが属するオブジェクト/モジュールがわからないため、多くの関数を処理するときに混乱を引き起こす可能性があります(の観点から)よく知らないすでに書かれたコードを見ている人)

0
Rick