Verwenden Sie "Modul importieren" oder "aus Modul importieren"?


410

Ich habe versucht, einen umfassenden Leitfaden zu finden, ob es am besten ist, import moduleoder from module import? Ich habe gerade mit Python angefangen und versuche, mit Best Practices zu beginnen.

Grundsätzlich hatte ich gehofft, dass jemand seine Erfahrungen teilen könnte, welche Vorlieben andere Entwickler haben und wie man am besten Fallstricke vermeiden kann .


5
Ich wollte Sie nur wissen lassen, dass die ausgewählte Antwort falsch ist. Es heißt, dass der Unterschied subjektiv ist, während es einen Unterschied gibt. Dies kann möglicherweise zu schwer zu erkennenden Fehlern führen. Siehe Michael Ray Lovetts Antwort.
Mayou36


2
Es gibt einen verdammt großen Unterschied zwischen dem Importieren bestimmter benannter Bezeichner 'from module import X,Y,Zund'from module import * . Letzteres verschmutzt Ihren Namespace und kann unvorhersehbare Ergebnisse liefern, je nachdem, was im Modul vor sich geht. Schlimmer noch ist es from module import *mit mehreren Modulen.
smci

Antworten:


474

Der Unterschied zwischen import moduleund from module import fooist hauptsächlich subjektiv. Wählen Sie die aus, die Ihnen am besten gefällt, und verwenden Sie sie konsequent. Hier sind einige Punkte, die Ihnen bei der Entscheidung helfen sollen.

import module

  • Vorteile:
    • Weniger Wartung Ihrer importAussagen. Sie müssen keine zusätzlichen Importe hinzufügen, um ein anderes Element aus dem Modul zu verwenden
  • Nachteile:
    • Das Eingeben module.fooIhres Codes kann mühsam und redundant sein (Langeweile kann durch die import module as moanschließende Eingabe minimiert werden mo.foo).

from module import foo

  • Vorteile:
    • Weniger tippen zu verwenden foo
    • Mehr Kontrolle darüber, auf welche Elemente eines Moduls zugegriffen werden kann
  • Nachteile:
    • Um ein neues Element aus dem Modul zu verwenden, müssen Sie Ihre importAnweisung aktualisieren
    • Sie verlieren den Kontext über foo. Zum Beispiel ist es weniger klar, was ceil()im Vergleich zu tutmath.ceil()

Beide Methoden sind akzeptabel, werden jedoch nicht verwendet from module import *.

Wenn Sie einen vernünftig großen Code-Satz import *wahrscheinlich in das Modul zementieren, kann er nicht entfernt werden. Dies liegt daran, dass es schwierig ist zu bestimmen, welche im Code verwendeten Elemente vom 'Modul' stammen, was es einfach macht, an den Punkt zu gelangen, an dem Sie glauben, dass Sie das nicht importmehr verwenden, aber es ist äußerst schwierig, sicher zu sein.


66
+1 um die Verwendung von "from module import *" zu verhindern, wird nur der Namespace unübersichtlich.
Christian Witts

22
Das Durcheinander des Namespace ist nicht der problematischste Teil von "import *", sondern die Verringerung der Lesbarkeit: Alle Namenskonflikte zeigen sich in (Unit-) Tests. Alle Namen, die Sie aus dem importierten Modul verwenden, sind jedoch leer und enthalten keinen Hinweis darauf, woher sie stammen. Ich hasse "import *".
Jürgen A. Erhard

21
Sagt das Zen von Python nicht, dass explizit besser ist als implizit?
Antony Koch

8
from module import *kann besonders nützlich sein, wenn Sie es verwenden als : if(windows):\n\t from module_win import * \n else: \n\t from module_lin import *. Dann kann Ihr übergeordnetes Modul möglicherweise betriebssystemunabhängige Funktionsnamen enthalten, wenn die Funktionsnamen in module_lin & module_win dieselben Namen haben. Es ist, als würde man eine Klasse bedingt erben.
Anishsane

19
@anishsane. Es gibt noch einen anderen Weg. importiere module_win als etwas. Dann benutze immer etwas.method_name ()
Vinay

163

Es gibt hier ein weiteres Detail, das nicht erwähnt wird und sich auf das Schreiben in ein Modul bezieht. Zugegeben, das ist vielleicht nicht sehr häufig, aber ich habe es von Zeit zu Zeit gebraucht.

Aufgrund der Funktionsweise von Referenzen und Namensbindung in Python müssen Sie foo a importieren, wenn Sie ein Symbol in einem Modul, z. B. foo.bar, von außerhalb dieses Moduls aktualisieren und einen anderen Importcode haben möchten, der diese Änderung "sieht" bestimmte Weise. Zum Beispiel:

Modul foo:

bar = "apples"

Modul a:

import foo
foo.bar = "oranges"   # update bar inside foo module object

Modul b:

import foo           
print foo.bar        # if executed after a's "foo.bar" assignment, will print "oranges"

Wenn Sie jedoch Symbolnamen anstelle von Modulnamen importieren, funktioniert dies nicht.

Wenn ich dies beispielsweise in Modul a mache:

from foo import bar
bar = "oranges"

Kein Code außerhalb von a sieht die Leiste als "Orangen", da meine Einstellung der Leiste lediglich den Namen "Leiste" innerhalb des Moduls a beeinflusste, nicht in das foo-Modulobjekt "griff" und dessen "Leiste" aktualisierte.


Können Sie mit diesem letzten Beispiel immer noch 'foo.bar = "orange" aufrufen, um' bar 'in' foo 'zu aktualisieren?
Velocirabbit

4
Nein, im letzten Beispiel ist der Name 'foo' unbekannt
Ghislain Leveque

31
Diese Antwort liefert die "wahre" Antwort auf die Frage: Was ist der Unterschied zwischen den beiden
Importvarianten

3
Schrieb einen Ausschnitt, um zu beweisen, dass diese Antwort absolut richtig ist, aber was ist der Grund dafür?
Huangbeidu

Ich denke, was Sie sagen, ist, Symbolnamen zu importieren, um lokale Variablen zu haben, aber Modulnamen zu importieren, um globale Variablen zu haben ???
WinEunuuchs2Unix

79

Obwohl viele Leute bereits über importvs erklärt haben import from, möchte ich versuchen, ein bisschen mehr darüber zu erklären, was unter der Haube passiert und wo sich all die Orte befinden, an denen es sich ändert.


import foo::

Importiert foound erstellt einen Verweis auf dieses Modul im aktuellen Namespace. Anschließend müssen Sie den abgeschlossenen Modulpfad definieren, um aus dem Modul heraus auf ein bestimmtes Attribut oder eine bestimmte Methode zugreifen zu können.

ZB foo.baraber nichtbar

from foo import bar::

Importiert foound erstellt Verweise auf alle aufgelisteten Mitglieder ( bar). Setzt die Variable nicht foo.

ZB baraber nicht bazoderfoo.baz

from foo import *::

Importiert foound erstellt Verweise auf alle öffentlichen Objekte, die von diesem Modul im aktuellen Namespace definiert wurden (alles, was in vorhanden ist, __all__falls __all__vorhanden, sonst alles, was nicht beginnt _). Setzt die Variable nicht foo.

ZB barund bazaber nicht _quxoder foo._qux.


Nun wollen wir sehen, wann wir es tun import X.Y:

>>> import sys
>>> import os.path

Überprüfen Sie sys.modulesmit Namen osund os.path:

>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>

Check globals()und locals()Namespace diktieren mit osund os.path:

 >>> globals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> locals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> globals()['os.path']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'os.path'
>>>

Aus dem obigen Beispiel haben wir herausgefunden, dass nur osin den lokalen und globalen Namespace eingefügt wird. Wir sollten also in der Lage sein:

 >>> os
 <module 'os' from
  '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
 >>> os.path
 <module 'posixpath' from
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
 >>>

Aber nicht path.

>>> path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>

Sobald Sie das Löschen osvon Einheimischen () Namespace, werden Sie nicht zugreifen können os, sowie os.pathauch wenn sie in sys.modules existieren:

>>> del locals()['os']
>>> os
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>> os.path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>

Sprechen wir jetzt über import from:

from::

>>> import sys
>>> from os import path

Überprüfen Sie sys.modulesmit osund os.path:

>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>

Wir fanden, dass sys.moduleswir in das gleiche wie zuvor gefunden haben, indem wir verwendet habenimport name

OK, lassen Sie uns überprüfen, wie es in locals()und globals()Namespace-Diktaten aussieht :

>>> globals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> locals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['os']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'os'
>>>

Sie können mit dem Namen zugreifen, pathnicht mit os.path:

>>> path
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> os.path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>

Löschen wir 'Pfad' aus locals():

>>> del locals()['path']
>>> path
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>

Ein letztes Beispiel mit einem Alias:

>>> from os import path as HELL_BOY
>>> locals()['HELL_BOY']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['HELL_BOY']
<module 'posixpath' from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>>

Und kein Pfad definiert:

>>> globals()['path']
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
KeyError: 'path'
>>>

8
Während dies ausführlich ist, ist dies wirklich die beste Antwort in der Liste für eine ziemlich komplexe Frage. Es enthält tatsächlichen Code, um die Feinheiten "unter der Haube" zu erklären, die für dieses spezielle Problem wichtiger sind als der Stil. Ich wünschte, ich könnte es mehr als einmal positiv bewerten!
Mike Williamson

Ändert sich die Verwendung as SYMBOLdieser Antwort überhaupt?
Maximilian Burszley

40

Beide Möglichkeiten werden aus einem Grund unterstützt: Es gibt Zeiten, in denen eine angemessener ist als die andere.

  • import module: schön, wenn Sie viele Bits aus dem Modul verwenden. Nachteil ist, dass Sie jede Referenz mit dem Modulnamen qualifizieren müssen.

  • from module import ...: schön, dass importierte Elemente direkt ohne Modulnamenpräfix verwendet werden können. Der Nachteil ist, dass Sie jedes Objekt auflisten müssen, das Sie verwenden, und dass im Code nicht klar ist, woher etwas stammt.

Welche zu verwenden ist, hängt davon ab, welche den Code klar und lesbar macht und hat mehr als ein wenig mit persönlichen Vorlieben zu tun. Ich neige import moduleallgemein dazu, weil im Code sehr klar ist, woher ein Objekt oder eine Funktion stammt. Ich verwende , from module import ...wenn ich einige Objekt / Funktion unter Verwendung einer Menge im Code.


1
Gibt es eine Möglichkeit, from M import Xdie Qualifikationsmerkmale irgendwie zu nutzen und trotzdem zu nutzen ? Es scheint, dass Sie das Beste aus beiden Welten bekommen könnten, wenn Sie es M.Xnach diesem Import noch tun könnten .
Arthropode

@ Artgropod: Ein bisschen. Das kannst du machen class m: from something.too.long import x, y, z. Würde das aber nicht wirklich empfehlen.
Lie Ryan

35

Ich persönlich benutze immer

from package.subpackage.subsubpackage import module

und dann auf alles zugreifen als

module.function
module.modulevar

usw. Der Grund dafür ist, dass Sie gleichzeitig einen kurzen Aufruf haben und den Modul-Namespace jeder Routine klar definieren. Dies ist sehr nützlich, wenn Sie nach der Verwendung eines bestimmten Moduls in Ihrer Quelle suchen müssen.

Verwenden Sie den Import * natürlich nicht, da er Ihren Namespace verschmutzt und Ihnen nicht sagt, woher eine bestimmte Funktion kommt (von welchem ​​Modul).

Natürlich können Probleme auftreten, wenn Sie denselben Modulnamen für zwei verschiedene Module in zwei verschiedenen Paketen haben, z

from package1.subpackage import module
from package2.subpackage import module

In diesem Fall stoßen Sie natürlich auf Probleme, aber dann gibt es einen starken Hinweis darauf, dass Ihr Paketlayout fehlerhaft ist, und Sie müssen es überdenken.


10
Im letzten Fall können Sie immer Folgendes verwenden: import pkgN.sub.module als modN, wobei Sie für jedes Modul unterschiedliche Namen angeben. Sie können auch das Muster 'Modulname als mod1 importieren' verwenden, um einen langen Namen zu verkürzen oder zwischen Implementierungen derselben API (z. B. DB-API-Module) mit einer einzigen Namensänderung zu wechseln.
Jeff Shannon

15
import module

Ist am besten, wenn Sie viele Funktionen aus dem Modul verwenden.

from module import function

Dies ist am besten geeignet, wenn Sie vermeiden möchten, den globalen Namespace mit allen Funktionen und Typen eines Moduls zu verschmutzen, wenn Sie dies nur benötigen function.


7
Sicherlich ist das einzige im globalen Namespace, wenn Sie "Modul importieren", "Modul"? Sie verschmutzen den Namespace nur, wenn Sie 'from .. import *' ausführen.
John Fouhy

10

Ich habe gerade einen subtileren Unterschied zwischen diesen beiden Methoden entdeckt.

Wenn das Modul fooeinen folgenden Import verwendet:

from itertools import count

Dann barkann das Modul versehentlich so verwendet werden, countals wäre es definiert in foo, nicht in itertools:

import foo
foo.count()

Wenn fooverwendet:

import itertools

Der Fehler ist immer noch möglich, aber weniger wahrscheinlich. barmuss:

import foo
foo.itertools.count()

Dies verursachte mir einige Probleme. Ich hatte ein Modul, das versehentlich eine Ausnahme von einem Modul importierte, das es nicht definierte, sondern nur von einem anderen Modul importierte (mit from module import SomeException). Wenn der Import nicht mehr benötigt und entfernt wurde, war das fehlerhafte Modul defekt.


10

Hier ist ein weiterer Unterschied nicht erwähnt. Dies wird wörtlich von http://docs.python.org/2/tutorial/modules.html kopiert

Beachten Sie dies bei der Verwendung

from package import item

Das Element kann entweder ein Submodul (oder ein Subpaket) des Pakets oder ein anderer im Paket definierter Name sein, z. B. eine Funktion, eine Klasse oder eine Variable. Die import-Anweisung testet zunächst, ob das Element im Paket definiert ist. Andernfalls wird davon ausgegangen, dass es sich um ein Modul handelt, und es wird versucht, es zu laden. Wenn es nicht gefunden wird, wird eine ImportError-Ausnahme ausgelöst.

Im Gegensatz dazu, wenn Syntax wie

import item.subitem.subsubitem

Jeder Artikel mit Ausnahme des letzten muss ein Paket sein. Das letzte Element kann ein Modul oder ein Paket sein, kann jedoch keine Klasse, Funktion oder Variable sein, die im vorherigen Element definiert wurde.


Eine andere Sache, die mir aufgefallen ist, war, dass, wenn item auch ein Submodul innerhalb des Pakets ist, "from package import item" funktioniert, aber "import package" package.item.subitem = ... nicht mit einer leeren init .py des Pakets funktioniert , es sei denn wir haben "Element importieren" in der Init- Datei des Pakets.
Amitoz Dandiana

6

Da ich auch Anfänger bin, werde ich versuchen, dies auf einfache Weise zu erklären: In Python gibt es drei Arten von importAnweisungen:

1. Generische Importe:

import math

Diese Art des Imports ist mein persönlicher Favorit. Der einzige Nachteil dieser Importtechnik ist, dass Sie die folgende Syntax verwenden müssen, wenn Sie die Funktion eines Moduls verwenden müssen:

math.sqrt(4)

Natürlich erhöht es den Schreibaufwand, aber als Anfänger hilft es Ihnen, den Überblick über das Modul und die damit verbundenen Funktionen zu behalten (ein guter Texteditor reduziert den Schreibaufwand erheblich und wird empfohlen).

Mit dieser Importanweisung kann der Schreibaufwand weiter reduziert werden:

import math as m

Jetzt können Sie anstelle von math.sqrt()verwenden m.sqrt().

2. Funktionsimporte:

from math import sqrt

Diese Art des Imports eignet sich am besten, wenn Ihr Code nur auf einzelne oder wenige Funktionen des Moduls zugreifen muss. Um jedoch ein neues Element aus dem Modul zu verwenden, müssen Sie die Importanweisung aktualisieren.

3. Universalimporte:

from math import * 

Dies reduziert zwar den Schreibaufwand erheblich, wird jedoch nicht empfohlen, da Ihr Code mit verschiedenen Funktionen des Moduls gefüllt wird und deren Name mit dem Namen der benutzerdefinierten Funktionen in Konflikt stehen kann. Beispiel:

Wenn Sie eine eigene Funktion namens sqrt haben und Mathematik importieren, ist Ihre Funktion sicher: Es gibt Ihre Funktion sqrt und math.sqrt. Wenn Sie aus Mathe importieren *, haben Sie jedoch ein Problem: nämlich zwei verschiedene Funktionen mit genau demselben Namen. Quelle: Codecademy


5
import package
import module

Bei importmuss das Token ein Modul (eine Datei mit Python-Befehlen) oder ein Paket (ein Ordner sys.pathmit einer Datei __init__.py) sein.

Wenn es Unterpakete gibt:

import package1.package2.package
import package1.package2.module

die Voraussetzungen für Ordner (Paket) oder Datei (Modul) sind die gleichen, aber die Ordner oder die Datei muss im Inneren sein , package2die im Inneren sein müssen package1, und beide package1und package2enthalten __init__.pyDateien. https://docs.python.org/2/tutorial/modules.html

Mit dem fromImportstil:

from package1.package2 import package
from package1.package2 import module

Das Paket oder Modul gibt den Namespace der Datei, die die importAnweisung enthält, als module(oder package) anstelle von ein package1.package2.module. Sie können jederzeit an einen bequemeren Namen binden:

a = big_package_name.subpackage.even_longer_subpackage_name.function

Nur der fromImportstil ermöglicht es Ihnen, eine bestimmte Funktion oder Variable zu benennen:

from package3.module import some_function

ist erlaubt, aber

import package3.module.some_function 

ist nicht erlaubt.


4

Um das zu ergänzen, was die Leute gesagt haben from x import *: Abgesehen davon, dass es schwieriger ist zu sagen, woher die Namen stammen, werden Codeprüfer wie Pylint abgeworfen. Sie melden diese Namen als undefinierte Variablen.


3

Meine eigene Antwort darauf hängt hauptsächlich davon ab, wie viele verschiedene Module ich verwenden werde. Wenn ich nur ein oder zwei verwenden werde, werde ich oft from... verwenden, importda es im Rest der Datei weniger Tastenanschläge gibt, aber wenn ich viele verschiedene Module verwenden möchte, bevorzuge ich nur importdenn das bedeutet, dass jede Modulreferenz selbstdokumentierend ist. Ich kann sehen, woher jedes Symbol kommt, ohne herumjagen zu müssen.

Normalerweise bevorzuge ich den selbstdokumentierenden Stil des einfachen Imports und wechsle nur von .. import, wenn die Häufigkeit, mit der ich den Modulnamen eingeben muss, über 10 bis 20 steigt, selbst wenn nur ein Modul importiert wird.


1

Einer der signifikanten Unterschied fand ich heraus , die überraschend niemand darüber gesprochen hat , ist die Ebene mit Import Sie zugreifen können private variableund private functionsaus dem importierten Modul, das nicht möglich ist , aus-Import - Anweisung.

Geben Sie hier die Bildbeschreibung ein

Code im Bild:

settings.py

public_variable = 42
_private_variable = 141
def public_function():
    print("I'm a public function! yay!")
def _private_function():
    print("Ain't nobody accessing me from another module...usually")

plain_importer.py

import settings
print (settings._private_variable)
print (settings.public_variable)
settings.public_function()
settings._private_function()

# Prints:
# 141
# 42
# I'm a public function! yay!
# Ain't nobody accessing me from another module...usually

from_importer.py

from settings import *
#print (_private_variable) #doesn't work
print (public_variable)
public_function()
#_private_function()   #doesn't work

0

Modul importieren - Sie benötigen keine zusätzlichen Anstrengungen, um eine andere Sache aus dem Modul abzurufen. Es hat Nachteile wie redundante Typisierung

Modulimport von - Weniger Eingabe und mehr Kontrolle darüber, auf welche Elemente eines Moduls zugegriffen werden kann. Um ein neues Element aus dem Modul zu verwenden, müssen Sie Ihre Importanweisung aktualisieren.


0

Es gibt einige eingebaute Module, die hauptsächlich nackte Funktionen enthalten ( base64 , math , os , shutil , sys , time , ...), und es ist definitiv eine gute Praxis, diese nackten Funktionen an einen Namespace zu binden und so die Lesbarkeit Ihrer zu verbessern Code. Überlegen Sie, wie schwierig es ist, die Bedeutung dieser Funktionen ohne ihren Namespace zu verstehen:

copysign(foo, bar)
monotonic()
copystat(foo, bar)

als wenn sie an ein Modul gebunden sind:

math.copysign(foo, bar)
time.monotonic()
shutil.copystat(foo, bar)

Manchmal benötigen Sie sogar den Namespace, um Konflikte zwischen verschiedenen Modulen zu vermeiden ( json.load vs. pickle.load ).


Auf der anderen Seite gibt es einige Module, die hauptsächlich Klassen enthalten ( configparser , datetime , tempfile , zipfile , ...), und viele von ihnen machen ihre Klassennamen selbsterklärend genug:

configparser.RawConfigParser()
datetime.DateTime()
email.message.EmailMessage()
tempfile.NamedTemporaryFile()
zipfile.ZipFile()

Daher kann es zu einer Debatte kommen, ob die Verwendung dieser Klassen mit dem zusätzlichen Modul-Namespace in Ihrem Code neue Informationen hinzufügt oder nur den Code verlängert.


0

Ich möchte noch hinzufügen, dass bei den Importaufrufen Folgendes zu beachten ist:

Ich habe folgende Struktur:

mod/
    __init__.py
    main.py
    a.py
    b.py
    c.py
    d.py

main.py:

import mod.a
import mod.b as b
from mod import c
import d

dis.dis zeigt den Unterschied:

  1           0 LOAD_CONST               0 (-1)
              3 LOAD_CONST               1 (None)
              6 IMPORT_NAME              0 (mod.a)
              9 STORE_NAME               1 (mod)

  2          12 LOAD_CONST               0 (-1)
             15 LOAD_CONST               1 (None)
             18 IMPORT_NAME              2 (b)
             21 STORE_NAME               2 (b)

  3          24 LOAD_CONST               0 (-1)
             27 LOAD_CONST               2 (('c',))
             30 IMPORT_NAME              1 (mod)
             33 IMPORT_FROM              3 (c)
             36 STORE_NAME               3 (c)
             39 POP_TOP

  4          40 LOAD_CONST               0 (-1)
             43 LOAD_CONST               1 (None)
             46 IMPORT_NAME              4 (mod.d)
             49 LOAD_ATTR                5 (d)
             52 STORE_NAME               5 (d)
             55 LOAD_CONST               1 (None)

Am Ende sehen sie gleich aus (STORE_NAME ist das Ergebnis in jedem Beispiel), aber dies ist erwähnenswert, wenn Sie die folgenden vier zirkulären Importe berücksichtigen müssen:

Beispiel 1

foo/
   __init__.py
   a.py
   b.py
a.py:
import foo.b 
b.py:
import foo.a
>>> import foo.a
>>>

Das funktioniert

Beispiel2

bar/
   __init__.py
   a.py
   b.py
a.py:
import bar.b as b
b.py:
import bar.a as a
>>> import bar.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "bar\a.py", line 1, in <module>
    import bar.b as b
  File "bar\b.py", line 1, in <module>
    import bar.a as a
AttributeError: 'module' object has no attribute 'a'

Kein Würfel

Beispiel3

baz/
   __init__.py
   a.py
   b.py
a.py:
from baz import b
b.py:
from baz import a
>>> import baz.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "baz\a.py", line 1, in <module>
    from baz import b
  File "baz\b.py", line 1, in <module>
    from baz import a
ImportError: cannot import name a

Ähnliches Problem ... aber eindeutig von x import y ist nicht dasselbe wie import import xy wie y

Beispiel4

qux/
   __init__.py
   a.py
   b.py
a.py:
import b 
b.py:
import a
>>> import qux.a
>>>

Dieser funktioniert auch


0

Dies ist meine Verzeichnisstruktur meines aktuellen Verzeichnisses:

.  
└─a  
   └─b  
     └─c
  1. Die importAnweisung merkt sich alle Zwischennamen .
    Diese Namen müssen qualifiziert sein:

    In[1]: import a.b.c
    
    In[2]: a
    Out[2]: <module 'a' (namespace)>
    
    In[3]: a.b
    Out[3]: <module 'a.b' (namespace)>
    
    In[4]: a.b.c
    Out[4]: <module 'a.b.c' (namespace)>
  2. Die from ... import ...Anweisung merkt sich nur den importierten Namen .
    Dieser Name darf nicht qualifiziert sein:

    In[1]: from a.b import c
    
    In[2]: a
    NameError: name 'a' is not defined
    
    In[2]: a.b
    NameError: name 'a' is not defined
    
    In[3]: a.b.c
    NameError: name 'a' is not defined
    
    In[4]: c
    Out[4]: <module 'a.b.c' (namespace)>

  • Hinweis: Natürlich habe ich meine Python-Konsole zwischen Schritt 1 und 2 neu gestartet.

0

Wie Jan Wrobel erwähnt, besteht ein Aspekt der verschiedenen Importe darin, wie die Importe offengelegt werden.

Modul mymath

from math import gcd
...

Verwendung von Mymath :

import mymath
mymath.gcd(30, 42)  # will work though maybe not expected

Wenn ich gcdnur für den internen Gebrauch importiert habe , um es nicht an Benutzer von weiterzugeben mymath, kann dies unpraktisch sein. Ich habe das ziemlich oft und in den meisten Fällen möchte ich "meine Module sauber halten".

Abgesehen von dem Vorschlag von Jan Wrobel , dies durch die Verwendung von etwas mehr zu verschleiern import math, habe ich begonnen, Importe vor der Offenlegung zu verbergen, indem ich einen führenden Unterstrich verwendete:

# for instance...
from math import gcd as _gcd
# or...
import math as _math

In größeren Projekten kann ich mit dieser "Best Practice" genau steuern, was bei nachfolgenden Importen angegeben wird und was nicht. Dies hält meine Module sauber und zahlt sich bei einer bestimmten Projektgröße aus.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.