Ich möchte nochmals auf das Thema Projektorganisation in Python zu sprechen kommen. Als Hintergrund: Es geht um eine Geräteemluation, benannt PyEMU. Das ganze läuft in einem Minipc unter Linux (ohne Tastatur & Bildschirm). Nach "innen" wird V24 gesprochen, nach aussen V24 und TCP/IP und Named Pipes und (in Zukunft vielleicht) USB. Anforderungen waren z.B. - Infrastruktur (Hochfahren, Konfiguration, Logfiles abziehen usw.) soll unabhängig vom nach aussen exportierten Protokoll sein - Voll dynamisch (d.h. eine Konfigurationsdatei legt fest, welches Protokoll über welche SChnittstelle mit welchem anderen Protokoll spricht) - Soll auf einer Read-Only-Partition laufen (d.h. / wird nach dem Booten ro geremounted), wg. plötzlichem Stromausfall usw. - Erweiterbar für weitere Protokolle / Schnittstellen (z.B. USB) Bisher habe ich folgende Projektorganisation irgendwas irgendwas/PyEMU irgendwas/PyEMU/protokoll_1 irgendwas/PyEMU/protokoll_2 .... irgendwas/PyEMU/protokoll_n In <irgendwas> ist nur ein Programm: main.py aus Gründen der Übersichtlichkeit. Das importiert das Modul PyEMU und startet es mit Parametern nach (Vorteil: PyEMU kann unter Windows als NT-Service konfiguriert werden); eigentliche Codebasis bleibt identisch. In <irgendwas/PyEMU> liegt der eigentliche Code, bestehend aus ungefähr 50 Sourcen. In <irgendwas/PyEMU/protokoll_x> liegen die HW-Protokolle, natürlich mit sprechenden Namen (also z.B. "Fingerprint" für "Protokoll des Fingerprint-Sensors"). Das Modul hat für jeden Befehl einen eigenen Sourcecode, aus folgenden Gründen: - Man findet die Sourcen zu einem Befehl leichter. Das mag harmlos klingen, ist aber etwas, was mich immer schon gestört hat: ich habe keine "richtige" IDE in Python, und bei sagen wir 60 Befehlen ist die Suche nach einem speziellen rein über grep doch etwas *arg* mühsam. Der Dateiname als Strukturierung bietet sich da schon an. - Die Befehle können ziemlich umständlich sein (z.B. Statistikauswertung, Verschlüsselung usw.) -> die Sourcen sollten nach Möglichkeit nicht >500 Zeilen haben. - Die Verzeichnisse enthalten je bis zu 60 Sourcen. Meine Probleme mit dem Ganzen 1) Abhängigkeiten der Module Beispiel. Ich möchte aus irgendwas/PyEMU/protokoll_1/blabla.py eine Funktion in irgendwas/PyEMU/misc.py aufrufen. Dann muß ich schreiben (immer vorausgesetzt, daß <irgendwas> bereits in den PYTHON_PATH aufgenommen wurde) import PyEMU.misc PyEMU.misc.funktion() Wenn ich statt dessen in irgendwas/PyEMU/blabla.py bin, kann ich direkt schreiben import misc misc.funktion() Noch schlimmer wird es, wenn protokoll_1 etwas von protokoll_2 braucht (was möglich ist, wenn es sich um abhängige Hardware handelt; z.B. kann Gerätetyp A nur betrieben werden, wenn Gerätetyp B (Alarm) möglich ist; also: in irgendwas/PyEMU/protokoll_1/funktion.py: import PyEMU.protokoll_2.irgendwas if PyEMU.protokoll_2.irgendwas.alarmIstDa(): # ok, weiter gehts 2) Entscheidung, was mache ich als Modul, was nicht. z.B. habe ich verschiedene Transportsysteme für die Protokolle (V24, TCP/IP, Dateibasiert für Named Pipes & Testfiles). Mache ich daraus ein eigenständiges Modul, oder lasse ich die Sourcen im "main"-Verzeichnis? Bisher ja; eigentlich gehört das aber auch in ein Modul rein. Aber: Mache ich ein Modul "transportsystems" oder ein Modul pro Transportsystem? 3) Ferner: In der Konfiguration habe ich z.B. Einträge wie den folgenden (Real-Life-Beispiel:) <transport> <protocol>FingerprintProtocol</protocol> <type>SerialTransportLayer</type> <portname>COM1</portname> <baudrate>38400</baudrate> <parity>none</parity> <stopbits>1</stopbits> <databits>8</databits> <traceV24>0</traceV24> </transport> Wenn ich die Konfigurationsdatei einlese, kann ich hübsch ein requestedType = { hier z.B. "SerialTransportLayer" } ... module = __import__(requestedType, globals(), locals(), []); return getattr( module, requestedType ) machen und habe meine Transportschicht. Wenn ich die aber in ein Modul gepackt habe, komme ich in Namensraumkonflikteschrott rein. 4) Da habe ich dann so hilfsmodule wie "trace.py". Packe ich die in ein weiteres Modul? Gehört das nicht in sitepackages, weil es Projektübergreifend gestaltet werden kann? Irgendwie befriedigt mich die Projektorganisation nicht: sie funktioniert, ist aber nicht "schön". Deshalb nochmal die Frage: Wie strukturiert ihr größere Pythonprojekte (Source-# > 300)? _______________________________________________ Python-de maillist - Python-de@python.net http://python.net/mailman/listinfo/python-de
Hi Gerson, Gerson Kurz wrote:
Ich möchte nochmals auf das Thema Projektorganisation in Python zu sprechen kommen [...] 1) Abhängigkeiten der Module
Beispiel. Ich möchte aus
irgendwas/PyEMU/protokoll_1/blabla.py
eine Funktion in
irgendwas/PyEMU/misc.py
aufrufen. Dann muß ich schreiben (immer vorausgesetzt, daß <irgendwas> bereits in den PYTHON_PATH aufgenommen wurde)
import PyEMU.misc PyEMU.misc.funktion()
Wenn ich statt dessen in
irgendwas/PyEMU/blabla.py
bin, kann ich direkt schreiben
import misc misc.funktion()
Vorsicht! Aus Sicht von Python sind damit PyEMU.misc und misc zwei _unterschiedliche_ Module. Meistens geht das gut, aber ich bin mit so etwas mal im Zusammenhang mit isinstance(obj, cls) auf die Nase gefallen und schreibe seitdem brav überall dieselben Import-Befehle, bzw. alle bezogen auf dasselbe Verzeichnis im PYTHONPATH :-) Tipp: in sys.modules schauen Im folgenden Beispiel entsprechen cache und tools.cache derselben Quelltextdatei. Der unten stehende Abschnitt ist aus einem laufenden Interpreter geschnippelt (bis auf den gekürzten Pfad in sys.modules['tools.cache']).
import cache import tools.cache import sys sys.modules['cache'] <module 'cache' from 'cache.pyc'> sys.modules['tools.cache'] <module 'tools.cache' from '/.../tools/cache.pyc'> c = cache.Cache() isinstance(c, tools.cache.Cache) 0 class Cache2(tools.cache.Cache): pass ... issubclass(Cache2, cache.Cache) 0
Ob mir zu deinen anderen Fragen noch etwas Hilfreiches einfällt, muss ich mal sehen. Viele Grüße Stefan _______________________________________________ Python-de maillist - Python-de@python.net http://python.net/mailman/listinfo/python-de
participants (2)
-
Gerson.Kurz@t-online.de
-
Stefan Schwarzer