"Export" an Modul möglich?

Guten Abend, in einer Datenbank-Anwendung, die später SQLite, PostgreSQL und evt. weitere Enginges bedienen soll, habe ich folgende Situation: Modell.py definiert mir Objekte, die auf einer SQL-DB operieren. Dieses Modul möchte ich auch für andere DB-Anwendungen nutzen können. Daher kennt Modell.py die tatsächliche DB nicht. Modelle.py definiert anwendungsspezifisch Objekte, die die jeweilige SQL-Tabellenstruktur abbilden. Grundlage dafür sind die (generischen) Objekte aus Modell.py Tools.py definiert weitere anwendungsspezifische Operationen auf der DB, typischerweise SELECT Anwendungen für Auswertungen. Main.py ist das Hauptprogramm. Das Hauptprogramm bekommt vom Benutzer z.B. auch Benutzernamen und Passwort für den DB-Zugang. Mein Problem: Wie bekommen Modell.py und Tools.py einen gültigen DB-Konnektor? Möglichst sogar den selben? Folgenden Versuch habe ich gemacht: In Modell.py gibt es eine Klasse DB_Konnektor mit einem Zustand DB_Konnektor.DB und einer Methode DB_Konnektor.Init(Zugangsdaten); letztere erzeugt den DB_Konnektor und speichert ihn in dem Klassenzustand DB_Konnektor.DB Außerdem gibt es in Modell.py die Funktion DB(), die einfach den Zustand DB_Konnektor.DB zurück gibt. In Main.py, Modelle.py und Tools.py kann ich nun aus Modell.py den DB_Konnektor und die Funktion DB() importieren. Und tatsächlich scheint der DB_Konnektor nach Aufruf von DB_Konnektor.Init(Zugangsdaten) sichtbar zu sein. Den Code der Python-Files habe ich unten wiedergegeben. Ist das ein gutes, "pythonisches" Vorgehen? Oder gibt es eine elegantere Möglichkeit? Unschön bleibt aus meiner Sicht, dass der DB-Konnektor nur über eine Funktion zugänglich ist, also DB(). Schöner wäre DB, also eine "Zustand des Moduls" - aber das gibt es wohl nicht? So sieht die Syntax später z.B. so aus: Cur = DB().cursor() DB().commit() Schöner wäre: Cur = DB.Cursor() DB.commit() Wäre es naheliegend, die Klasse DB_Konnektor von den Konnektor-Klassen der implementierten Schnittstellen erben zu lassen? Also etwa: class DB_Konnektor(sqlite3.Connector, psycopg2.extensions.connection) def __init__(Typ, ...): if Typ == 'SQLite': sqlite3.Connector.__init__(...) elif Typ == 'PostgreSQL': psycopg2.extensions.connection.__init__(...) ... Vielen Dank für Hilfe oder Hinweise! Gruß Ulrich Hier mein vorläufiger Code: ====== Modell.py ====== class DB_Konnektor(): DB = "DB Prototyp (unbrauchbar)" def Init(DB_Name): DB_Konnektor.DB = DB_Name def DB(): return DB_Konnektor.DB class Modell(): def DB(self): print('Aus Sicht von Modell.Modell ist DB: {}'.format(DB())) return DB_Konnektor.DB ### Die Klasse Modell ist in Wirklichkeit sehr umfangreich. ### Sie greift auf den DB-Konnektor zurück. ### ### Hier folgen weitere Objekte, die auch auf den DB-Konnektor ### zurückgreifen. ====== Modelle.py ====== from Modell import * ### Hier folgen die Klassen, die Datenbank-Tabellen abbilden. ### Grundlage dafür sind die in Test_Modell ### definierten Objekte. ====== Tools.py ====== from Modelle import * def Tools(): print('Aus Sicht von Tools ist DB: {}'.format(DB())) ### Hier folgen eine Reihe von Objekten, die auf den ### DB-Konnektor zurückgreifen. === Main.py === from Modell import DB from Modelle import * from Tools import * M = Modell() ### Vor dem Aufruf von DB_Konnektor.Init() sieht es so aus: print('Aus Sicht des Hauptprogramms vor Init ist DB: {}'.format(DB())) print('Aus Sicht des Hauptprogramms vor Init ist M.DB: {}'.format(M.DB())) Tools() ### Aufruf von DB_Konnektor.Init(Zugangsdaten): DB_Konnektor.Init("DB brauchbar.") ### Nach dem Aufruf von DB_Konnektor.Init(Zugangsdaten) ### sieht es so aus: print('Aus Sicht des Hauptprogramms nach Init ist DB: {}'.format(DB())) print('Aus Sicht des Hauptprogramms nach Init ist M.DB: {}'.format(M.DB())) Tools() -- Ulrich Goebel Hainallee 40, 44139 Dortmund

Am 10.07.2023 um 23:45 schrieb Ulrich Goebel <ml@fam-goebel.de>:
Ist das ein gutes, "pythonisches" Vorgehen? Oder gibt es eine elegantere Möglichkeit?
Hmm, kennst du das Repository-Pattern schon? Das ist so der übliche Weg, wenn man die Datenhaltung wegabstrahieren möchte: https://www.cosmicpython.com/book/chapter_02_repository.html
Unschön bleibt aus meiner Sicht, dass der DB-Konnektor nur über eine Funktion zugänglich ist, also DB(). Schöner wäre DB, also eine "Zustand des Moduls" - aber das gibt es wohl nicht? So
Klar, das geht auch. Aber Attribute von Modulen sind halt für alle gleich, d.h. wenn man das ändern sollte, ändert man es für alle, die es benutzen. Viele Grüße Jochen

Hallo Ulrich, ich kenne deinen Anwendungsfall nicht, aber möchte eine Sache zu bedenken geben, die ich aus meinen Anfangszeiten mitgenommen habe. Datenbank sind ziemlich cool und so. Auf den ersten Blick erscheinen sie meist als das Mittel der Wahl. Sie an eine Anwendung anzubinden ist aber häufig sehr aufwendig und noch aufwendiger diese Anbindung zu warten. Manchmal ist es sinnvoller vielleicht doch auf eine Datenhaltung ohne Datenbank zurückzugreifen; Textdateien, JSON, CSV, Pickle-Files. Ein bisschen Verwaltungs-Logik muss man dann selbst implementieren, aber langfristig spart es viel Arbeit, weil man die ganze "Last" (Abstraktionsschichten, Code-Wartung, Unittests, ...) die man sich mit einer Datenbank dazu holt wegfällt. Es ist eine Kosten-Nutzen-Rechnung. Schöne Grüße Christian Am 10.07.2023 23:45 schrieb Ulrich Goebel:

On 2023-07-10 21:45, Ulrich Goebel <ml@fam-goebel.de> wrote:
Also einen Methodennamen, der mit einem Großbuchstaben beginnt, finde ich nicht schöner, sondern ziemlich irritierend.
DB.commit()
Oh, Du meinst das? Geht natürlich genauso. Die Variable musst Du dann halt vorher initialisieren und das Behandeln von Verbindungsabbrüchen wird auch komplizierter. Aber wenn Du den Cursor schon hast, hast Du auch eine Verbindung zur Connection: Cur.connection.commit() (Und "cur" würde ich auch mit kleinem c schreiben) hp

Am 10.07.2023 um 23:45 schrieb Ulrich Goebel <ml@fam-goebel.de>:
Ist das ein gutes, "pythonisches" Vorgehen? Oder gibt es eine elegantere Möglichkeit?
Hmm, kennst du das Repository-Pattern schon? Das ist so der übliche Weg, wenn man die Datenhaltung wegabstrahieren möchte: https://www.cosmicpython.com/book/chapter_02_repository.html
Unschön bleibt aus meiner Sicht, dass der DB-Konnektor nur über eine Funktion zugänglich ist, also DB(). Schöner wäre DB, also eine "Zustand des Moduls" - aber das gibt es wohl nicht? So
Klar, das geht auch. Aber Attribute von Modulen sind halt für alle gleich, d.h. wenn man das ändern sollte, ändert man es für alle, die es benutzen. Viele Grüße Jochen

Hallo Ulrich, ich kenne deinen Anwendungsfall nicht, aber möchte eine Sache zu bedenken geben, die ich aus meinen Anfangszeiten mitgenommen habe. Datenbank sind ziemlich cool und so. Auf den ersten Blick erscheinen sie meist als das Mittel der Wahl. Sie an eine Anwendung anzubinden ist aber häufig sehr aufwendig und noch aufwendiger diese Anbindung zu warten. Manchmal ist es sinnvoller vielleicht doch auf eine Datenhaltung ohne Datenbank zurückzugreifen; Textdateien, JSON, CSV, Pickle-Files. Ein bisschen Verwaltungs-Logik muss man dann selbst implementieren, aber langfristig spart es viel Arbeit, weil man die ganze "Last" (Abstraktionsschichten, Code-Wartung, Unittests, ...) die man sich mit einer Datenbank dazu holt wegfällt. Es ist eine Kosten-Nutzen-Rechnung. Schöne Grüße Christian Am 10.07.2023 23:45 schrieb Ulrich Goebel:

On 2023-07-10 21:45, Ulrich Goebel <ml@fam-goebel.de> wrote:
Also einen Methodennamen, der mit einem Großbuchstaben beginnt, finde ich nicht schöner, sondern ziemlich irritierend.
DB.commit()
Oh, Du meinst das? Geht natürlich genauso. Die Variable musst Du dann halt vorher initialisieren und das Behandeln von Verbindungsabbrüchen wird auch komplizierter. Aber wenn Du den Cursor schon hast, hast Du auch eine Verbindung zur Connection: Cur.connection.commit() (Und "cur" würde ich auch mit kleinem c schreiben) hp
participants (4)
-
c.buhtz@posteo.jp
-
jochen@wersdoerfer.de
-
Peter J. Holzer
-
Ulrich Goebel