So importieren Sie in __init__.py definierte Klassen

105

Ich versuche, einige Module für meinen eigenen Gebrauch zu organisieren. Ich habe so etwas:

lib/
  __init__.py
  settings.py
  foo/
    __init__.py
    someobject.py
  bar/
    __init__.py
    somethingelse.py

In lib/__init__.pymöchte ich einige Klassen definieren, die verwendet werden sollen, wenn ich lib importiere. Ich kann es jedoch nicht herausfinden, ohne die Klassen in Dateien zu trennen und sie zu importieren __init__.py.

Anstatt zu sagen:

    lib/
      __init__.py
      settings.py
      helperclass.py
      foo/
        __init__.py
        someobject.py
      bar/
        __init__.py
        somethingelse.py

from lib.settings import Values
from lib.helperclass import Helper

Ich möchte so etwas:

    lib/
      __init__.py  #Helper defined in this file
      settings.py
      foo/
        __init__.py
        someobject.py
      bar/
        __init__.py
        somethingelse.py

from lib.settings import Values
from lib import Helper

Ist es möglich oder muss ich die Klasse in eine andere Datei trennen?

BEARBEITEN

OK, wenn ich lib aus einem anderen Skript importiere, kann ich auf die Helper-Klasse zugreifen. Wie kann ich über settings.py auf die Helper-Klasse zugreifen?

Das Beispiel hier beschreibt Intra-Package-Referenzen. Ich zitiere "Submodule müssen sich oft aufeinander beziehen". In meinem Fall benötigt lib.settings.py den Helper und lib.foo.someobject Zugriff auf Helper. Wo soll ich also die Helper-Klasse definieren?

Scottm
quelle
Ihr letztes Beispiel dort sollte funktionieren. Sehen Sie einen ImportError? Können Sie die Details einfügen?
Joe Holloway

Antworten:

81
  1. Das lib/übergeordnete Verzeichnis von muss sich in befinden sys.path.

  2. Dein ' lib/__init__.py' könnte so aussehen:

    from . import settings # or just 'import settings' on old Python versions
    class Helper(object):
          pass

Dann sollte das folgende Beispiel funktionieren:

from lib.settings import Values
from lib import Helper

Antwort auf die bearbeitete Version der Frage:

__init__.pydefiniert, wie Ihr Paket von außen aussieht. Wenn Sie verwenden müssen , Helperin settings.pydefinieren dann Helperin einer anderen Datei zB ‚ lib/helper.py‘.

.
| `- import_submodule.py
    `- lib
    | - __init__.py
    | - foo
    | | - __init__.py
    | `- someobject.py
    | - helper.py
    `- settings.py

2 Verzeichnisse, 6 Dateien

Der Befehl:

$ python import_submodule.py

Ausgabe:

settings
helper
Helper in lib.settings
someobject
Helper in lib.foo.someobject

# ./import_submodule.py
import fnmatch, os
from lib.settings import Values
from lib import Helper

print
for root, dirs, files in os.walk('.'):
    for f in fnmatch.filter(files, '*.py'):
        print "# %s/%s" % (os.path.basename(root), f)
        print open(os.path.join(root, f)).read()
        print


# lib/helper.py
print 'helper'
class Helper(object):
    def __init__(self, module_name):
        print "Helper in", module_name


# lib/settings.py
print "settings"
import helper

class Values(object):
    pass

helper.Helper(__name__)


# lib/__init__.py
#from __future__ import absolute_import
import settings, foo.someobject, helper

Helper = helper.Helper


# foo/someobject.py
print "someobject"
from .. import helper

helper.Helper(__name__)


# foo/__init__.py
import someobject
jfs
quelle
Wie kann ich in meinem Beispiel die Helper-Klasse in die Datei settings.py importieren?
Scottm
Ich verstehe nicht, warum das kreisförmig ist. Wenn settings.py Helper benötigt und foo.someobject.py Helper benötigt, wo schlage ich vor, dass ich es definiere?
Scottm
Wow, das Wort "Helfer" verliert in diesem Beispiel wirklich an Bedeutung. Sie haben mir jedoch gezeigt, wonach ich gesucht habe.
Scottm
3
upvoted for "__init__.py definiert, wie Ihr Paket von außen aussieht."
Petri
19

Wenn lib/__init__.pydie Helper-Klasse definiert ist, können Sie in settings.py Folgendes verwenden:

from . import Helper

Das funktioniert weil. ist das aktuelle Verzeichnis und fungiert aus Sicht des Einstellungsmoduls als Synonym für das lib-Paket. Beachten Sie, dass es nicht erforderlich ist, Helper über zu exportieren __all__.

(Bestätigt mit Python 2.7.10 unter Windows.)

yoyo
quelle
1
Das funktioniert gut für mich, Downvoter erklären bitte Ihr Missfallen?
Yooy
8

Sie setzen sie einfach in __init__.py.

Also mit test / classes.py als:

class A(object): pass
class B(object): pass

... und test / __ init__.py ist:

from classes import *

class Helper(object): pass

Sie können Test importieren und haben Zugriff auf A, B und Helper

>>> import test
>>> test.A
<class 'test.classes.A'>
>>> test.B
<class 'test.classes.B'>
>>> test.Helper
<class 'test.Helper'>
Aaron Maenpaa
quelle
Woher importieren Sie?
Aaron Maenpaa
Angenommen, ich möchte Helper aus lib / settings.py importieren?
Scottm
1
Dies führt mit ziemlicher Sicherheit zu einem zirkulären Import (Einstellungen importieren Test und Test importiert Einstellungen) ... der den von Ihnen beschriebenen NameError erzeugt. Wenn Sie Helfer benötigen, die im Paket verwendet werden, sollten Sie ein internes Modul definieren, das Ihr Code verwendet.
Aaron Maenpaa
1
Helfer in init .py sollten für externe Benutzer sein, um Ihre API zu vereinfachen.
Aaron Maenpaa
1
Wenn es nicht Teil der API ist, ist init .py wirklich nicht der richtige Ort dafür. lib / internal.py oder ähnliches wäre viel besser (was den doppelten Zweck hat, die Wahrscheinlichkeit von Zirkularimporten zu verringern).
Aaron Maenpaa
5

Fügen Sie so etwas hinzu lib/__init__.py

from .helperclass import Helper

Jetzt können Sie es direkt importieren:

from lib import Helper

Dawid Gosławski
quelle
4

Bearbeiten, da ich die Frage falsch verstanden habe:

Setzen Sie einfach die HelperKlasse ein __init__.py. Das ist perfekt pythonisch. Es fühlt sich einfach seltsam an, aus Sprachen wie Java zu kommen.

Richard Levasseur
quelle
Du hast das falsch verstanden. Ich möchte die Datei helperClass.py nach Möglichkeit entfernen.
Scottm
Richard ist nicht der einzige, der falsch verstanden hat. Ihr Beispiel sollte funktionieren. Was ist der Traceback?
Troy J. Farrell
Nun, dann habe ich die Dokumente richtig gelesen. Also, jetzt habe ich gerade einen Testfall gemacht und es funktioniert gut.
Scottm
Ich habe das gleiche Setup in meinem Paket, aber ich erhalte einen ImportError "Name Helper kann nicht importiert werden"
scottm
Ich glaube, mein Problem ist, dass ich versuche, die Helper-Klasse aus settings.py zu importieren. Wie kann ich das tun?
Scottm
2

Ja, es ist möglich. Möglicherweise möchten Sie auch __all__in __init__.pyDateien definieren . Es ist eine Liste von Modulen, die importiert werden, wenn Sie dies tun

from lib import *
vartec
quelle
-6

Vielleicht könnte das funktionieren:

import __init__ as lib
Turion
quelle