webentwicklung-frage-antwort-db.com.de

Warum ist "Import *" schlecht?

Es wird empfohlen, import * nicht in Python zu verwenden. 

Kann jemand bitte den Grund dafür mitteilen, damit ich es beim nächsten Mal vermeiden kann?

121
  • Weil dadurch viel in Ihren Namespace eingefügt wird (möglicherweise werden andere Objekte vom vorherigen Import beschattet, und Sie wissen nichts darüber). 

  • Weil Sie nicht genau wissen, was importiert wird und nicht leicht aus welchem ​​Modul ein bestimmtes Objekt importiert wurde (Lesbarkeit). 

  • Weil Sie keine coolen Tools wie pyflakes verwenden können, um Fehler in Ihrem Code statisch zu erkennen.

186
gruszczy

Nach dem Zen von Python :

Explicit ist besser als implizit.

... kann damit nicht argumentieren?

40
Federer

Sie übergeben **locals() nicht an Funktionen, oder?

Da Python keine "include" -Anweisung enthält, sind und der Parameter self explizit, und die Bereichsregeln für und sind ziemlich einfach. In der Regel ist es sehr einfach, mit dem Finger auf eine Variable zu zeigen und zu sagen, woher das Objekt stammt. - ohne das Lesen anderer Module und ohne jegliche Art von IDE (die ohnehin durch die Introspektion eingeschränkt sind, da die Sprache sehr dynamisch ist).

Der import * bricht das alles.

Es hat auch eine konkrete Möglichkeit, Fehler zu verbergen.

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

Wenn das Bar-Modul über die Attribute "os", "mystuff" usw. verfügt, werden die explizit importierten Attribute überschrieben und möglicherweise auf sehr unterschiedliche Dinge verwiesen. Das Definieren von __all__ in Takten ist oft weise - dies legt fest, was implizit importiert wird - aber es ist immer noch schwer zu ermitteln, woher Objekte kommen, ohne das Stabmodul zu lesen und zu parsen und its -Importen zu folgen. Ein Netzwerk von import * ist das Erste, was ich korrigiere, wenn ich ein Projekt in Besitz nehme.

Verstehen Sie mich nicht falsch: Wenn der import * fehlt, würde ich ihn weinen lassen. Aber es muss vorsichtig verwendet werden. Ein guter Anwendungsfall ist das Bereitstellen einer Fassadenschnittstelle über einem anderen Modul. Die Verwendung von bedingten Importanweisungen oder das Importieren von Funktions-/Klassennamensräumen erfordert ebenfalls ein wenig Disziplin.

Ich denke, bei mittelgroßen bis großen Projekten oder kleinen Projekten mit mehreren Mitwirkenden ist ein Mindestmaß an Hygiene in Bezug auf die statische Analyse erforderlich, bei der mindestens Pyflakes oder besser ein richtig konfigurierter Pylint ausgeführt werden, um verschiedene Arten von Fehlern zu finden sie passieren.

Natürlich, da dies Python ist - zögern Sie nicht, Regeln zu brechen und zu erkunden - aber seien Sie vorsichtig bei Projekten, die sich verzehnfachen könnten, wenn der Quellcode Disziplin fehlt, wird dies ein Problem sein.

33
Marco Mariani

Das liegt daran, dass Sie den Namespace verschmutzen. Sie importieren alle Funktionen und Klassen in Ihrem eigenen Namensraum, der mit den von Ihnen definierten Funktionen kollidieren kann.

Außerdem denke ich, dass die Verwendung eines qualifizierten Namens für die Wartungsaufgabe klarer ist. Sie sehen in der Codezeile selbst, woher eine Funktion kommt, so dass Sie die Dokumente viel einfacher auschecken können.

Im Modul foo:

def myFunc():
    print 1

In Ihrem Code:

from foo import *

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

def myFunc():
    print 2
15
extraneon

Es ist in Ordnung, from ... import * in einer interaktiven Sitzung auszuführen.

14
codeape

http://docs.python.org/tutorial/modules.html

Beachten Sie, dass das Importieren von * aus einem Modul oder Paket generell verpönt ist, da dies häufig schlecht lesbaren Code verursacht. 

11
Felix Kling

Angenommen, Sie haben den folgenden Code in einem Modul namens foo:

import ElementTree as etree

und dann haben Sie in Ihrem eigenen Modul:

from lxml import etree
from foo import *

Sie haben jetzt ein schwer zu debugierendes Modul, das aussieht wie. Es enthält lxmls Etree, aber stattdessen ElementTree.

7
jcdyer

Das sind alles gute Antworten. Ich füge hinzu, dass der Umgang mit import * sehr schwierig ist, wenn man anderen Leuten Code in Python beibringt. Auch wenn Sie oder sie den Code nicht geschrieben haben, ist er immer noch ein Hindernis.

Ich lehre Kinder (ca. 8 Jahre), in Python zu programmieren, um Minecraft zu manipulieren. Ich gebe ihnen gerne eine hilfreiche Programmierumgebung, um mit ( Atom Editor ) zu arbeiten und REPL-gesteuerte Entwicklung (über bpython ) zu lehren. In Atom finde ich, dass die Hinweise/Vervollständigung genauso effektiv sind wie bpython. Glücklicherweise wird Atom im Gegensatz zu anderen statistischen Analysewerkzeugen nicht von import * getäuscht.

Nehmen wir jedoch dieses Beispiel ... In diesem Wrapper sie from local_module import * ist ein Bündel von Modulen, die diese Liste von Blöcken enthalten. Ignorieren wir das Risiko von Namespace-Kollisionen. Mit from mcpi.block import * machen sie diese gesamte Liste von obskuren Blocktypen zu etwas, das Sie ansehen müssen, um zu erfahren, was verfügbar ist. Wenn sie stattdessen from mcpi import block verwendet hätten, könnten Sie walls = block. eingeben, und dann würde eine Autocomplete-Liste erscheinen .  Atom.io screenshot

6
Bruno Bronosky

Verstand die gültigen Punkte, die die Leute hier setzen. Ich habe jedoch ein Argument, dass "Sternimport" manchmal nicht immer eine schlechte Praxis ist:

  • Wenn ich meinen Code so strukturieren möchte, dass alle Konstanten in ein Modul namens const.py: .__ gehen.
    • Wenn ich import const tue, muss ich es für jede Konstante als const.SOMETHING bezeichnen, was wahrscheinlich nicht der bequemste Weg ist.
    • Wenn ich from const import SOMETHING_A, SOMETHING_B ... mache, dann ist es offensichtlich viel zu ausführlich und besiegt den Zweck der Strukturierung.
    • Daher denke ich, dass in diesem Fall ein from const import * eine bessere Wahl ist.
4
ibic

Als Test habe ich ein Modul test.py mit 2 Funktionen A und B erstellt, die jeweils "A 1" und "B 1" drucken. Nach dem Import von test.py mit:

import test

. . . Ich kann die 2 Funktionen als test.A () und test.B () ausführen, und "test" erscheint als module im Namespace. Wenn ich test.py editiere, kann ich es mit:

import importlib
importlib.reload(test)

Aber wenn ich folgendes mache:

from test import *

es gibt keinen Hinweis auf "test" im Namespace. Daher gibt es keine Möglichkeit, es nach einer Bearbeitung erneut zu laden (soweit ich das beurteilen kann). Dies ist ein Problem in einer interaktiven Sitzung. In Erwägung nachstehender Gründe:

import test
import test as tt

fügt "test" bzw. "tt" als Modulnamen im Namespace hinzu, wodurch das erneute Laden ermöglicht wird.

Wenn ich mache:

from test import *

die Namen "A" und "B" erscheinen im Namespace als Funktionen . Wenn ich test.py bearbeite und den obigen Befehl wiederhole, werden die geänderten Versionen der Funktionen nicht erneut geladen.

Der folgende Befehl löst eine Fehlermeldung aus.

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

Wenn jemand weiß, wie man ein mit "from module import *" geladenes Modul neu lädt, bitte posten. Andernfalls wäre dies ein weiterer Grund, um das Formular zu vermeiden:

from module import *
2
Alex

Es ist eine sehr schlechte Praxis aus zwei Gründen:

  1. Lesbarkeit des Codes
  2. Gefahr des Überschreibens der Variablen/Funktionen etc

Für Punkt 1: Sehen wir uns ein Beispiel an:

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

a = b + c - d

Wenn Sie den Code sehen, wird hier niemand eine Vorstellung davon bekommen, zu welchem ​​Modul b, c und d tatsächlich gehört. 

Auf der anderen Seite, wenn Sie es so machen:

#                   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

Es ist viel sauberer für Sie, und auch die neue Person, die in Ihr Team kommt, hat eine bessere Idee.

Für Punkt 2: Nehmen wir an, dass module1 und module2 eine Variable als b haben. Wenn ich tue:

from module1 import *
from module2 import *

print b  # will print the value from module2

Hier geht der Wert von module1 verloren. Es ist schwer zu debuggen, warum der Code nicht funktioniert, auch wenn b in module1 deklariert ist und ich den Code geschrieben habe, in dem erwartet wird, dass mein Code module1.b verwendet.

Wenn Sie in verschiedenen Modulen dieselben Variablen haben und nicht das gesamte Modul importieren möchten, können Sie sogar Folgendes tun:

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

Wie in den Dokumenten vorgeschlagen, sollten Sie niemals import * im Produktionscode verwenden.

Ein weiterer Grund, dies zu vermeiden, ist, dass das Importieren von * aus einem package anders funktioniert als import * aus einem module, was zu Fehlern führen kann. Grundsätzlich importiert from package import * alle Namen, die durch __init__.py definiert sind, es schließt jedoch auch alle Submodule des Pakets ein, die von vorherigen Importanweisungen explizit geladen wurden. Betrachten Sie diesen Code:

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

# in your module
from sound.effects import *

In diesem Beispiel werden die echo- und surround-Module im aktuellen Namespace importiert (wobei sie möglicherweise vorherige Definitionen überschreiben), da sie bei Ausführung der sound.effects-Anweisung im from sound.effects import *-Paket definiert werden.

0
Eugene Yarmash