adressbuch in oop

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
archer
User
Beiträge: 8
Registriert: Samstag 8. August 2009, 21:39

Hallo und gute abend,

Ich hab vor kurzem "A Byte of Python" gelesen, und dort wird empfohlen ein adressbuch zu schreiben.
Ich hab es jetzt mal rein prozentual geschrieben, es funktioniert soweit auch ganz gut ich kann: kontake hinzufügen, löschen und suchen.
Und ich wollte fragen ob es Sinn macht das ganze jetzt in oop zu schreiben.
Das Problem ist das ich dieses ganze Konzept dahinter irgendwie nicht richtig verstehe.
Kann man auch ohne Klassen GUIs wie z.B. mit PyQt schreiben oder wird das dann zu kompliziert?

hier mal der code:

Code: Alles auswählen

#!/usr/bin/python3

import pickle

def eingabe():
	try:
		f = open('kontakte.data', 'rb')
		kontakt = pickle.load(f)
	except:
		kontakt = {}
	name = input('Geben Sie einen Namen ein: ')
	nummer = input('Geben Sie eine Telefonnummer ein: ')
	email = input('Geben Sie eine Email-Adresse ein: ')
	daten = (nummer, email)
	kontakt[name] = daten
	f = open('kontakte.data', 'wb')
	pickle.dump(kontakt, f)
	f.close()

def ausgabe():
	try:
		f = open('kontakte.data', 'rb')
		gespDict = pickle.load(f)
	except:
		print('Kein Kontakt vorhanden')
	else:
		print('')
		print('NAME         NUMMER            EMAIL')
		print('----------------------------------------')
		for name, daten in gespDict.items():
			print(name, daten[0], daten[1])

def suche():
	try:
		f = open('kontakte.data', 'rb')
		gespDict = pickle.load(f)
	except:
		print('Kein Kontakt vorhanden')
	else:
		name = input('Geben sie den zu suchenden Namen ein: ')
		if name in gespDict:
			print('Kontakt gefunden!')
			print('--------------------------')
			print('Nummer:', gespDict[name][0])
			print('Email:', gespDict[name][1])
		else:
			print('Kontakt nicht gefunden!')

def loeschen():
	try:
		f = open('kontakte.data', 'rb')
		gespDict = pickle.load(f)
	except:
		print('Kein Kontakt vorhanden')
	else:
		name = input('Geben sie den zu loeschenden Namen ein: ')
		if name in gespDict:
			print('Kontakt gelöscht!')
			del gespDict[name]
			f = open('kontakte.data', 'wb')
			pickle.dump(gespDict, f)
			f.close()
		else:
			print('Kontakt nicht gefunden!')


while True:
	print('''
******MENÜ******
eingabe = e
ausgabe = a
suche = s
loeschen = l
beenden = q''')
	menu = input(': ')
	if menu == 'e':
		eingabe()
	elif menu == 'a':
		ausgabe()
	elif menu == 's':
		suche()
	elif menu == 'l':
		loeschen()
	elif menu == 'q':
		break
	else:
		print('Ungueltige Eingabe!')
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

Ja es macht sicherlich sinn.
oop ist am anfang nicht ganz leicht zu verstehen, aber es kommt mir der zeit.
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
archer
User
Beiträge: 8
Registriert: Samstag 8. August 2009, 21:39

na dann werd ichs mal probieren,
weißt du vielleicht wo oop am besten für Anfänger
erklärt wird, in "A Byte of Python" ist die Erlärung etwas knapp?
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Erstmal den Code optimieren bevor du zum nächsten übergehst ;-)

(Nie alle Exceptions mit `except` abfangen und die untersten 12 Zeilen löst man in Python mit dicts (es gibt halt kein switch-Statements in Python, if-Konstrukte sind aber auch nicht so schön)
archer
User
Beiträge: 8
Registriert: Samstag 8. August 2009, 21:39

ich hab jetzt mal bei jeder exception: except IOError geschrieben
aber ich krieg das mit dem dict nicht hin das er nur die funktion ausführt die ich angebe

Code: Alles auswählen

    menu = input(': ')
    optionen = {
        menu == 'e': eingabe(),
        menu == 'a': ausgabe(),
        menu == 's': suche(),
        menu == 'l': loeschen()
        }
BlackJack

@archer: Du führst da ja auch *jede* der Funktionen aus. Und das ist eine Abbildung von Wahrheitswerten auf Funktionsergebnisse und nicht von Buchstaben auf Funktionen.

Code: Alles auswählen

    optionen = {
        'e': eingabe,
        'a': ausgabe,
        's': suche,
        'l': loeschen
    }
    
    menu = raw_input(': ')
    optionen[menu]()
Das ist so natürlich ohne jegliche Fehlerbehandlung was die Benutzereingabe betrifft.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Mit einem Dict, und keinem Dict-Switch-Hybrid-Mutant-Dingens.

Code: Alles auswählen

choice = raw_input(': ')
options = {
    'i': input,
    'o': output,
    's': search,
    'd': delete}
action = options[choice]
action()
Edit: Och menno .. nich schon wieder :roll:
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

archer hat geschrieben:Ich hab es jetzt mal rein prozentual geschrieben
Wie niedlich :D Es heißt übrigens prozedural.
Das Leben ist wie ein Tennisball.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

So könnte man ein Adressbuch-Objekt und ein Adress-Objekt (welches nur eine E-Mail hat, keine Telefonnummer) modellieren:

Code: Alles auswählen

import pickle

class Address(object):
    def __init__(self, name, email):
        self.name, self.email = name, email
    
    def __str__(self):
        return u"%s <%s>" % (self.name, self.email)

class AddressBook(object):
    def __init__(self):
        self.addresses = {}
    
    @classmethod
    def load(cls, name):
        with open(name, "rb") as f: return pickle.load(f)

    def save(self, name):
        with open(name, "wb") as f: pickle.dump(self, f)
    
    def add_address(self, name, email):
        self.addresses[name] = Address(name, email)
    
    def remove_address(self, name):
        del self.addresses[name]
    
    def get_address(self, name):
        return self.addresses.get(name)

    def __str__(self):
        return "\n".join(str(address) 
            for address in sorted(self.addresses.values(), key=lambda a: a.name))
Stefan
archer
User
Beiträge: 8
Registriert: Samstag 8. August 2009, 21:39

@BlackJack, @cofi: Danke, ich habs mal so umgeschrieben
@sma: Danke für die Anregung ich werd mir mal oop anschauen und dann schreib ichs um und werds hier posten
lunar

@sma: Man hätte für "Address" auch "__hash__()" und "__eq__()" überladen und "AddressBook" anschließend von "set" ableiten können.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Ich habe verinnerlicht, von Collection-Klassen niemals zu erben. Vererbung ist die stärkste Abhängigkeit, die zwei Klassen haben können. Solche Abhängigkeiten sind schlecht. Mir gefällt es besser, statt "ein Adressbuch IST eine Menge" lieber "ein Adressbuch verhält sich WIE eine Menge" zu modellieren.

Stefan
lunar

Python erzwingt keine statischen Typen, und manuelle Typtests sind doch eher unüblich. Der Unterschied zwischen "ist eine Menge" und "verhält sich wie eine Menge" sollte in einem gut programmierten Python-Programm eigentlich keine Rolle spielen. Insofern ist die Abhängigkeit vielleicht stark, aber doch alles andere als unlösbar, zumal man mithilfe der ABCs ja auch relativ einfach eigene Mengen-Klassen implementieren kann.

Aus dem Verzicht auf das Vererben von Container-Klassen ein unerschütterliches Dogma zu machen, halte ich daher für ein bisschen übertrieben. Ein Adressbuch ist ein Container, also liegt es nahe, existierende Container dafür zu benutzen, um Arbeit zu sparen. Letztlich macht dein Code ja nichts anderes, als die Mengen-Schnittstelle neu zu erfinden, und das Kind lediglich anders zu nennen.
BlackJack

@lunar: Das Problem was ich mit dem erben von den eingebauten Containern habe, ist das man in aller Regel Sachen miterbt, die auf dem neuen Container in der Form keinen Sinn machen, oder die nicht wie erwartet funktionieren. Bei `set()` mag das ja vielleicht noch gehen, aber bei `list()` zum Beispiel ist viel dabei was ich einfach nicht haben will, und deswegen auch nicht überschreiben müssen möchte.
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

ixh würd dir noch empfehlen cPickle zu verwenden, es ist einfach schneller (steht auch in a byte of Python drin) und um dicts zu verwenden mit
(z.B.)
* name
* adresse
* e-mail

machs so:

dict1 = {
hans : ('Wohnort', 'e-mail')
wurscht : ('Wohnort2', 'e-mail2')
}

das format verwende ich auch in meinem Adressbuch (inspiriert durch a byte of Python) mit GUI (wxpython)

mfg
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

``pickle`` nutzt IMO automatisch ``cPickle``, wenn das verfuegbar ist, allerdings gings hier noch gar nicht um Persistenz. Waere das nicht der Fall sollte man das so machen:

Code: Alles auswählen

try:
    import cPickle as pickle
except ImportError:
    import pickle

Dein Ansatz hat ein paar Probleme: 
 * Es sind keine gleichen Namen moeglich (Bei sma auch nicht, aber das ist jetzt egal)
 * Man hat ein Tupel, das man nur ueber Indizes ansprechen kann und dass ohne die nutzlos ist.

Da ist smas Ansatz weit besser, wenn man keine ``Address`` Klasse nehmen will, dann doch mindestens ein ``named_tuple``
Antworten