Seite 1 von 1

adressbuch in oop

Verfasst: Samstag 8. August 2009, 22:17
von archer
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!')

Verfasst: Samstag 8. August 2009, 22:23
von jbs
Ja es macht sicherlich sinn.
oop ist am anfang nicht ganz leicht zu verstehen, aber es kommt mir der zeit.

Verfasst: Samstag 8. August 2009, 22:31
von archer
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?

Verfasst: Samstag 8. August 2009, 22:47
von Dauerbaustelle
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)

Verfasst: Sonntag 9. August 2009, 01:06
von archer
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()
        }

Verfasst: Sonntag 9. August 2009, 01:55
von 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.

Verfasst: Sonntag 9. August 2009, 01:57
von cofi
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:

Re: adressbuch in oop

Verfasst: Sonntag 9. August 2009, 09:35
von EyDu
archer hat geschrieben:Ich hab es jetzt mal rein prozentual geschrieben
Wie niedlich :D Es heißt übrigens prozedural.

Verfasst: Sonntag 9. August 2009, 09:35
von sma
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

Verfasst: Sonntag 9. August 2009, 10:23
von archer
@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

Verfasst: Sonntag 9. August 2009, 19:12
von lunar
@sma: Man hätte für "Address" auch "__hash__()" und "__eq__()" überladen und "AddressBook" anschließend von "set" ableiten können.

Verfasst: Montag 10. August 2009, 09:55
von sma
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

Verfasst: Montag 10. August 2009, 17:05
von 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.

Verfasst: Montag 10. August 2009, 18:28
von 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.

Verfasst: Dienstag 11. August 2009, 09:36
von Dav1d
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

Verfasst: Dienstag 11. August 2009, 10:12
von cofi
``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``