Was sind gute Faustregeln für Python-Importe?

72

Ich bin ein wenig verwirrt über die Vielzahl von Möglichkeiten, wie Sie Module in Python importieren können.

import X
import X as Y
from A import B

Ich habe über Scoping und Namespaces gelesen, möchte aber einige praktische Ratschläge dazu, welche Strategie unter welchen Umständen und warum die beste ist. Sollten Importe auf Modulebene oder auf Methoden- / Funktionsebene erfolgen? Im __init__.pyoder im Modulcode selbst?

Meine Frage wird von " Python-Pakete - Import nach Klasse, nicht Datei " nicht wirklich beantwortet , obwohl sie offensichtlich verwandt ist.

Simon
quelle

Antworten:

67

Im Produktionscode unseres Unternehmens versuchen wir, die folgenden Regeln zu befolgen.

Wir platzieren Importe am Anfang der Datei, direkt nach der Dokumentzeichenfolge der Hauptdatei, z.

"""
Registry related functionality.
"""
import wx
# ...

Wenn wir nun eine Klasse importieren, die eine der wenigen im importierten Modul ist, importieren wir den Namen direkt, sodass wir im Code nur den letzten Teil verwenden müssen, z.

from RegistryController import RegistryController
from ui.windows.lists import ListCtrl, DynamicListCtrl

Es gibt jedoch Module, die Dutzende von Klassen enthalten, z. B. eine Liste aller möglichen Ausnahmen. Dann importieren wir das Modul selbst und verweisen im Code darauf:

from main.core import Exceptions
# ...
raise Exceptions.FileNotFound()

Wir verwenden das import X as Yso selten wie möglich, da es die Suche nach der Verwendung eines bestimmten Moduls oder einer bestimmten Klasse erschwert. Manchmal müssen Sie es jedoch verwenden, wenn Sie zwei Klassen importieren möchten, die denselben Namen haben, aber in verschiedenen Modulen vorhanden sind, z.

from Queue import Queue
from main.core.MessageQueue import Queue as MessageQueue

In der Regel führen wir keine Importe innerhalb von Methoden durch - sie machen Code einfach langsamer und weniger lesbar. Einige mögen dies als einen guten Weg betrachten, um das Problem der zyklischen Importe leicht zu lösen, aber eine bessere Lösung ist die Code-Reorganisation.

DzinX
quelle
5
"Sie machen Code einfach langsamer" ist nicht so wahr. Es wurde hier getestet: stackoverflow.com/a/4789963/617185
kmonsoor
37

Lassen Sie mich nur einen Teil des Gesprächs in die von Guido van Rossum gestartete Django-Dev-Mailingliste einfügen:

[...] Zum Beispiel ist es Teil der Google Python-Stilrichtlinien [1], dass alle Importe ein Modul importieren müssen, keine Klasse oder Funktion aus diesem Modul. Es gibt weit mehr Klassen und Funktionen als Module. Daher ist es viel einfacher, sich daran zu erinnern, woher ein bestimmtes Objekt stammt, wenn ihm ein Modulname vorangestellt wird. Oft definieren mehrere Module Dinge mit demselben Namen. Ein Leser des Codes muss also nicht zum Anfang der Datei zurückkehren, um zu sehen, aus welchem ​​Modul ein bestimmter Name importiert wird.

Quelle: http://groups.google.com/group/django-developers/browse_thread/thread/78975372cdfb7d1a

1: http://code.google.com/p/soc/wiki/PythonStyleGuide#Module_and_package_imports

Bartosz Ptaszynski
quelle
IMO sollte dies der bevorzugte Weg sein, um Dinge zu importieren, insbesondere in großen Projekten.
Priidu Neemre
12

Ich würde normalerweise import Xauf Modulebene verwenden. Wenn Sie nur ein einzelnes Objekt aus einem Modul benötigen, verwenden Sie from X import Y.

Nur verwenden, import X as Ywenn Sie anderweitig mit einem Namenskonflikt konfrontiert sind.

Ich verwende Importe nur auf Funktionsebene, um Dinge zu importieren, die ich benötige, wenn das Modul als Hauptmodul verwendet wird, wie zum Beispiel:

def main():
  import sys
  if len(sys.argv) > 1:
     pass

HTH

MvdD
quelle
10

Jemand oben hat das gesagt

from X import A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P

ist äquivalent zu

import X

import XErmöglicht direkte Änderungen am AP, während from X import ...Kopien des AP erstellt werden. Denn from X import A..PSie erhalten keine Aktualisierungen von Variablen, wenn diese geändert werden. Wenn Sie sie ändern, ändern Sie nur Ihre Kopie, aber X kennt Ihre Änderungen.

Wenn AP Funktionen sind, kennen Sie den Unterschied nicht.

Robert Jacobs
quelle
Insbesondere, wenn Sie mockin Unit-Tests beispielsweise zum Verspotten verwenden möchten, X.Afunktioniert dies nur, wenn Sie es verwendet haben import X.
RemcoGerlich
5

Andere haben hier den größten Teil des Bodens abgedeckt, aber ich wollte nur einen Fall hinzufügen, den ich import X as Y(vorübergehend) verwenden werde, wenn ich eine neue Version einer Klasse oder eines Moduls ausprobiere.

Wenn wir also auf eine neue Implementierung eines Moduls migrieren, aber die Codebasis nicht auf einmal aufteilen möchten, schreiben wir möglicherweise ein xyz_newModul und tun dies in den von uns migrierten Quelldateien:

import xyz_new as xyz

Sobald wir die gesamte Codebasis gekürzt haben, ersetzen wir einfach das xyzModul durch xyz_newund ändern alle Importe wieder auf

import xyz
davidavr
quelle
3

Tu das NICHT:

from X import *

es sei denn, Sie sind absolut sicher, dass Sie alles in diesem Modul verwenden werden. Und selbst dann sollten Sie wahrscheinlich einen anderen Ansatz wählen.

Davon abgesehen ist es nur eine Frage des Stils.

from X import Y

ist gut und erspart Ihnen viel Tippen. Ich benutze das normalerweise, wenn ich etwas ziemlich häufig darin verwende. Wenn Sie jedoch viel aus diesem Modul importieren, kann dies zu einer Importanweisung führen, die folgendermaßen aussieht:

from X import A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P

Du hast die Idee. Das ist, wenn Importe mögen

import X

nützlich werden. Entweder das oder wenn ich in X nicht wirklich häufig etwas benutze.

Jason Baker
quelle
'from X import *' hat seine Verwendung - zB beim Pyparsing.
John Fouhy
Genau. Aber im Allgemeinen ist es keine gute Angewohnheit, sich darauf einzulassen. Nichts stört mich mehr, als herausfinden zu müssen, welche Funktion von welchem ​​Modul stammt, da es viele Anweisungen vom Typ x import * gibt.
Jason Baker
2

Ich versuche im Allgemeinen, das reguläre zu verwenden import modulename, es sei denn, der Modulname ist lang oder wird häufig verwendet.

Zum Beispiel würde ich tun ..

from BeautifulSoup import BeautifulStoneSoup as BSS

..so kann ich soup = BSS(html)statt tunBeautifulSoup.BeautifulStoneSoup(html)

Oder..

from xmpp import XmppClientBase

.. anstatt den gesamten xmpp zu importieren, wenn ich nur die XmppClientBase verwende

Die Verwendung import x as yist praktisch, wenn Sie entweder sehr lange Methodennamen importieren oder verhindern möchten, dass ein vorhandener Import / eine Variable / eine Klasse / eine Methode überlastet wird (etwas, das Sie vollständig vermeiden sollten, das aber nicht immer möglich ist).

Angenommen, ich möchte eine main () - Funktion von einem anderen Skript aus ausführen, habe aber bereits eine main () - Funktion.

from my_other_module import main as other_module_main

..wollte meine mainFunktion nicht durch my_other_module's ersetzenmain

Oh, eine Sache - tu es nicht from x import *- es macht deinen Code sehr schwer zu verstehen, da du nicht leicht erkennen kannst, woher eine Methode stammt ( from x import *; from y import *; my_func()- wo ist my_func definiert?)

In allen Fällen könnten Sie einfach tun import modulenameund dann tun modulename.subthing1.subthing2.method("test")...

Das from x import y as zZeug dient nur der Bequemlichkeit - verwenden Sie es, wenn es Ihren Code leichter lesen oder schreiben lässt!

dbr
quelle
2
IMHO, hier gibt es einige Missverständnisse ... 1) "Importieren von xmpp, wenn ich nur verwende ..." : Dies impliziert fälschlicherweise, dass dieser Ansatz "leichter" ist, aber Python lädt und initiiert trotzdem das gesamte Modul, unabhängig davon von wie vielen Objekten Sie importiert haben. In Bezug auf "Namespace-Verschmutzung" fügen beide dem lokalen Namespace einen einzigen Eintrag hinzu: xmppoder XmppClientBase. Diese Begründung ist also nicht gültig
MestreLion
2
2) "da Sie nicht leicht erkennen können, woher eine Methode stammt" : Richtig für * Importe, aber auch für Ihren Ansatz, asnur einen Modul- / Objektnamen zu verkürzen. Woher kommt BSS()das? Die Verwendung fromleidet auch (ein bisschen) darunter : from mymod import MyClass. Jetzt 300 Zeilen voraus class MyOtherClass(MyClass):... sehen Sie , woher kam MyClass wieder? Ein Leser ist gezwungen, immer zum Header zurückzukehren, um zu überprüfen, woher welches Objekt importiert wurde
MestreLion
1

Wenn Sie eine gut geschriebene Bibliothek haben, was in Python manchmal der Fall ist, sollten Sie sie einfach importieren und als solche verwenden. Eine gut geschriebene Bibliothek nimmt in der Regel das eigene Leben und die eigene Sprache in Anspruch, was zu einem angenehm zu lesenden Code führt, in dem Sie selten auf die Bibliothek verweisen. Wenn eine Bibliothek gut geschrieben ist, sollten Sie nicht zu oft umbenennen oder etwas anderes.

import gat

node = gat.Node()
child = node.children()

Manchmal ist es nicht möglich, es so zu schreiben, oder Sie möchten Dinge aus der importierten Bibliothek entfernen.

from gat import Node, SubNode

node = Node()
child = SubNode(node)

Manchmal tun Sie dies für viele Dinge, wenn Ihre Importzeichenfolge 80 Spalten überläuft. Es ist eine gute Idee, dies zu tun:

from gat import (
    Node, SubNode, TopNode, SuperNode, CoolNode,
    PowerNode, UpNode
)

Die beste Strategie besteht darin, alle diese Importe oben in der Datei zu belassen. Vorzugsweise alphabetisch sortiert, zuerst Import-Anweisungen, dann aus Import-Anweisungen.

Jetzt sage ich Ihnen, warum dies die beste Konvention ist.

Python hätte durchaus einen automatischen Import haben können, der anhand der Hauptimporte nach dem Wert sucht, wenn er nicht im globalen Namespace gefunden werden kann. Das ist aber keine gute Idee. Ich erkläre kurz warum. Abgesehen davon, dass die Implementierung komplizierter ist als der einfache Import, würden Programmierer nicht so sehr über die Abhängigkeiten nachdenken und herausfinden, von wo Sie Dinge importiert haben, sondern auf andere Weise als nur über Importe nachdenken.

Die Notwendigkeit, Abhängigkeiten herauszufinden, ist ein Grund, warum Menschen "von ... import *" hassen. Es gibt jedoch einige schlechte Beispiele, bei denen Sie dies tun müssen, zum Beispiel opengl-Wrappings.

Die Importdefinitionen sind also tatsächlich wertvoll, um die Abhängigkeiten des Programms zu definieren. Auf diese Weise sollten Sie sie ausnutzen. Von ihnen aus können Sie schnell überprüfen, woher eine seltsame Funktion importiert wird.

Heiter
quelle
0

Dies import X as Yist nützlich, wenn Sie unterschiedliche Implementierungen desselben Moduls / derselben Klasse haben.

Mit einigen verschachtelten try..import..except ImportError..imports können Sie die Implementierung vor Ihrem Code verbergen. Siehe Beispiel für den Import von lxml etree :

try:
  from lxml import etree
  print("running with lxml.etree")
except ImportError:
  try:
    # Python 2.5
    import xml.etree.cElementTree as etree
    print("running with cElementTree on Python 2.5+")
  except ImportError:
    try:
      # Python 2.5
      import xml.etree.ElementTree as etree
      print("running with ElementTree on Python 2.5+")
    except ImportError:
      try:
        # normal cElementTree install
        import cElementTree as etree
        print("running with cElementTree")
      except ImportError:
        try:
          # normal ElementTree install
          import elementtree.ElementTree as etree
          print("running with ElementTree")
        except ImportError:
          print("Failed to import ElementTree from any known place")
olt
quelle
0

Ich bin mit Jason in der Tatsache, nicht zu verwenden

from X import *

Aber in meinem Fall (ich bin kein erfahrener Programmierer, daher entspricht mein Code nicht so gut dem Codierungsstil) mache ich in meinen Programmen normalerweise eine Datei mit allen Konstanten wie Programmversion, Autoren, Fehlermeldungen und all dem Zeug. Die Datei sind also nur Definitionen, dann mache ich den Import

from const import *

Das spart mir viel Zeit. Aber es ist die einzige Datei, die diesen Import hat, und das liegt daran, dass alle in dieser Datei nur Variablendeklarationen sind.

Diese Art des Imports in eine Datei mit Klassen und Definitionen kann nützlich sein, aber wenn Sie diesen Code lesen müssen, verbringen Sie viel Zeit damit, Funktionen und Klassen zu finden.

Oscar Carballal
quelle