package __init__.py from x import *

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
droptix
User
Beiträge: 521
Registriert: Donnerstag 13. Oktober 2005, 21:27

Habe ein Modul, welches plattformspezifische Operationen durchführt, z.B. Systeminfos auslesen. Unter Windows möchte ich z.B. die Win32 Extensions verwenden und unter Unix muss es aus Dateien gelesen werden oder man holt sich Infos aus geparsten Ausgaben bestimmter Befehle.

Um später weitere Plattformen hinzufügen zu können, dachte ich eher an ein Package, um die zusammengehörigen .py-Dateien besser zu strukturieren.

Also habe ich ein Verzeichnis namens qwer angelegt. Dort drin liegen:
  • • __init__.py
    • qwer.py
    • win32.py
Ein import qwer soll nun also ins Verzeichnis qwer wandern und dort die __init__.py ausführen. Dort drin steht:

Code: Alles auswählen

import sys

PLATFORM = sys.platform

# define platform specific modules here and import them 'as osdep' (OS dependent)
if PLATFORM == "win32":
	import win32 as osdep
else:
	osdep = None
	raise ImportError("This platform is not supported: %s" % PLATFORM)

# base module
from qwer import *
Das "base module" qwer/qwer.py enthält ein plattformunabhängiges Gerüst, quasi eine Abstraktionsschicht wenn man so will. Sie benutzt einheitliche Klassennamen und Funktionsnamen und liefert gleiche Ergebnisse für alle Plattformen.

Das plattformspezifische Modul qwer/win32.py enthält alle Namen, die qwer/qwer.py benutzt. Als Rückgabewert bringt win32.py immer standardisierte (von mir vorgegebene) Formate, mit der das "base module" was anfangen kann.

Sinn der Sache ist es, dass man später für Unix und Co. weitere plattformspezifische Module hinzufügen kann. Sie müssen ebenfalls alle Namen enthalten und gleich formatierte Rückgabewerte liefern wie win32.py, nur wie sie an die Informationen rankommen kann intern völlig anders gestaltet sein.

Nun endlich zur Frage: from qwer import * importiert ja nur alles, was nicht mit einem Unterstrich ("_") beginnt. Ich benutze aber auch Funktionsnamen und Modulvariablen, die mit einem Unterstrich beginnen. Die werden dann nicht importiert. Keine gute Lösung. Ich nutze das, weil ich alles aus qwer/qwer.py verfügbar haben will, wenn ich mittels import qwer das Package importiere. Ich möchte quasi alles aus qwer/qwer.py in qwer/__init__.py verfügbar machen. Wie erreiche ich mein Ziel?

Frage 2: Das Importieren der plattformspezifischen Module ist komisch bzw. ich verstehe es nicht… import win32 as osdep funktioniert zwar fehlerfrei, steht dann aber nach so einem Aufruf hier nicht zur Verfügung:

Code: Alles auswählen

import qwer
a = qwer.AClass()
# NameError: global name 'osdep' is not defined
qwer/qwer.py:

Code: Alles auswählen

class AClass:
    def __init__(self):
        print osdep.test
qwer/win32.py:

Code: Alles auswählen

test = "works"
Wieso ist osdep nicht in qwer/qwer.py verfügbar, wenn doch zuvor win32 unter dem Alias osdep importiert wurde? Was mache ich falsch? Auch das hier scheitert:

Code: Alles auswählen

import qwer
print osdep
# NameError: name 'osdep' is not defined
[Edit:] Man beachte: Im letzten Code-Snippet heißt es nur noch name und nicht mehr global name.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Möchtest du sowas erreichen?

Code: Alles auswählen

# a.py
from b import *
print _foo

Code: Alles auswählen

# b.py
__all__ = ['_foo']
_foo = 42
Aber ist es wirklich eine gute Idee, die Python-Konvention, dass Namen mit "_" privat in einem Modul sind, künstlich zu verletzten? Ich würde glaube ich lieber mit anderen Namen arbeiten.

Stefan
droptix
User
Beiträge: 521
Registriert: Donnerstag 13. Oktober 2005, 21:27

sma hat geschrieben:Möchtest du sowas erreichen?

Code: Alles auswählen

# a.py
from b import *
print _foo
Ja, eigentlich schon.
sma hat geschrieben:

Code: Alles auswählen

# b.py
__all__ = ['_foo']
_foo = 42
Ich dachte das __all__ Attribut bezieht sich nur auf Submodule/-packages, also auf "Unterordner" sozusagen.
sma hat geschrieben:Aber ist es wirklich eine gute Idee, die Python-Konvention, dass Namen mit "_" privat in einem Modul sind, künstlich zu verletzten? Ich würde glaube ich lieber mit anderen Namen arbeiten.
Finde ich nicht. Das Nutzen von __all__ wird sogar empfohlen, z.B. unter Windows, weil es du u.U. zu Pfadproblemen kommen kann, wenn Submodule eingebunden werden sollen. Irgendwelche Windows-Eigenarten machen da wohl manchmal Probleme.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

droptix hat geschrieben:Das Nutzen von __all__ wird sogar empfohlen
Ich sehe nicht wo in dem Dokument von ``__all__`` die Rede ist...
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
droptix
User
Beiträge: 521
Registriert: Donnerstag 13. Oktober 2005, 21:27

Oh ja, hab mich vertan. Das hier meinte ich:
6.4.1 Importing * From a Package hat geschrieben:6.4.1 Importing * From a Package

Now what happens when the user writes from sound.effects import *? Ideally, one would hope that this somehow goes out to the filesystem, finds which submodules are present in the package, and imports them all. Unfortunately, this operation does not work very well on Windows platforms, where the filesystem does not always have accurate information about the case of a filename! On these platforms, there is no guaranteed way to know whether a file ECHO.PY should be imported as a module echo, Echo or ECHO. (For example, Windows 95 has the annoying practice of showing all file names with a capitalized first letter.) The DOS 8+3 filename restriction adds another interesting problem for long module names.

The only solution is for the package author to provide an explicit index of the package. The import statement uses the following convention: if a package's __init__.py code defines a list named __all__, it is taken to be the list of module names that should be imported when from package import * is encountered. It is up to the package author to keep this list up-to-date when a new version of the package is released. Package authors may also decide not to support it, if they don't see a use for importing * from their package.
BlackJack

Und wo liesst Du da jetzt heraus, das es empfohlen wird "private" Namen über `__all__` zu exportieren!? Ich sehe das eher als Mechanismus um *mehr* vor einem Sternchen-Import zu "verstecken" als die "privaten" Namen, und nicht um diese nach aussen verfügbar zu machen.

Wenn Du alles aus `quer.py` in der `__init__.py` haben möchtest, wäre es wohl das einfachste den Quelltext auch wirklich in die `__init__.py` zu schreiben.
droptix
User
Beiträge: 521
Registriert: Donnerstag 13. Oktober 2005, 21:27

BlackJack hat geschrieben:Wenn Du alles aus `quer.py` in der `__init__.py` haben möchtest, wäre es wohl das einfachste den Quelltext auch wirklich in die `__init__.py` zu schreiben.
So hab ich das mittlerweile auch gemacht :P
Antworten