Adressbuch

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Antworten
KMachine
User
Beiträge: 5
Registriert: Donnerstag 29. Januar 2009, 20:47
Kontaktdaten:

Hallo Forum,

Ich habe heute das Buch "A Byte Of Python" zu Ende gelesen und versuche mich jetzt an dem Adressbuch-Aufgabe, welches am Ende des Buches vorgeschlagen wird.
Ich habe begonnen das Programm zu schreiben, doch tauchen einige Fragen auf, ohne deren Antwort ich nicht weiterkomme.
(IMHO fand ich dieses Buch schon viel logischer aufgebaut und mehr verständlich als das Openbook über Python, und empfand es als sehr gute Ergänzung zu diesem.)

Ich habe schon einen Thread mit ähnlichem Titel und Inhalt hier im Forum gelesen, doch fand ich den Programm-Code unnötig "sophisticated".

Lange Rede, kurzer Sinn. Hier ist mein Programm in der Version 1.00 :lol: :

Code: Alles auswählen

#!/usr/bin/env python

import cPickle

'''Adressbuch-Skript Version: 1.00

Kurzbeschreibung:
Kommandozeilenbasiertes Adressbuch-Programm, mit dem man seine \
Kontakte und die dazugehoerigen Informationen wie Email-Adresse, Telefonnummer\
 hinzufuegen, loeschen oder durchsuchen kann.
Die Daten werden fuer den spaeteren Zugriff gespeichert.

Info fuer mich:

1. Adressbuch das Informationen ueber die Kontakte enthaelt wie:
-Vorname
-Nachname
-Alter
-ICQ-Nummer
-Email

2. Die Daten werden in einem Dictionary gespeichert, welches \
schliesslich in einer externen Datei gespeichert wird.

3. Es soll eine visuelle Rueckmeldung ueber Erfolg oder Failure geben'''

class Adressbuch:
	global
	d = {}
	def __init__(self, vorname, nachname, alter, icq, email):
		self.vorname = vorname
		self.nachname = nachname
		self.alter = alter
		self.icq = icq
		self.email = email
		print 'Kontakt %s %s gespeichert' % (self.vorname, \
		self.nachname)
		
	def info(self):
		print "'%s %s', Alter: '%d' . \nICQ-Nummer: %d \nE-Mail: %s" \
 % (self.vorname, self.nachname, self.alter, self.icq, self.email)
			
print 'Gib die Kontaktinformationen ein:\n'
try:
	vorname = raw_input('Vorname:')
	nachname = raw_input('Nachname:')
	alter = int(raw_input('Alter:'))
	icq = int(raw_input('ICQ:'))
	email =raw_input('Email:')

except:
	print '\nEs ist ein Fehler aufgetreten\n'
	
else:
	print '\nAlles hat geklappt!'

finally:
	p = Adressbuch(vorname, nachname, alter, icq, email)
	p.info()

f = file("Adressbuch.txt", "a")
cPickle.dump(p, f)
f.close

Meine Frage:
Ich möchte, dass die Attribute der Klasse (korrigiert mich wenn ich Quark erzähle)

Code: Alles auswählen

p = Adressbuch(vorname, nachname, alter, icq, email)
in das globale Dictionary d eingefügt werden. Ich weiß nicht so Recht wie ich das am Geschicktesten anstelle. Über Referenzen oder Tipps wäre ich sehr dankbar!

Anmerkungen
1.)Ich benutze hier bewusst eine Klasse, wobei ich glaube dass es prozedual für den jetzigen Zeitpunkt mehr "python-like" wäre (wobei ich mir bei der aktuellen Phase des Programms nicht sicher bin ob es wirklich einen Unterschied macht) und ich hinterher noch andere Funktionen wie Gruppen, etc. hinzufügen möchte.

2.)

Code: Alles auswählen

cPickle.dump(p, f)
Der Inhalt der Datei der Variablen f ist natürlich völliger Käse.

3.) Ich habe diesmal versucht mehr PEP 8 konform zu schreiben. Ich hoffe das ist mir diesmal mehr gelungen wie in meinem anderen Programm.

Weiterhin freue ich mich über Antwort und Verbesserungsvorschläge!

Grüße,
KMachine

[/code]
Zuletzt geändert von KMachine am Mittwoch 11. Februar 2009, 02:08, insgesamt 2-mal geändert.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Der Name Adressbuch für die Klasse passt nicht, Kontakt würde es eher Treffen. Dein Adressbuch könnte einfach eine Liste mit Kontakten sein. Das es "global" gibt vergisst du besser gleich wieder.

`print`s innerhalb von Klassen sind i.d.R. eine schlechte Idee, so auch hier. Die Kontakt gespeichert Meldung taucht nämlich irgendwann auf aber höchstwahrscheinlich nie wenn den Kontakt gespeichert wird, so in einer Datei auf der Festplatte ;)

`info` solltest du weglassen, überschreib statt dessen __str__ und gibt einen passenden String zurück oder lass es ganz weg. Perfektion ist nicht erreicht wenn man nichts mehr hinzufügen kann und du nutzt es sowieso nicht.

Ein reines try..except ist sehr böse, da du damit Fehler abfängst von denen es erwünscht ist dass sie nach oben weiter gereicht werden, um an entsprechender Stelle darauf zu reagieren oder weil ein Fehler auftritt der nie auftreten sollte. Gerade wenn du einen Fehler abfängst der unerwartet auftritt wirst du dich früher oder später gewaltige Probleme beim debuggen bekommen.

Zum öffnen von Dateien sollte man nicht file direkt verwenden, dafür gibt es open. Desweiteren sollte man Dateien so öffnen:

Code: Alles auswählen

with open('datei') as f:
    # mach was mit f
Dann wird garantiert dass die Datei auch wieder geschlossen wird, sollte eine Exception im eingerückten Block auftreten.

Ansonsten wäre es sinnvoll einige Teile des Codes auf Modulebene in Funktionen auszulagern.
KMachine
User
Beiträge: 5
Registriert: Donnerstag 29. Januar 2009, 20:47
Kontaktdaten:

Hallo DasIch,

Deinen Ratschlag berücksichtigend, habe ich es komplett neu geschrieben.

Hier der Code:

Code: Alles auswählen

#!/usr/bin/env python
import cPickle
from sys import exit

print 'Was moechtest Du machen?'
while True:
	print '1 - Neuen Kontakt erstellen'
	print '2 - Adressbuch lesen'
	eingabe = int(raw_input("\nBitte waehle jetzt: "))
	if eingabe == 1:
		break
		print
	if eingabe == 2:
		print 'Dies ist noch nicht moeglich\nDas Programm wird jetz beendet.'
		exit(-1)
		
print '\nGib die Kontaktinformationen ein:\n\nInfo:\nAlter: Mindestens\
5 Jahre bis 99 Jahre erlaubt\nICQ: Bitte beachte die Laenge deiner \
ICQ-Nummer, 9 Zahlen erlaubt.\n'

while True:
	vorname = raw_input('Vorname:')
	nachname = raw_input('Nachname:')
	alter = int(raw_input('Alter:'))
	if alter < 5 or alter > 99:
		print 'Ungueltiges Alter'
		continue
	icq = raw_input('ICQ:')
	if len(icq) != 9:
		print 'Ueberpruefe deine Angabe nochmals'
		continue
	email =raw_input('Email:')
	break

d = {"Vorname": vorname, "Nachname": nachname, "Alter": alter, "ICQ": \
icq, "E-Mail": email}

f = open("Adressbuch.txt", "w")
for k, v in d.iteritems():
	f.write(k.join(":") + v + "\n")
f.close()

r = open("Adressbuch.txt")
for line in r:
	print line
r.close()
Leider klappt diese Stelle nicht:

Code: Alles auswählen

f = open("Adressbuch.txt", "w")
for k, v in d.iteritems():
	f.write(k.join(":"), v)
f.close()
Python will nur ein Argument, aber ich habe zwei angegeben. Gibt es auch einen anderen Weg?

Wenn diese Basis klappt, dann werd ich das Programm beliebig erweitern.

Danke für das Feedback DasIch. An einiges fände ich es sinnvoll Funktionen einzufügen. Z.B. fände ich es sinnvoll statt den beiden while-Blöcken, Funktionen zu definieren. Findet ihr das sinnvoll?

Würde mich über Vorschläge und Antwort freuen!

Grüße
KMachine
Benutzeravatar
gkuhl
User
Beiträge: 600
Registriert: Dienstag 25. November 2008, 18:03
Wohnort: Hong Kong

@KMachine: Die Codezeile 9 deines ersten Posts ist etwas zu lang um dieses Thread noch geniessen zu koennen...
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Du könntest das dict einfach pickeln.

Wenn du Dicts, Listen, Tuple o.ä. hast mit sovielen Einträgen dass sie nicht in eine Zeile passen würde ich pro Element eine Zeile nutzen. Bei dicts macht man dass dann i.d.R. so:

Code: Alles auswählen

d = {
    'Vorname': vorname,
    'Nachname': nachname,
    'Alter': alter,
    'ICQ': icq,
    'E-Mail': email,
    }
Das sieht besser aus und lässt sich schneller lesen, vorallem wenn dass noch komplexer wird. Außerdem kann man so noch Kommentare hinzuschreiben oder Elemente auskommentieren.
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

Warum machst du nicht einfach (wie weiter oben auch schon gesagt) eine Klasse Person und eine Liste, die die Personen-Objekte enthält.
Dann musst du einfach nur die Liste pickeln.

Edit: Und ja, es ist sinnvoll, Funktionen statt den While Schleifen zu schreiben, dann kannst du diese auch mehrmal aufrufen (was du ja später sicher auch willst, wenn ich mir dein Menü anschaue).

Edit2: Editier mal bitte deinen ersten Beitrag und lösch Zeile 9 aus deinem Code, damit der Thread wieder ne normale Breite hat!
KMachine
User
Beiträge: 5
Registriert: Donnerstag 29. Januar 2009, 20:47
Kontaktdaten:

Hallo Forum,

Nach kürzerer Auszeit hab ich mich jetzt wieder intensiv dem Kontaktbuch gewidmet. Ich habe es nochmal komplett umgeschrieben und bin viel zufriedener mit der Funktionalität wie vorher.

Hier eine Vorschau:

Code: Alles auswählen

import 
def kontakt_neu():

	while True:
		kontakt_vorname = raw_input("Gib den Vornamen an: ")
		if kontakt_vorname == 0:
			print "Bitte Vorname angeben!"
			continue

		kontakt_nachname = raw_input("Gib den Nachnamen an: ")
		if kontakt_nachname == 0:
			print "Bitte Nachname angeben!"
			continue

		kontakt_alter = raw_input("Gib das Alter an: ")
		if len(kontakt_alter) == 0:
			print "Bitte Alter angeben!"
			continue

		elif len(kontakt_alter) > 99:
			print "Kontakt zu alt!"
			continue

		kontakt_icq = raw_input("Gib die ICQ-Nummer an: ")
		if len(kontakt_icq) != 9 and len(kontakt_icq) > 1:
			print "9 Ziffern oder '0'!"
			continue
		else:
			kontakt_icq = "Keine Angabe"

		kontakt_email = raw_input("Gib die Email-Adresse an. ")
		break

	global	kontaktliste_kontakt_

	kontaktliste_kontakt_ = {"Vorname":kontakt_vorname,
				"Nachname":kontakt_nachname,
	 		        "Alter":kontakt_alter,
			 	"ICQ":kontakt_icq,
				"E-Mail":kontakt_email
				}

def kontakt_speichere():
	try:
		f = open("Adressbuch.txt", "a")
		for engl in kontaktliste_kontakt_:
			f.write(engl.ljust(12) + ":"\
			 + kontaktliste_kontakt_[engl] + "\n")
			 f.close
	except:
		print "Unbekannter Fehler aufgetreten beim Speichern"
	
	else:		 
		print "Änderungen erfolgreich vorgenommen!"

def kontakt_lade():
	pass
	
kontakt_neu()
kontakt_speichere()

Was ich in (naher) Zukunft hinzufügen möchte bzw. werde:
  • Menüauswahl
  • Kontaktbuch-Ansicht:
Da fällt mir leider nichts passendes ein. Denn mit zunehmenden Kontakten, reicht es nicht wenn ich einfach die ganze Datei wiedergebe. Das ist zu unübersichtlich.
Was könnte ich machen, damit ich einen Kontakt einzeln, mit seinen Informationen aufrufen kann? Hat jemand eine Idee oder Vorschläge für mich?

Weiterhin freue ich mich über Feedback
zero-one
User
Beiträge: 58
Registriert: Dienstag 20. Mai 2008, 20:52

hmm evl. sqlite als db benutzen ... das is wohl einfacher als alles selbst in ner flatfile zu speichern...
BlackJack

@KMaschine: Du vergleichst an zwei Stellen Zeichenketten mit Zahlen, das ist *immer* `False`.

Ich wüsste nicht warum ein Adressbuch verbieten sollte Kontakte zu haben, die "zu alt" sind, aber der Test, den Du da machst, ist doch sehr unsinnig. Soooo alte Kontakte gibt's wirklich nicht. Ich kenne jedenfalls niemanden von vor dem Urknall. ;-)

Lass das ``global`` weg. Werte sollten Funktionen als Rückgabewerte verlassen, nicht durch neubinden von globalen Namen.

Umgekehrt sollte man Werte als Argumente in Funktionen hineingeben, statt auf globale Namen zuzugreifen.

Dann kann man die letzten beiden Zeilen auch in eine Hauptfunktion stecken.
glaslos
User
Beiträge: 23
Registriert: Donnerstag 12. Februar 2009, 18:55
Kontaktdaten:

Wenn mich nicht alles täuscht, sind ICQ Nummern aktuell im Bereich 5 <= Nummer <= 9, wobei nach oben quasi keine Schranke besteht (fortlaufende Nummerierung).
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Kann ich als Inhaber einer 8-stelligen Nummer nur bestätigen. Sinnvoller wäre es zu prüfen, ob das wirklich eine Nummer ist die da eingegeben wurde.

Ich wäre bei solchen Prüfungen sowieso sehr vorsichtig. Lieber eine Prüfung zu wenig als eine gültige Eingabe durch unsinnige Prüfungen abzulehnen. Ich wage einfach mal zu behaupten, dass z.B. > 95% der Prüfungen, ob eine Mail-Adresse gültig ist, genau wie z.B. auch in diesem Forum fehlerhaft sind.
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

Nimm entweder mit sqlite3, csv oder das pickle Modul für deine Datenspeicherung.
Oder alternativ noch xml.

Deine ICQ-Numme Abfrage ist nichts. Und man darf auch nicht abfragen, ob der Input nur aus Ziffern besteht. "123-456-789" ist z.B. ein typisches Format für ICQ-Nummern.

Außerdem nimm keine globale Variable.
Warum gibts du das Personen-dict nicht einfach mit ``return'' zurück und übergibst es dann der Speicherfunktion.
Alternativ kannst du auch so eine Liste mit mehreren Personen führen.

Eine bessere Lösung statt dem Personen-dict wäre natürlich noch eine Klasse Person...

Code: Alles auswählen

class Person(object):
  def __init__(self):
    self.vorname = ""
    self.nachname = ""
# usw.
  def kontak_neu(self):
# hier kannst deine funktion so eig. übernehmen, nur die variablen musst halt anpassen

Antworten