Max Most: Python: Verständnisprobleme mit import/__init__.py

Nabend, die Herren,

ich habe, wie der Titel sagt, leichte Verständnisprobleme mit dem Import-System in Python. Angenommen eine Dateistruktur wie die folgende:

foo.py
bar/
    __init__.py
    baz.py
    boo.py

Die init.py enthält sowas wie:

from baz import *
from boo import *

Und bar/baz.py enthält:

__all__ = ["how_cool"]

def how_cool():
    return -273.15

Was ich erwarten würde, und hier liege ich offensichtlich falsch, ist, daß ich in foo.py folgendes schreiben kann:

import bar

print(bar.how_cool())

Was ich tatsächlich bekomme, ist: ImportError: No module named 'baz', und zwar in der init.py. Nun könnte ich die init.py leeren und in foo.py sowas schreiben wie:

import bar.baz

print(bar.baz.how_cool())

Aber damit kann ich ehrlich gesagt nicht leben. Simple Funktionsaufrufe wären mir zu lang (module.submodule1.do_something(module.submodule2.get_data())), circular imports würden mir vermutlich das Leben erschweren, und überhaupt, ich scheine hier etwas nicht zu verstehen. Was ich möchte, ist, einen Haufen an Funktionen o. ä. in einen Ordner zu schmeißen und die dann in einem Namespace zusammengefaßt haben. Halt als package.do_something(), selbst wenn "package" eine Reihe an Dateien oder sogar Unterordnern mit Dateien umfaßt. Wäre für jeden Denkanstoß dankbar.

Danke vorab, Max

  1. moin,

    ich vermute mal, dass Dateinamen wie __init__.py nicht erlaubt sind und andernfalls damit möglicherweise eine deep recursion stattfindet.

    Prüf das mal.pl

    1. Hallo

      ich vermute mal, dass Dateinamen wie __init__.py nicht erlaubt sind und andernfalls damit möglicherweise eine deep recursion stattfindet.

      Aha.

      „The __init__.py files are required to make Python treat the directories as containing packages; this is done to prevent directories with a common name, such as ‚string‘, from unintentionally hiding valid modules that occur later on the module search path. In the simplest case, __init__.py can just be an empty file, but it can also execute initialization code for the package or set the __all__ variable, described later.“

      Tschö, Auge

      --
      Wenn man ausreichende Vorsichtsmaßnahmen trifft, muss man keine Vorsichtsmaßnahmen mehr treffen.
      Toller Dampf voraus von Terry Pratchett
      1. Hallo

        ich vermute mal, dass Dateinamen wie __init__.py nicht erlaubt sind und andernfalls damit möglicherweise eine deep recursion stattfindet.

        Aha.

        Spielverderber ;)

        Kompliziert in Python, dasselbe in Perl

        Selber schuld ;)

  2. Tach!

    Was ich tatsächlich bekomme, ist: ImportError: No module named 'baz', und zwar in der init.py.

    Kann ich nicht nachvollziehen. Getestet in Python 2.7.5 kommt bei mir kein Fehler sondern die Ausgabe.

    dedlfix.

    1. Hi,

      Kann ich nicht nachvollziehen. Getestet in Python 2.7.5 kommt bei mir kein Fehler sondern die Ausgabe.

      Hah! Da sind wir der Lösung doch möglicherweise schon etwas näher. Ich hätte dazuschreiben sollen: Getestet nur in Python 3(.4.2). In Python 2 geht es tatsächlich. Die einzig relevante Stelle aus der Doku (Unterschiede zwischen 3 und 2), die ich auf Anhieb finden konnte, besagt:

      The only acceptable syntax for relative imports is from .[module] import name. All import forms not starting with . are interpreted as absolute imports.

      Wenn ich bar/init.py ändere auf:

      from . import *
      from . import *
      

      kommt allerdings: AttributeError: 'module' object has no attribute 'how_cool'. Diesmal in Python 3 und 2.

      Grüße, Max

      1. Hallo nochmal.

        Wenn ich bar/init.py ändere auf:

        from . import *
        from . import *
        

        kommt allerdings: AttributeError: 'module' object has no attribute 'how_cool'. Diesmal in Python 3 und 2.

        Und wenn ich mich dann ein kleines bißchen weniger dämlich anstelle und folgendes in bar/init.py notiere:

        from .baz import *
        from .boo import *
        

        dann funktioniert auch alles so, wie ich das wollte. :-D Danke für den Denkanstoß, mehr hat's anscheinend nicht gebraucht. Läuft.

        Grüße, Max

  3. Hallo

    Vorausgeschickt sei, dass ich mit Python selbst erst in der Experimentalphase bin.

    Angenommen eine Dateistruktur wie die folgende:

    foo.py
    bar/
        __init__.py
        baz.py
        boo.py
    

    Die init.py enthält sowas wie:

    from baz import *
    from boo import *
    

    Wenn ich das Tutorial an der Stelle richtig verstehe, muss man, um import * benutzen zu können, irgendwo „oberhalb“ die Liste __all__ mit den Namen der Submodule angelegt haben. Die scheint normalerweise in der init.py zu liegen.

    Du machst es anders herum. Du notierst in der init.py den Sternchen-Import und legst erst in dem so aufgerufenen Modul die Liste __all__ an.

    import bar.baz
    
    print(bar.baz.how_cool())
    

    Aber damit kann ich ehrlich gesagt nicht leben. Simple Funktionsaufrufe wären mir zu lang (module.submodule1.do_something(module.submodule2.get_data())), …

    Mal abgesehen von deinem konkreten Fall: Du kannst Module auch mit einem Alias importieren.

    import bar.baz as bazz
    
    print(bazz.how_cool())
    

    Tschö, Auge

    --
    Wenn man ausreichende Vorsichtsmaßnahmen trifft, muss man keine Vorsichtsmaßnahmen mehr treffen.
    Toller Dampf voraus von Terry Pratchett
    1. Hi,

      Wenn ich das Tutorial an der Stelle richtig verstehe, muss man, um import * benutzen zu können, irgendwo „oberhalb“ die Liste __all__ mit den Namen der Submodule angelegt haben. Die scheint normalerweise in der init.py zu liegen.

      Jap. Mit all innerhalb der Module definiert man, welche Funktionen, Klassen usw. innerhalb dieses Moduls von * umfaßt werden. Eine Definition wie all = ["baz", "boo"] innerhalb von bar/init.py sollte in diesem Fall keinen Unterschied machen.

      Mal abgesehen von deinem konkreten Fall: Du kannst Module auch mit einem Alias importieren.

      Habe das bisher auch immer so gehandhabt. Wäre in meinem konkreten Fall aber weit unschöner als einfach "import package", und ich stoße hier auch zum ersten Mal auf Probleme mit circular imports, die ich mit einem simplen "import package" nicht haben sollte, wenn ich das richtig verstehe. Wenn.

      Grüße, Max