「インポート*」が悪いのはなぜですか?


153

import *Pythonでは使用しないことをお勧めします。

誰もがその理由を教えてくれますか?そうすれば次回はそれを避けることができますか?



2
再利用する必要のあるスクリプトを記述しているのか、コードを記述しているのかによって異なります。コード標準を無視することは時々お金がかかります。「インポート*」は、どこから来たのかを明確にする命名規則がある場合にも問題ありません。例:「from Cats import *; TabbyCat; MaineCoonCat; CalicoCat;」
gatoatigrado 2010

3
import *Pythonの2または3で最初の場所で私のために動作しません
joshreesjones

1
これはあなたの質問に答えますか?「インポート*」は正確に何をインポートしますか?
AMC

回答:


223
  • 名前空間に多くのものを配置するためです(以前のインポートから他のオブジェクトをシャドウする可能性があり、それについてはわかりません)。

  • 何がインポートされたのか正確にわからず、特定のものがインポートされたモジュール(読みやすさ)を簡単に見つけることができないため。

  • pyflakesコード内のエラーを静的に検出するようなクールなツールを使用できないからです。


2
ええ、私は誰かが*インポートを使用するとき、私の仕事を本当に嫌っています。なぜなら、私はpyflakesを実行して幸せになるだけでなく、それらのインポートを修復する必要があるからです。pyflakesを使用すると、次のことができるので便利です:-)
gruszczy

7
具体的な例として、NumPyの多くのユーザーは、numpy.anyシャドウイングanyを行うfrom numpy import *か、「役立つ」ツールを使用してシャドウイングすることで噛まれています。
user2357112は

1
同じ理由でIPythonの--pylabスイッチの使用を避けるべきですか?
timgeb 2014

6
これを読む前に思いもしなかったリスクを強調するため(「以前のインポートから他のオブジェクトをシャドウする可能性がある」):ステートメントimport *順序import重要にします...通常はインポートの順序を気にしない標準ライブラリモジュールでも。importかつての輸入戦争の犠牲者が唯一の生存者となった場合、声明をアルファベット順に並べるような無邪気なことがスクリプトを壊す可能性があります。(スクリプトが現在機能し、変更されない場合でも、インポートされたモジュールが、依存していた名前に代わる新しい名前を導入すると、後で突然失敗する可能性があります。)
Kevin J. Chase

49

禅のPythonによると:

明示的は暗黙的よりも優れています。

...確かにそれを議論することはできませんか?


29
実際、あなたはそれについて議論することができます。また、Pythonで変数を明示的に宣言しないと、完全に一貫性がなくなります。変数を割り当てると、変数が存在するようになります。
Konrad Rudolph

7
@gruszczy:変数の宣言は何に冗長ですか?割り当てますか?いいえ、それは2つの別個の概念であり、何かを宣言することは非常に明確で重要な情報を伝えます。とにかく、明示性は常に冗長性にいくらか関連しており、それらは同じコインの2つの面です。
Konrad Rudolph

3
@kriss正しいが、それは私の趣旨ではなかった。私の要点は、変数を明示的に宣言しないとエラーが発生するということでした。あなたは「[宣言]なしの割り当ては不可能である」と言います。しかし、それは間違っています。私の要点は、Pythonが残念ながら正確にそれを可能にするということです。
Konrad Rudolph

3
@kriss 宣言によってコンパイラに提供されるもう1つの情報は、実際に新しい変数を宣言するつもりであるという事実です。これは、型システムにとって重要な情報です。最近のIDEはタイプミスの問題を解決すると言いますが、それは単に間違っています。実際、これは静的にコンパイルされていない言語では重大な問題であり、Perlが追加した理由ですuse strict(JavaScript var)。余談ですが、もちろんPythonは型なしではありません(実際には強く型付けされています)。とにかく、でもあればあなたが正しかった、これはまだのPythonの禅と矛盾するだろう、この回答で引用。
Konrad Rudolph

3
@kriss間違っています。同じ変数名の再利用は問題ではありません。同じ変数の再利用は同じです(つまり、同じスコープ内の同じ名前)。明示的な宣言はこの間違いを正確に防止します(そして他のことは、私が言ったように、Perlライクでは問題がより大きくなることは正しいとはいえ、実際には非常に一般的で時間のかかる問題です)言語)。そして私が暗示する矛盾は、ここで窓から投げ出された禅の明示性の要件です。
Konrad Rudolph

40

**locals()関数にパスしないのですか?

Pythonには「include」ステートメントがなくselfパラメータは明示的であり、スコープ規則は非常に単純であるため、通常、他のモジュールを読み取ったり、種類を指定したりせずに、変数を指で指して、そのオブジェクトがどこから来たかを伝えるのは非常に簡単です。 IDEの(これは、とにかくイントロスペクションの方法が制限されており、言語が非常に動的であるという事実によって)。

import *休憩すべてのこと。

また、バグを非表示にする具体的な可能性もあります。

import os, sys, foo, sqlalchemy, mystuff
from bar import *

これで、barモジュールに「os」、「mystuff」などの属性がある場合、それらは明示的にインポートされた属性をオーバーライドし、非常に異なるものを指す可能性があります。定義__all__暗黙的にインポートされるか、この状態- -バーにすることは賢明なことが多いですが、オブジェクトが読み込みとバーモジュールを解析し、次ずに、どこから来た、まだそれが追跡するのは難しい輸入を。import *プロジェクトの所有権を取得するときに最初に修正するのは、ネットワークです。

私を誤解しないでください。もしimport *欠けていたら、私はそれを持っていると叫びます。ただし、慎重に使用する必要があります。良い使用例は、別のモジュール上にファサードインターフェイスを提供することです。同様に、条件付きインポートステートメント、または関数/クラスの名前空間内のインポートを使用するには、多少の規則が必要です。

中規模から大規模のプロジェクト、または複数の貢献者がいる小規模なプロジェクトでは、静的分析(少なくともpyflakesを実行するか、適切に構成されたpylintを実行する)の観点から、最小限の衛生が必要であり、以前にいくつかの種類のバグをキャッチする必要があります彼らが起こります。

もちろん、これはpythonなので、自由にルールを破って調査してください。ただし、10倍に成長する可能性のあるプロジェクトには注意してください。ソースコードに規律がない場合は問題になります。


6
Python 2.xに「include」ステートメントがあります。と呼ばれていexecfile()ます。幸い、3.xではめったに使用されなくなりました。
Sven Marnach

**vars()呼び出された関数が別のファイルにある場合、グローバルを含めるのはどうですか?:P
ソロモンウッコ

16

from ... import *対話型セッションで実行しても問題ありません。


doctest文字列の内部はどうですか?んimport *getが、この場合には、「サンドボックス」内に解釈しましたか?ありがとう。
PatrickT

16

名前空間を汚染しているからです。すべての関数とクラスを独自の名前空間にインポートします。これは、自分で定義した関数と競合する可能性があります。

さらに、メンテナンスタスクでは修飾名を使用する方がわかりやすいと思います。コード行自体に関数の出所が表示されるので、ドキュメントをはるかに簡単にチェックアウトできます。

モジュールfoo:

def myFunc():
    print 1

あなたのコードで:

from foo import *

def doThis():
    myFunc() # Which myFunc is called?

def myFunc():
    print 2


9

fooというモジュールに次のコードがあるとします。

import ElementTree as etree

そして、あなた自身のモジュールであなたは持っています:

from lxml import etree
from foo import *

これで、デバッグが難しいモジュールにlxmlのetreeが含まれているよう見えますが、実際にはElementTreeが含まれています。


7

これらはすべて良い答えです。新しい人々にPythonでのコード作成を教えるときに、import *は非常に難しいます。あなたや彼らがコードを書かなかったとしても、それはまだつまずきです。

私は子供(約8歳)に、Minecraftを操作するためにPythonでプログラミングすることを教えています。(Atomエディター)で動作し、REPL駆動の開発を(bpythonを介して)教えるのに役立つコーディング環境を彼らに提供したいと思います。Atomでは、ヒント/補完がbpythonと同じくらい効果的に機能することがわかりました。幸い、他の統計分析ツールとは異なり、Atomはにだまされませんimport *

ただし、この例を見てみましょう... このラッパーでfrom local_module import *、これらのブロックのリストを含むモジュールを束にしています。名前空間の衝突のリスクを無視しましょう。そうfrom mcpi.block import *することで、これらの不明瞭なタイプのブロックのリスト全体を、利用可能なものを知るために調べなければならないものにします。代わりにを使用したfrom mcpi import block場合は、入力するwalls = block.とオートコンプリートリストがポップアップ表示されます。 Atom.ioスクリーンショット


6

ここで人々が述べた有効なポイントを理解しました。ただし、「スターのインポート」が必ずしも悪い習慣であるとは限らない可能性があるという意見があります。

  • すべての定数が呼び出されるモジュールに行くようにコードを構造化したいとき const.py
    • もしそうならimport const、すべての定数について、それをとして参照する必要がありますがconst.SOMETHING、これはおそらく最も便利な方法ではありません。
    • 私がそうするならfrom const import SOMETHING_A, SOMETHING_B ...、明らかにそれはあまりに冗長すぎて、構造化の目的を無効にします。
    • したがって、私はこの場合、a from const import *を行う方が良い選択だと感じます。

4

次の2つの理由から、これは非常に悪い習慣です。

  1. コードの読みやすさ
  2. 変数/関数などをオーバーライドするリスク

以下のためのポイント1:レッツは、この例を参照してください。

from module1 import *
from module2 import *
from module3 import *

a = b + c - d

ここでは、コードを見る上で、誰がどのモジュールからに関するアイデアを取得しないだろうbcd実際に属している。

逆に、あなたがそれを好きなら:

#                   v  v  will know that these are from module1
from module1 import b, c   # way 1
import module2             # way 2

a = b + c - module2.d
#            ^ will know it is from module2

それはあなたにとってはるかにきれいです、そしてあなたのチームに加わる新しい人はより良い考えを持つでしょう。

以下のためのポイント2:両方を言ってみましょうmodule1module2として変数を持っていますb。私がする時:

from module1 import *
from module2 import *

print b  # will print the value from module2

ここからの値module1は失われます。でb宣言されていてもコードが機能しない理由をデバッグするのは難しくmodule1、コードが使用することを期待してコードを記述しましたmodule1.b

異なるモジュールに同じ変数があり、モジュール全体をインポートしたくない場合は、次のようにすることもできます。

from module1 import b as mod1b
from module2 import b as mod2b

2

テストとして、「A 1」と「B 1」をそれぞれ出力する2つの関数AとBを持つモジュールtest.pyを作成しました。test.pyをインポートした後:

import test

。。。2つの関数をtest.A()とtest.B()として実行できます。「test」は名前空間のモジュールとして表示されるため、test.pyを編集すると、次のように再ロードできます。

import importlib
importlib.reload(test)

しかし、私が次のことをした場合:

from test import *

名前空間には "test"への参照がないため、編集後に(私が知る限り)再読み込みする方法はありません。これは、対話型セッションの問題です。一方、次のいずれかです。

import test
import test as tt

名前空間にモジュール名として「テスト」または「tt」を(それぞれ)追加します。これにより、再ロードが可能になります。

私が行った場合:

from test import *

名前「A」と「B」は名前空間に関数として表示されます。test.pyを編集して上記のコマンドを繰り返すと、変更されたバージョンの関数がリロードされません。

そして、次のコマンドはエラーメッセージを引き出します。

importlib.reload(test)    # Error - name 'test' is not defined

「from module import *」でロードされたモジュールをリロードする方法を誰かが知っている場合は、投稿してください。それ以外の場合、これはフォームを回避するもう1つの理由です。

from module import *

2

ドキュメントで提案されているように、運用import *コードでは(ほとんど)使用しないでください。

モジュール*からインポートすることは悪いことですパッケージから*をインポートすることはさらに悪いことです。デフォルトでは、以前に読み込まれたパッケージのサブモジュールを含むfrom package import *、パッケージので定義されている名前をインポートします。__init__.pyimportステートメント。

ただし、パッケージの__init__.pyコードでという名前のリストが定義__all__されている場合from package import *は、が検出されたときにインポートする必要があるサブモジュール名のリストと見なされます。

次の例を考えてみます(に何も__all__定義されていないと仮定しますsound/effects/__init__.py):

# anywhere in the code before import *
import sound.effects.echo
import sound.effects.surround

# in your module
from sound.effects import *

最後のステートメントは、echoおよびsurroundモジュールを現在のネームスペースにインポートします(以前の定義を上書きする可能性があります)。これらはステートメントの実行sound.effects時にパッケージで定義されているためimportです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.