32

あなたがたまたま持っているなら

from <module> import *

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

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

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

それで、誰もfrom <module> import *がすべての可能な場合に禁止されるべきである理由を正確に詳細に説明できますか?

4

6 に答える 6

29

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

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

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

トップレベルの宣言from module import * の間に入れるのはスタイルが悪いですが、許可されています:

def f():
    ...

from module import *

def g():
    ...

2013年4月の編集:他のことを調べていると、「ネストされたスコープ」機能PEP 227)の結果として、この制限がPython2.1で導入されたことがわかりました。リンクからの引用:

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

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

SON OF EDIT: ...そして明らかにflashkは、「Python 2.1の新機能」の同じ段落を引用して、数年前に別の回答でこれを指摘しました。Y'allは今それを賛成します。

于 2010-08-26T01:59:42.403 に答える
17

あらゆる語彙レベルで、インタラクティブなインタプリタプロンプトでの便利な探索を除いfrom amodule import *て、実際の生活で実際の災害を証明した「当時は良いアイデアのように見えた」設計決定です(それでも、私はあまり暑くありませんその上で-代わりに修飾名を使用するように2つの余分な文字のみを強制します[[接頭辞のみ]]、修飾名は常に裸の名前よりもシャープで柔軟性があります。など!)。import module as mm.mhelp(m)reload(m)

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

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

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

Pythonインタラクティブプロンプトに移動します。タイプimport this。何が見えますか?Pythonの禅。そのテキストの最後の、そしておそらく最大の知恵は何ですか...?

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

修飾名が非常に望ましい場合にベアネームの使用を強制することにより、基本的にこの賢明な推奨事項とは正反対のことを行います。名前空間の素晴らしさとホンキングチュードを賞賛する代わりに、それらの多くを行うのではなく、 2つを完全に分解します。すぐに使用できる優れた名前空間(インポートするモジュールの名前空間と、インポートする字句スコープの名前空間)を使用して、単一の、不潔で、バグが多く、遅く、堅固で、使用できない混乱を引き起こします。

Pythonで初期の設計上の決定を1つ変更できれば(これは難しい選択です。def特にlambda、Javascriptを使用すると、非常に読みやすいように呼び出されるので、すぐに呼び出されます;-)、 Guidoのアイデアfunctionをさかのぼって一掃します。import *マインド。インタラクティブなプロンプトで探索するのに便利だと言われている量は、それが引き起こした悪の量のバランスをとることができません...!- )

于 2010-08-26T02:21:54.800 に答える
13

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

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

于 2010-08-26T02:02:13.643 に答える
4

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

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

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

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

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

于 2010-08-26T02:03:19.100 に答える
0

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

于 2010-08-26T03:03:01.653 に答える