Python: Importieren eines Unterpakets oder Untermoduls

Lesezeit: 10 Minuten

Python Importieren eines Unterpakets oder Untermoduls
Hibou57

Nachdem ich bereits flache Pakete verwendet hatte, hatte ich nicht mit dem Problem gerechnet, auf das ich bei verschachtelten Paketen gestoßen bin. Hier ist…

Verzeichnislayout

dir
 |
 +-- test.py
 |
 +-- package
      |
      +-- __init__.py
      |
      +-- subpackage
           |
           +-- __init__.py
           |
           +-- module.py

Inhalt von drin.py

Beide package/__init__.py und package/subpackage/__init__.py sind leer.

Inhalt von module.py

# file `package/subpackage/module.py`
attribute1 = "value 1"
attribute2 = "value 2"
attribute3 = "value 3"
# and as many more as you want...

Inhalt von test.py (3 Versionen)

Version 1

# file test.py
from package.subpackage.module import *
print attribute1 # OK

Das ist die schlechte und unsichere Art, Dinge zu importieren (alles auf einmal zu importieren), aber es funktioniert.

Version 2

# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
from module import attribute1

Eine sicherere Methode zum Importieren, Element für Element, aber es schlägt fehl, Python will das nicht: schlägt mit der Meldung fehl: “No module named module”. Jedoch …

# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
print module # Surprise here

… sagt <module 'package.subpackage.module' from '...'>. Das ist also ein Modul, aber das ist kein Modul /-P 😯 … äh

Fassung 3

# file test.py v3
from package.subpackage.module import attribute1
print attribute1 # OK

Dieser funktioniert. Sie sind also entweder gezwungen, die ganze Zeit das Overkill-Präfix zu verwenden, oder verwenden den unsicheren Weg wie in Version #1 und werden von Python nicht zugelassen, um den sicheren handlichen Weg zu verwenden? Der bessere Weg, der sicher ist und unnötig lange Präfixe vermeidet, ist der einzige, den Python ablehnt? Ist das, weil es liebt import * oder weil es überlange Präfixe liebt (was nicht hilft, diese Praxis durchzusetzen)?.

Entschuldigen Sie die harten Worte, aber das sind zwei Tage, an denen ich versucht habe, dieses dumme Verhalten zu umgehen. Wenn ich mich nicht irgendwo total geirrt habe, wird mir das das Gefühl geben, dass etwas in Pythons Modell von Paketen und Unterpaketen wirklich kaputt ist.

Anmerkungen

  • Ich möchte mich nicht darauf verlassen sys.pathum globale Nebenwirkungen zu vermeiden, noch auf *.pth Dateien, die nur eine andere Möglichkeit sind, damit zu spielen sys.path mit den gleichen globalen Auswirkungen. Damit die Lösung sauber ist, muss sie nur lokal sein. Entweder kann Python Unterpakete verarbeiten, oder nicht, aber es sollte nicht erforderlich sein, mit der globalen Konfiguration zu spielen, um lokale Dinge verarbeiten zu können.
  • Ich habe auch versucht, Importe in zu verwenden package/subpackage/__init__.pyaber es hat nichts gelöst, es tut dasselbe und beschwert sich subpackage ist kein bekanntes Modul, während print subpackage sagt, es ist ein Modul (wieder seltsames Verhalten).

Vielleicht bin ich völlig falsch (die Option, die ich bevorzugen würde), aber das macht mich sehr enttäuscht über Python.

Irgendein anderer bekannter Weg außer den drei, die ich versucht habe? Etwas, von dem ich nichts weiß?

(Seufzen)

—– %< ----- bearbeiten ----- >% —–

Fazit bisher (nach den Kommentaren der Leute)

Es gibt nichts Besseres als ein echtes Unterpaket in Python, da alle Paketreferenzen nur in ein globales Wörterbuch gehen, was bedeutet, dass es kein lokales Wörterbuch gibt, was impliziert, dass es keine Möglichkeit gibt, lokale Paketreferenzen zu verwalten.

Sie müssen entweder das vollständige Präfix oder das kurze Präfix oder den Alias ​​verwenden. Wie in:

Vollständige Präfixversion

from package.subpackage.module import attribute1
# An repeat it again an again
# But after that, you can simply:
use_of (attribute1)

Kurze Präfixversion (aber wiederholtes Präfix)

from package.subpackage import module
# Short but then you have to do:
use_of (module.attribute1)
# and repeat the prefix at every use place

Oder eine Variation des oben Gesagten.

from package.subpackage import module as m
use_of (m.attribute1)
# `m` is a shorter prefix, but you could as well
# define a more meaningful name after the context

Faktorisierte Version

Wenn es Ihnen nichts ausmacht, mehrere Entitäten auf einmal in einem Batch zu importieren, können Sie:

from package.subpackage.module import attribute1, attribute2
# and etc.

Nicht in meinem ersten Lieblingsgeschmack (ich bevorzuge eine Importanweisung pro importierter Entität), aber vielleicht diejenige, die ich persönlich bevorzuge.

Aktualisierung (14.09.2012):

Scheint schließlich in der Praxis OK zu sein, außer mit einem Kommentar zum Layout. Anstelle des oben genannten habe ich verwendet:

from package.subpackage.module import (

    attribute1, 
    attribute2,
    attribute3,
    ...)  # and etc.

  • Wie läuft es, wenn Sie “from . import module” in “/package/subpackage/__init__.py” schreiben?

    – Markus Unterwaditzer

    1. September 12 um 16:56 Uhr

  • Ihre “faktorisierte Version” scheint genau das Richtige für das zu sein, was Sie tun möchten. Wenn Sie eine separate Importzeile für Attribut1 und Attribut2 erstellen (wie Sie es “bevorzugen”), geben Sie sich nur absichtlich mehr Arbeit. Es gibt keinen Grund, das zu tun.

    – BrenBarn

    1. September 12 um 18:25 Uhr


  • Tut mir leid, aber ich verstehe nicht, was du willst. Könntest du deine Frage nochmal deutlicher formulieren? Was möchtest du genau machen? Ich meine, was würden Sie gerne schreiben, das nicht funktioniert, und wie würden Sie erwarten, dass es funktioniert? Nach dem, was ich gelesen habe, denke ich, dass Sie die Semantik des Imports wie Java oder vielleicht C umfassen. Zu guter Letzt: Sie können ein Modul “Stern-Import” sicher hinzufügen __all__ Variable, die eine Liste der Namen enthält, die beim Star-Import exportiert werden sollen. Bearbeiten: Okay, beim Lesen der Antwort von BrenBarn habe ich verstanden, was Sie meinten.

    – Bakuriu

    1. September 12 um 18:41 Uhr


Python Importieren eines Unterpakets oder Untermoduls
BrenBarn

Du scheinst missverstanden zu haben wie import sucht nach Modulen. Wenn Sie eine import-Anweisung verwenden, it stets sucht den aktuellen Modulpfad (bzw sys.modules); es verwendet kein Modul Objekte im lokalen Namensraum, die aufgrund früherer Importe vorhanden sind. Wenn Sie das tun:

import package.subpackage.module
from package.subpackage import module
from module import attribute1

Die zweite Zeile sucht nach einem Paket namens package.subpackage und Importe module aus diesem Paket. Diese Zeile hat keine Auswirkung auf die dritte Zeile. Die dritte Zeile sucht nur nach einem Modul namens module und findet keinen. Das aufgerufene Objekt wird nicht “wiederverwendet”. module die Sie aus der obigen Zeile erhalten haben.

Mit anderen Worten from someModule import ... bedeutet nicht “aus dem Modul namens someModule, das ich zuvor importiert habe …”, sondern “aus dem Modul namens someModule, das Sie in sys.path finden …”. Es gibt keine Möglichkeit, den Pfad eines Moduls “inkrementell” aufzubauen, indem die Pakete importiert werden, die zu ihm führen. Beim Import muss immer auf den gesamten Modulnamen verwiesen werden.

Es ist nicht klar, was Sie erreichen wollen. Wenn Sie nur das bestimmte Objektattribut1 importieren möchten, tun Sie dies einfach from package.subpackage.module import attribute1 und fertig damit. Sie müssen sich nie um die lange Sorgen machen package.subpackage.module sobald Sie den gewünschten Namen daraus importiert haben.

wenn du tun Zugriff auf das Modul haben möchten, um später auf andere Namen zuzugreifen, dann können Sie dies tun from package.subpackage import module und, wie Sie gesehen haben, können Sie dann tun module.attribute1 und so weiter, wie Sie möchten.

Falls Sie es wollen beide — das heißt, wenn Sie möchten attribute1 direkt zugänglich und Sie wollen module zugänglich, führen Sie einfach beide der oben genannten Schritte aus:

from package.subpackage import module
from package.subpackage.module import attribute1
attribute1 # works
module.someOtherAttribute # also works

Wenn Sie nicht gerne tippen package.subpackage Auch zweimal können Sie einfach manuell einen lokalen Verweis auf Attribut1 erstellen:

from package.subpackage import module
attribute1 = module.attribute1
attribute1 # works
module.someOtherAttribute #also works

  • Ihre Kommentare gehen in die gleiche Richtung wie die von Ignacio Vazquez-Abrams (ich habe seine Nachricht kommentiert). Sie ergänzen am Ende, über die Verwendung module.attribute1 ist etwas, worüber ich nachdenke, aber ich dachte, es gäbe eine Möglichkeit, die Notwendigkeit eines Präfixes überall zu vermeiden. Also muss ich entweder überall ein Präfix verwenden oder einen lokalen Alias ​​erstellen und den Namen wiederholen. Nicht der Stil, den ich erwartet hatte, aber wenn es keine Möglichkeit gibt (schließlich bin ich an Ada gewöhnt, die mit ihren Umbenennungserklärungen etwas Ähnliches erfordert).

    – Hibou57

    1. September 12 um 18:11 Uhr

  • @ Hibou57: Mir ist immer noch nicht klar, was Sie in Ihrer “Version 2” erreichen wollen. Was möchten Sie tun, was nicht möglich ist? Sie möchten niemals einen Teil des Paket-/Modul-/Attributnamens erneut eingeben, aber trotzdem sowohl das Modul als auch sein Attribut importieren?

    – BrenBarn

    1. September 12 um 18:17 Uhr


  • Ich wollte eine lokale Paketreferenz haben, genau wie Sie eine lokale Objektreferenz haben können. Es scheint, dass es endlich wirklich lokale Modulreferenzen gibt, aber Sie können diese nicht importieren. Es ist eine Mischung aus lokal und global mit einem komischen Geschmack (einige Dinge können lokal sein, andere müssen global sein, ich mag es nicht, aber ich bin in Ordnung, solange ich jetzt besser verstehe, wie es funktioniert). Danke übrigens für deine Nachricht.

    – Hibou57

    1. September 12 um 18:37 Uhr

  • Ich bin mir nicht sicher, ob Sie noch verstehen, wie es funktioniert. Oder das taten Sie 2012 auf jeden Fall.

    – Hejazzman

    13. September 17 um 10:08 Uhr

  • Jedes Mal, wenn ich nach einer 6-monatigen Entlassung zu Python zurückkehre, lande ich hier. Wenn ich nur jedes Mal upvoten könnte, wenn ich diese Seite besuche! Ich werde ein riesiges Poster mit diesem Satz erstellen: “Es gibt keine Möglichkeit, den Pfad eines Moduls “inkrementell” aufzubauen, indem die Pakete importiert werden, die zu ihm führen.”

    – PatrickT

    14. Mai 20 um 7:37 Uhr

Der Grund, warum Nr. 2 fehlschlägt, ist, weil sys.modules['module'] existiert nicht (die Importroutine hat ihren eigenen Geltungsbereich und kann die module lokaler Name), und es gibt keine module Modul oder Paket auf der Festplatte. Beachten Sie, dass Sie mehrere importierte Namen durch Kommas trennen können.

from package.subpackage.module import attribute1, attribute2, attribute3

Ebenfalls:

from package.subpackage import module
print module.attribute1

  • Ihr Hinweis auf sys.modules['name'] was ich bis jetzt nicht wusste, ließ mich denken, dass ich das befürchtet habe (und BrenBarn bestätigt): Es gibt nichts Besseres als echte Unterpakete in Python. sys.moduleswie der Name schon sagt, ist global, und wenn alle Verweise auf Module darauf angewiesen sind, dann gibt es nichts Besseres als einen lokalen Verweis auf ein Modul (kann mit Python 3.x kommen?).

    – Hibou57

    1. September 12 um 18:05 Uhr

  • Ihre Verwendung von “Referenz” ist mehrdeutig; Der Erste import in #2 erzeugt einen lokalen Verweis auf package.subpackage.module gebunden an module.

    – Ignacio Vazquez-Abrams

    1. September 12 um 18:07 Uhr

  • Ja, aber das ist ein „Modul“, aus dem ich nicht importieren kann 😉

    – Hibou57

    1. September 12 um 18:33 Uhr

Wenn Sie nur versuchen, attribute1 in Ihren globalen Namensraum zu bekommen, scheint Version 3 ganz gut zu sein. Warum ist es ein Overkill-Präfix?

In Version 2 statt

from module import attribute1

du kannst tun

attribute1 = module.attribute1

  • attribute1 = module.attribute1 wiederholt nur den Namen ohne Mehrwert. Ich weiß, dass es funktioniert, aber ich mag diesen Stil nicht (was nicht bedeutet, dass ich Ihre Antwort nicht mag).

    – Hibou57

    1. September 12 um 18:06 Uhr

  • Ich denke, ich verstehe, wie alle Leute, die hier kommentieren, nicht, was Sie tun wollen. In allen Beispielen, die Sie geben, sieht es so aus, als wollten Sie am Ende ein Symbol aus einem Unterpaket in Ihrem Namensraum haben. Ihr nicht funktionierendes Beispiel (Beispiel 2) möchte dies tun, indem es ein Submodul aus einem Paket importiert und dann ein Symbol aus diesem Submodul importiert. Ich weiß nicht, warum Sie es in zwei Schritten statt in einem machen wollen. Erklären Sie vielleicht genauer, was Ihre ideale Lösung wäre und warum.

    – Thomas Vander Stichele

    3. September 12 um 9:32 Uhr

.

758340cookie-checkPython: Importieren eines Unterpakets oder Untermoduls

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy