import Rätsel...

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Ich habe folgende Struktur:

Code: Alles auswählen

any_app/
:...core/
    :... __init__.py
    :... main.py
:... utils/
    :... __init__.py
    :... utility.py
main.py:

Code: Alles auswählen

from any_app.utils import utility
utility.py:

Code: Alles auswählen

from any_app.core import main
1. Wo ist ``main``?

Code: Alles auswählen

>>> import any_app.core
>>> dir(any_app.core)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__']
2. Warum?

Code: Alles auswählen

>>> from any_app.core import main
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "any_app/core/main.py", line 1, in <module>
    from any_app.utils import utility
  File "any_app/utils/utility.py", line 1, in <module>
    from any_app.core import main
ImportError: cannot import name main
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Die Namen welche in any_app.core verfuegbar sind wird durch dessen __init__.py bestimmt. Da wird nicht magisch main importiert.

Wenn du das machen willst, musst du ein

Code: Alles auswählen

import any_app.core.main as main
in selbiges __init__.py schreiben, und dann hast du das verfuegbar. So geht auch os vor, um os.path schon gleich anzubieten. Da ist das etwa komplizierter, aber das Prinzip ist das gleiche.

Was du *nicht* tun solltest, auch wenn es in Python2.x geht, ist "import main". Denn das ist ein relativer Import, und die sind Pfui, und das funktioniert auch nicht mehr, wenn man "from __future__ import absolute_import" angibt - aus gutem Grund.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@__deets__
Eben nicht. Auch wenn ich in der ``any_app.core.__init__.py`` ein

Code: Alles auswählen

import any_app.core.main as main
ausführe, bekomme ich

Code: Alles auswählen

>>> from any_app.core import main
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "any_app/core/__init__.py", line 1, in <module>
    import any_app.core.main as main
  File "any_app/core/main.py", line 1, in <module>
    from any_app.utils import utility
  File "any_app/utils/__init__.py", line 1, in <module>
    import any_app.utils.utility as utility
  File "any_app/utils/utility.py", line 1, in <module>
    from any_app.core import main
ImportError: cannot import name main
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
BlackJack

@mutetella: Ich denke __deets__ ging davon aus das es hier nur um die Verzeichnisshierarchie ging und nicht zusätzlich in den Modulen noch zirkuläre Importe bestehen. Die macht man nämlich unter anderen genau aus diesem Grund nicht.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Tatsaechlich geht es nicht so, wie ich das dachte. Sieh Code unten.

Die einzige Begruendung dafuer, die ich mir vorstellen kann ist, dass waehrend "any_app.core" als Modul definiert wird, soll durch einen import schon darauf Bezug genommen werden. Das muss natuerlich fehlschlagen. Aber einen eleganten Weg, ohne relative Importe doch ein komplettes Paket/Modul in den Namensraum zu hieven habe ich nicht gefunden - soll vielleicht nicht sein - oder, sonst wer einen Idee?

@BlackJack: deinen zirkulaeren import Bezug verstehe ich nicht ganz - wer zirkelt wo?

Code: Alles auswählen

import sys
import os
import shutil

basedir = sys.argv[1]

if os.path.exists(basedir):
    shutil.rmtree(basedir)

os.mkdir(basedir)

files = {
    ("any_app", "__init__.py") : "",
    ("any_app", "core", "__init__.py") : """
import main # geht, aber pfui. Nur was sonst?
from .main import main_func # geht
#import any_app.core.main as main # geht nicht
""",
    ("any_app", "core", "main.py") : """
def main_func():
    print "main_func"
    """,
    }

for path, content in files.iteritems():
    destpath = basedir
    for part in path[:-1]:
        destpath = os.path.join(destpath, part)
        if not os.path.exists(destpath):
            os.mkdir(destpath)
    destfile = os.path.join(destpath, path[-1])
    with open(destfile, "wb") as outf:
        outf.write(content)

sys.path.append(basedir)
import any_app.core.main

Benutzeravatar
kbr
User
Beiträge: 1510
Registriert: Mittwoch 15. Oktober 2008, 09:27

@__deets__: main.py und utility.py importieren sich gegenseitig. So was geht schief.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Ok, ich hab' unter anderem noch diesen Beitrag auf google groups gefunden, der mein Problem widerspiegelt. Wenn ich das richtig verstehe, dann liegt mein Problem hier:
If a module does exist in sys.modules then an import simply returns that
module whether or not it has completed executing. That is the reason why
cyclic imports may return modules which appear to be partly empty.
Jetzt könnte ich natürlich folgende Änderung machen:
``any_app/core/main.py``

Code: Alles auswählen

#from any_app.utils import utility
import any_app.utils
``any_app/utils/utility``

Code: Alles auswählen

#from any_app.core import main
import any_app.core
Dadurch umgehe ich zwar das Problem, erzeuge aber so einen Wahnsinn (das ist doch jetzt ein circular import, oder?):

Code: Alles auswählen

>>> from any_app.core import main
>>> dir(main.any_app)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', 'core', 'utils']
>>> dir(main.any_app.core)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', 'main']
>>> dir(main.any_app.core.main)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'any_app']
>>> dir(main.any_app.core.main.any_app)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', 'core', 'utils']
Ist das ganze hier vielleicht mit ein Beispiel für das, was ich in Gründe für import innerhalb Funktion? angesprochen hatte?

Und jetzt natürlich die Frage: Wie lässt sich das lösen?
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
BlackJack

@mutetella: Das ist eigentlich kein Grund für einen ``import`` in einer Funktion sondern ein Grund keine zirkulären importe zu machen. Dein `main` braucht `utility` und `utility` braucht `main`? Warum? Wenn sich zwei Module gegenseitig brauchen, dann stellt sich die Frage warum das dann überhaupt zwei Module sind wenn die so eng zusammenhängen. Den Namen nach würde ich sagen dürfte `utility` das `main`-Modul nicht benötigen. Das löst man normalerweise in dem man das was beide Module brauchen in ein drittes Modul auslagert um den zirkulären Import loszuwerden.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@BlackJack
Ich habe ein ``core`` package, das neben dem ``main`` module auch ein ``dt`` module enthält, in dem sich Klassen befinden, die ich sowohl in ``main`` als auch in ``utils`` verwende. Und diverse Funktionen aus ``utils`` wiederum verwende ich in ``main``. Selbst wenn ich diese Klassen in ein anderes Modul auslagern würde, wäre damit das Problem nicht gelöst? Dann würde ich doch nur dieses neue Modul wiederum in ``main`` und ``utils`` importieren müssen.
Und: Weshalb habe ich das Problem erst, seitdem ich meine Module innerhalb packages thematisiert habe?
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

EDIT:
Oh Mann, ich blicke bald selbst nicht mehr durch... :oops: :

Ich habe ein Modul `utils/utils.py`, das auf Klassen aus `core/dt.py` zugreift. Und `core/dt.py` wiederum verwendet Hilfsfunktionen aus `utils/utils.py`. Das ist das Problem...
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Sirius3
User
Beiträge: 18335
Registriert: Sonntag 21. Oktober 2012, 17:20

@mutetella: da sieht man mal wieder, dass es kein Problem ist, dass es keine zirkulären Importe gibt, sondern dass diese Einschränkung hilft, gut strukturierten Code zu schreiben. Am besten versuchst Du mal, Deine Abhängigkeiten mit Papier und Bleistift zu entwirren.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@Sirius3
Offensichtlich, ja. Allerdings verstehe ich noch nicht, weshalb das Problem erst auftrat, nachdem ich meine Module auf Packages verteilt habe.
Ohne Packages hatte ich:
`dt.py`:

Code: Alles auswählen

import utils
`utils.py`:

Code: Alles auswählen

import dt
Seit der Aufteilung in Packages:
`core/dt.py`:

Code: Alles auswählen

from denkdran.utils import utils
`utils/utils.py`:

Code: Alles auswählen

from denkdran.core import dt
Wo genau liegt der Unterschied?
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
snafu
User
Beiträge: 6908
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

mutetella hat geschrieben:Oh Mann, ich blicke bald selbst nicht mehr durch... :oops: :
Das spricht nicht unbedingt dafür, dass deine derzeitige Strukturierung besonders hilfreich ist. Bevor man da jetzt an den Symptomen solange herumdoktert bis es irgendwie funktioniert, würde ich doch eher empfehlen, den kompletten Entwurf nochmal zu überdenken.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@snafu
Nun ja, ganz so dramatisch ist es jetzt auch wieder nicht... `utils` verwendet etwas aus meinem `dt` Modul und anderst 'rum... Jetzt, da ich weiß, wo das Problem liegt, lässt sich das sicher umgestalten. Und ich habe auch nicht vor, an den Symptomen herumzudoktern, allerdings muss ich jetzt auch nicht die gesamte Strukturierung in Frage stellen...

Vielmehr würde mich eine Antwort auf meine letzte Frage interessieren...
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Antworten