Datenspeicherung unabhängig machen - Factory?

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
bot
User
Beiträge: 20
Registriert: Montag 22. Mai 2006, 19:47

Montag 22. Mai 2006, 19:52

Hi

Wenn ich ein Programm habe und möchte das meine Daten "unabhängig" gespeichert werden, wie mache ich das am besten unter Python?

sprich der Appl. soll es egal sein, ob z.B. Userdaten

- in eine db geschrieben werden
- auf file ebene ( da auch maybe unabhängig z.b. ini oder xml )
- über http zu einem server verschickt werden ( maybe soap )
- ect.

In C++ würde ich das mit ner Abstract Factory Class machen und nur die Schnittstellen definieren.

z.b.

m_user.Save();

Die Save Fkt ist für alle gleich, nur die implementation total anders.

Kann mir da einer ne gute Seite nennen wo ein tolles bsp für sowas ist?

Wäre echt supi :)
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Montag 22. Mai 2006, 21:14

Und was hintert dich daran, genau das su machen? Du definierst einen Basisklasse, definierst sagen wir mal die Funktionen alle als abstrakt (raise NotImplementedError) damit du ein Interface hast, leitest mehrere Klassen ab, die die Persistenz (RDBMS, OODBMS, pickle, INI, XML) implementieren. Los gehts!
Da brauchts auch nicht viel Code für:

Code: Alles auswählen

class BasePersistance(object):
    def __init__(self):
        raise NotImplementedException('Abstract class')

    def save(self):
        raise NotImplementedException('Abstract class')

class PicklePersistance(BasePersistance):
    def __init__(self):
        # pickle Init-Code hier

    def save(self):
        # speichern-Code hier
My god, it's full of CARs! | Leonidasvoice vs Modvoice
bot
User
Beiträge: 20
Registriert: Montag 22. Mai 2006, 19:47

Montag 22. Mai 2006, 21:21

Danke

Wie sieht es dann aus wenn ich dies per ini verwalten will?

[IRGENDWAS]
wasdenn=ini

m_wassdenn #ini ist hier drin


BasePersistance( m_wasdenn )

das ist doch jetzt nichtdamit getan oder?
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Montag 22. Mai 2006, 21:30

Nein, das machst du dann so:

Code: Alles auswählen

class IniPersistance(BasePersistance):
    def __init__(self):
        filename = 'name.ini'

    def save(self):
        # hier der code der die Einstellungen in die INI-Datei speichert

    def load(self):
        # hier der code der die Einstellungen mittels ConfigParser ausliest
Es gibt praktischerweise den ConfigParser der INI-Dateien parsen kann. Sehr nützlich in diesem Fall.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
bot
User
Beiträge: 20
Registriert: Montag 22. Mai 2006, 19:47

Montag 22. Mai 2006, 22:23

und wo bestimm ich was gemacht wird? da muss es doch eine art "switch" geben, ne? je nachdem was der value der ini ist, muss doch die richtige klasse erstellt werden.

if m = ini:
obj = IniPersistance
elif m = db:
obj = DbPersistance

und dann speichere ich meine werte mit

obj.save()

so ungefähr hab ich mir das vorgestellt

habe noch diese klasse hier gefunden

http://aspn.activestate.com/ASPN/Cookbo ... cipe/86900

in c++ würd ich das so machen

obj = FactoryBuilder("ini")

und das wars.
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

Dienstag 23. Mai 2006, 10:45

Code: Alles auswählen

def FactoryBuilder(id):
  if id == "ini":
    return IniPersistance()
  elif id == "db":
    return DbPersistance()
  else:
    raise ValueError("Unknown id")
Oder auch (ungetestet):

Code: Alles auswählen

def FactoryBuilder(id):
  return globals()[id]
Das ist aber gefährlich.
Zuletzt geändert von Joghurt am Sonntag 28. Mai 2006, 23:27, insgesamt 3-mal geändert.
Mad-Marty
User
Beiträge: 317
Registriert: Mittwoch 18. Januar 2006, 19:46

Mittwoch 24. Mai 2006, 14:53

Am besten über eine AbstractFactory dein object instanzieren.

Als Übergabe könnte ich mir einen pfad zu einer .ini vorstellen.

In der __new__ deiner AbstractFactory nutzt du am besten den ConfigParser um dir eine klasse oder eine registry mit classen zu bauen, entweder mittels __meta__ oder setattr.

Ich bevorzuge setattr. (Klassen sind auch objekte)

Dann braucht dein __new__ deiner AbstractFactory nur noch auszuwählen welche echte Klasse instanziert wird, dies zu tun, und das object mit return zurückgeben.

Oder gibts da bessere wege ?
bot
User
Beiträge: 20
Registriert: Montag 22. Mai 2006, 19:47

Donnerstag 25. Mai 2006, 09:06

Es werde es so machen wie Joghurt Bsp.

Aber mal ne Folgefrage.

Ich habe z.b. jetzt ein konkretes Objekt a ( von class A ) und diese hat 2 Methoden foo(), bar()

Ich habe jetzt in einem x.py file eine function bar() drin.

Was ich jetzt machen will ist, von dem Objekt a erst foo dann bar aufrufen, aber ich will immer erst schauen ob in meiner x.py datei es eine gleichnamige function gibt, wenn ja dann nimm diese.

wie würde ich dies machen?

Code: Alles auswählen

from utils import hasOwnMethod
class a
#... some inits for a

# rufe foo auf

if hasOwnMethod( "x.py", "foo" ):    # 1. parameter file, 2. functionsname
  a.setattr( from x import foo ) # wird das so gemacht?
  a.foo
else:
  a.foo           # hier wird das standard genommen

#rufe jetzt bar auf

if hasOwnMethod( "x.py", "bar" ):    # 1. parameter file, 2. functionsname
  a.setattr( from x import bar ) # hier das das aus x.py genommen
  a.bar
else:
  a.bar     

# wie genau müsste hasOwnMethod implementiert sein?
# getattr ist ja für klassen.

vielen dank im voraus
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Donnerstag 25. Mai 2006, 10:50

Was du suchst ist hasattr:

Code: Alles auswählen

import os
# eine möglichkeit, aber eher unpythonic und daher eher abzuraten
hasattr(os, 'name')

# alternativ, und eher pythonic (EAFP):
try:
    print os.name
except AttributeError:
    print 'os.name gibt es nicht'
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Donnerstag 25. Mai 2006, 11:08

Leonidas hat geschrieben:

Code: Alles auswählen

# eine möglichkeit, aber eher unpythonic und daher eher abzuraten
hasattr(os, 'name')
Hi Leonidas!

Ich habe zwar den Anfang dieses Threads nicht verfolgt, aber warum bezeichnest du "hasattr()" als unpythonic und warum soll man es nicht verwenden? Auf was stützt du deine Aussage?

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Donnerstag 25. Mai 2006, 11:42

gerold hat geschrieben:Ich habe zwar den Anfang dieses Threads nicht verfolgt, aber warum bezeichnest du "hasattr()" als unpythonic und warum soll man es nicht verwenden? Auf was stützt du deine Aussage?
Ich stütze es auf eines meiner Lieblings-Python-Paradigmen, EAFP: Easier to ask for forgiveness than permission.
Python Glossar hat geschrieben:This common Python coding style assumes the existence of valid keys or attributes and catches exceptions if the assumption proves false. This clean and fast style is characterized by the presence of many try and except statements.
Klar, man kann hasattr() verwenden, aber ich denke, dass man mit try-except schneller vorrankommt, wenn man davon ausgeht, dass es diese Attribute gibt, statt erst zu prüfen ob es sie gibt und sie dann erst zu benutzen. Wobei: YMMV :)
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Donnerstag 25. Mai 2006, 12:12

Leonidas hat geschrieben:Ich stütze es auf eines meiner Lieblings-Python-Paradigmen, EAFP: Easier to ask for forgiveness than permission.
Hi Leonidas!

Ich interpretiere das verlinkte Glossary so: Es gibt **EAFP** und es ist ganz normal, wenn man es in in Python verwendet. Das schließt aber keinesfalls **LBYL** aus und stellt auch keine Empfehlung dar. Ich denke, man soll das verwenden, was in der aktuellen Situation an bequesten ist.

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
bot
User
Beiträge: 20
Registriert: Montag 22. Mai 2006, 19:47

Donnerstag 25. Mai 2006, 12:39

versteh ich nicht ganz. warum os.name? wo gebe ich da das file an oder die function?

dann müsste also

a.setattr( from x import foo )

gehen. werde es an meinem platz mal ausprobieren.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Donnerstag 25. Mai 2006, 19:23

gerold hat geschrieben:Ich interpretiere das verlinkte Glossary so: Es gibt **EAFP** und es ist ganz normal, wenn man es in in Python verwendet. Das schließt aber keinesfalls **LBYL** aus und stellt auch keine Empfehlung dar. Ich denke, man soll das verwenden, was in der aktuellen Situation an bequesten ist.
Man kann beides verwenden, klar, jedoch denke ich schon, dass man sich eher an EAFP halten sollte. Wieso? Na, es geht ja nicht nur ums prüfen von Atributen, sondern um die generelle Einstelltung, dass alles funktioniert. Wenn es nicht funktioniert, dann kann man ja immer noch hinterher versuchen, es wieder ins Lot zu bringen. Man kann nicht alle möglichen Fehlerquellen explizit vorher prüfen.
bot hat geschrieben:versteh ich nicht ganz. warum os.name? wo gebe ich da das file an oder die function?
Das war nur ein beispiel um hasattr() und AttributeError zu demonstrieren.
bot hat geschrieben:dann müsste also

a.setattr( from x import foo )

gehen.
Nein, weil das import-Statement keinen Rückgabewert hat und somit gibts einen SyntaxError.

Ungetestet:

Code: Alles auswählen

import x
try:
    x.foo()
    x.bar()
except AttributeError:
    a = A()
    a.foo()
    a.bar()
My god, it's full of CARs! | Leonidasvoice vs Modvoice
bot
User
Beiträge: 20
Registriert: Montag 22. Mai 2006, 19:47

Freitag 26. Mai 2006, 14:54

gut, dann werde ich das mit dem try so versuchen, nur was ungeschickt ist, wenn ich 10 fkt habe und es gäbe

1,2,3,5

dann würde er ja bei 4 eine exception werfen und die 5te "überschriebene" fkt nicht verwenden. hmm dann schreibe ich eine extra fkt die schleifenartig das durchgeht
Antworten