Übungsprojekt meinAdressbuch

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
BlackJack

@ltownatze: Da könnte man mit Defaultargumenten arbeiten.

Code: Alles auswählen

def show_entry(ab, name=None):
        if name is not None:
            print name, ':', ab.get(name, 'not found, try `meinAdressbuch show | grep -i <NAME>`')
        else:
            pass # Irgendwas anderes machen.
ltownatze
User
Beiträge: 28
Registriert: Donnerstag 8. April 2010, 16:02

Nicht ganz ohne Stolz präsentiere ich eine komplett überarbeitete Version von meinAdressbuch

Wie immer freue ich mich auf kontruktive Kritik.

Edit: Ich spiele mit dem Gedanken Docstrings einzubauen.. haltet ihr das bei einem so kleinen Script/Modul/Programm[?] für Sinnvoll? Welchen Mehrwert hätte das für den Anwender/Programmierer?
BlackJack

@ltownatze: Ich sehe nicht so ganz den Mehrwert das in dieser Form in eine Klasse zu stecken. Ausser einmal ein Exemplar zu erzeugen, dass dann die Kommandozeilenargumente auswertet, kann man damit ja nicht viel machen.

Die Klasse vermischt zuviel. Die Benutzerinteraktion ist da mit drin, und man kann auch kein Adressbuch erzeugen, ohne das versucht wird etwas aus einer Datei zu laden.
ltownatze
User
Beiträge: 28
Registriert: Donnerstag 8. April 2010, 16:02

BlackJack hat geschrieben:Ich sehe nicht so ganz den Mehrwert das in dieser Form in eine Klasse zu stecken.
Das schien mir die beste möglichkeit zu sein 'global' zu vermeiden ohne 'addressbook_filename' an jede Funktion übergeben zu müssen.
Meinen Recherchen und Experimenten zu Folge ist die Verwendung von 'self' nur innerhalb einer Klasse möglich.
Die möglichkeit über 'self' auf Referenzen aus dem Namensraum von 'MeinAdressbuch' zuzugreifen hat auserdem den positiven Nebeneffekt das ich problemlos auf 'parser.get_usage()' zugreifen kann.

Glaubst du ich sollte von der Klassen-Idee abstand nehmen?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

ltownatze hat geschrieben: Glaubst du ich sollte von der Klassen-Idee abstand nehmen?
Ja! Zumindest von der, wie Du es jetzt machst.

Im Grunde wrappst Du nur Dictionary-Zugriffe und baust Speicher- und Lade-Mechanismen direkt in die Klasse ein. Du kannst doch genauso gut Funktionen schreiben, die ein Adressbuch-Dictionary ausgeben, sortieren usw. Das Laden und Speichern würde ich auch eher aus der Klasse rausziehen. Ist doch toll eine Funktion zu haben, die solch eine Klasse anlegen kann.

Prinzipiell würde ich erst einmal alles ohne Klassen versuchen. Solltest Du auf die Idee kommen, verschachtelte Datenstrukturen einzubauen, oder eine schönere Sortiermethode anzugehen, kann man später immer noch eine Art "Adresse"-Klasse bauen und die Objekte in einer Liste oder einem Dictionary halten.

Das Argument mit dem global habe ich nicht ganz verstanden. Den Dateinamen brauchst Du doch nur zum Laden und Speichern. Da müßtest Du ihn also an zwei Funktionen übergeben - imho nicht aufwendig ;-) Aber dennoch braucht es da keine Klasse, um ein global zu vermeiden.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
ltownatze
User
Beiträge: 28
Registriert: Donnerstag 8. April 2010, 16:02

Mal ne kleine Zwischenfrage:
Ich konnte in der Python-Dokumentation nichts in der Richtung finden und langsam glaube ich das es da auch nichts zu finden gibt bevor ich also weiter suche bis ich alt und grau bin hier meine Frage:

Mal angenommen ich habe 2 Funktionen: 'main()' und 'open_addressbook()':

Code: Alles auswählen

def main():
    [...]
    open_addressbook()
    [...]

def open_addressbook():
    addressbook_filename = 'einschönerdateiname'
und ich möchte die Variable 'addressbook_filename', nach dem Aufruf von open_addressbook(), in main() weiterverwenden.
Wie könnte ich hier vorgehen? Ist sowas überhaupt möglich?
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

ltownatze hat geschrieben:Ist sowas überhaupt möglich?
Nein, gluecklicherweise geht das nicht. Du suchst Rueckgabewerte.
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

cofi hat geschrieben:
ltownatze hat geschrieben:Ist sowas überhaupt möglich?
Nein, gluecklicherweise geht das nicht. Du suchst Rueckgabewerte.
Also mit Rückgabewerten lautet die Antwort eigentlich schon "Ja" ;)

Code: Alles auswählen

def main():
    [...]
    addressbook_filename = open_addressbook()
    [...]

def open_addressbook():
    addressbook_filename = 'einschönerdateiname'
    [...]
    return addressbook_filename
„Lieber von den Richtigen kritisiert als von den Falschen gelobt werden.“
Gerhard Kocher

http://ms4py.org/
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

ms4py hat geschrieben: Also mit Rückgabewerten lautet die Antwort eigentlich schon "Ja" ;)
Bezogen auf "die Variable" im Ursprungspost aber dann eben doch "nein" ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
ltownatze
User
Beiträge: 28
Registriert: Donnerstag 8. April 2010, 16:02

Mir fällt es noch etwas schwer mich präzise Auszudrücken.. aber ich wurde irgendwie Verstanden ;)

Mit 'return' hatte ich auch schon rumgespielt, bin aber nicht auf diese Idee gekommen:

Code: Alles auswählen

addressbook_filename = open_addressbook()
Außerdem hat mich die Python-Doku hier etwas verwirrt.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

ltownatze hat geschrieben: Außerdem hat mich die Python-Doku hier etwas verwirrt.
Respekt für das Lesen der Doku, aber Du solltest erst einmal hier gucken ;-) Das sind wirklich absolute Baics.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

ltownatze hat geschrieben:Mit 'return' hatte ich auch schon rumgespielt, bin aber nicht auf diese Idee gekommen:

Code: Alles auswählen

addressbook_filename = open_addressbook()
Um das klarzustellen: `addressbook_filename` ist NICHT dieselbe Variable, wie in der Funktion, sondern enthaelt den Rueckgabewert von `open_addressbook`, d.h. du kannst sie a) aendern, ohne den Wert in der Funktion zu aendern und b) aendert sich der Wert in der Funktion, dann aendert sich nicht der Wert dieser Variablen (es sei denn, du weisst ihr wieder den Rueckgabewert der Funktion zu).
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Was mir hier gerade noch auffällt: Wieso definiert man denn einen Dateinamen innerhalb einer Funktion? Irgend wie kein guter Stil...

Vielleicht noch mal ein simpleres Beispiel, um klar zu stellen, dass Namen jeweils in ihrem Scope eindeutig sind:

Code: Alles auswählen

In [1]: def foo():
   ...:     a = "test"
   ...:     return a
   ...:

In [2]: a = 3

In [3]: b = foo()

In [4]: print a, b
------> print(a, b)
(3, 'test')
Das 'a' auf Modulebene verweist auch nach dem Aufruf von foo() weiterhin auf 3. Dafür wird der Rückgabewert von foo() an den Namen 'b' gebunden.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
ltownatze
User
Beiträge: 28
Registriert: Donnerstag 8. April 2010, 16:02

Danke für die ausführlichen und anschaulichen Erklärungen, ich habs jetzt endlich begriffen. ;)
Wieso definiert man denn einen Dateinamen innerhalb einer Funktion? Irgend wie kein guter Stil...
Eigentlich ging es mir nicht um den Dateinamen sondern um ein Dictionary das aus einer Datei ausgelesen wird und dem/der Namen/Variable/Referenz (k.A. was jetzt der korrekte Begriff ist) 'addressbook' zugeordnet wird. In der Praxis sieht das so aus:

Code: Alles auswählen

def main():
    [...]
    addressbook = open_addressbook(addressbook_filename)
    [...]
def open_addressbook(addressbook_filename):
    try:
        fp = open(addressbook_filename, 'r')
        addressbook = json.load(fp)
        fp.close()
    except IOError:
        addressbook = {}
    return addressbook
Ist es in diesem Fall guter Stil?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Datein würde ich immer mit with öffnen:

Code: Alles auswählen

with open(filename, "r") as infile:
    addressbook = json.load(infile)
Damit sparst Du Dir das close() und bist auch sicher, dass die datei auch bei einer Exception geschlossen wird (wozu Du sonst ein finally benötigen würdest!)

Sieht doch so ganz gut aus :-)

Einzig die Rückgabe eines leeren Dicts bei einem Fehler könnte man überdenken. So bekommt man ja keine Rückmeldung, ob das geklappt hat oder nicht!

Ich würde dann eher die Exception beim Auruf der Funktion abfangen und ggf. dort eine Meldung ausgeben. Mit einem leeren Dict kannst Du dann ja immer noch weiterarbeiten.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Antworten