Optimierung eines Telefonbuchs

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.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@Dav1d: Nein!

Ich hab mir grad noch mal das angeguckt: Wieso heißt das noch tell()? Mich wundert, dass das überhaupt klappt!

Code: Alles auswählen

# wieso person_info - das ist doch bei dir eine "person", also würd ichs auch so nennen
def tell(person_info):
    # wieso haben die Keys hier einen ":" dran? Das sollte einen Fehler geben!
    order = ['Name:', 'Tel. Number:', 'Mob. Number:',
       'Occupation:', 'Address:', 'Email:']
    for key in order:
        try:
            print "%s %s \n" %(key, person_info[key])
        except KeyError:
            pass

def display_all(pb):
    # i ist mist! wieso nicht "person"?
    for i in pb.values():
        tell(i)
        print "*"*45
Seeker
User
Beiträge: 70
Registriert: Mittwoch 16. September 2009, 19:52

Ich war Essen, hatte also noch keine Zeit mich ums öffnen/schliessen etc. zu kümmern.
Aber nur kurz zur Erklärung:
Wieso heißt das noch tell()
Es hiess tell(), weil ich ursprünglich ein Grundgerüst aus "Byte of Python" genommen hatte, wo tell() benutzt wurde. Mir persönlich gefällt der name tell() einfach, da ich das phonebook sozusagen nach einer Person frage und er mir was über sie "erzählt". k.A., ich fands jetzt nicht so tragisch :roll:
# wieso person_info - das ist doch bei dir eine "person", also würd ichs auch so nennen
Es heisst person_info, weil es das "innere" Dictionary ist. Im phonebook sind ja die verschiedenen Personen als Keys drin, und deren Values (wiederum Dictonaries) habe ich halt person_info genannt, weil dort die einzelnen Infos über eine Person enthalten sind.
# i ist mist! wieso nicht "person"?
Weil ich am Anfang für alle for ... in... jeweils i benutzt habe und erst nachträglich gewisse verändert habe.

Aber ich mach mich zuerst mal ans Grundgerüst, danach kann ich Namen immer noch ändern.

*EDIT*:
Tut mir echt leid... aber ich verstehe irgendwie immer noch nicht, was am file-management so falsch war. Vielleicht sehe ich einfach etwas völlig falsch. Ich erklär mal wie ichs mir gedacht hab (arbeite unterdessen trotzdem mal an deinem Vorschlag):

Code: Alles auswählen

def organize_file():
    '''Takes care of the opening/creating, processing,
and saving the file'''
    try: #Versuch, das phonebookfile zu öffnen. Falls es existiert, wird
         #es geladen.
        f = open("phonebook.data")
        pb = pickle.load(f)
        f.close()
        manage_menu(pb) #zugegeben, dies ist nicht schön. Aber andersrum machts noch
                        #Sinn: Ich öffne das Phonebook (ohne dieses macht das
                        #ganze Programm ja keinen Sinn), arbeite dran so lang
                        #rum wie ich wünsch, und dann wird es automatisch
                        #gespeichert.
        
    except IOError: #Diese Exception kommt, wenn das File noch nicht existiert,
                    #d.h. das Programm zum ersten Mal ausgeführt wird.
        f = open(phonebookfile, "w")
        f.close()   #Das erstellen und schliessen eines leeren File verhindert,
                    #dass ich mich beim pickle.dump und schliessen der File
                    #darum sorgen muss, ob das File nun zu Beginn existierte oder nicht
        manage_menu(pb = {}) #siehe oben
    finally:
        f = open(phonebookfile, "w")    #dieser Punkt wird erreicht, wenn ich mit
                                        #"break" den loop beende. Die Datei existiert
                                        #sicher, dafür wurde schon gesorgt.
                                        #also einfach öffnen, dumpen, schliessen.
        pickle.dump(pb, f)
        f.close()
Seeker
User
Beiträge: 70
Registriert: Mittwoch 16. September 2009, 19:52

Soo... neuer Versuch
Das Programm ist nun so aufgebaut:

main:
----loop:
-------input(wahl)
-------load pb
-------save pb
-------change pb
-----------loop: (wahl wie bisher)
-------exit

Das Programm ist irgendwie launisch. Zum Teil funktioniert es so halb, zum Teil verhält es sich komisch... vor allem betreffend der Loops (z.B. ich rufe den break des main-loops auf, welcher auch beendet wird... aber dafür lande ich im manage_menu-loop ?!)
Auch erscheinen beim laden und speichern immer neue Errors... weshalb ich bei den exceptions, die gewählt werden sollen, wenn das File nicht existiert, nicht ganz sicher bin.

Naja, hier mal der neue Teil des Codes:

http://paste.pocoo.org/show/141345/
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Das ist kein komisches Verhalten. Immerhin rufst du in Zeile 38 erneut die main-Funktion auf, du hast die Rekursion also nur sehr gut versteckt. Wie schon einmal gesagt: Parameter und Rückgabewerte. Erwähnte ich eigentlich Parameter und Rückgabewerte?
Das Leben ist wie ein Tennisball.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Nein, nein, nein!

Wieso nutzt Du nicht meine Vorgaben für das Laden und Speichern? So fängst Du beim Speichern genau gar keine Exceptions ab... :roll:

Und man sollte das with-Statement beim öffnen von Dateien benutzen - wieso "wehrst" Du Dich dagegen? Ich habe Dir das alles schon mal gezeigt!

Ich vermute das ganze geht schief wegen div. Rekursionen ohne Rücksprung!

Wieso machst Du es Dir denn so schwer?

Nach dem Start landet man in dem main-loop, in dem man Kommandos absetzen kann. Nach jeder Operation wird dahin zurückgesprungen!

Wozu dieses verschachtelte (was eben zu einer Rekursion führen dürfte!).

Hier mal ein logischer Aufbau:

Code: Alles auswählen

import sys

def load(filename="was auch immer"):
    # hier dann das Laden
    # das initialisierte dict zurückgeben
    return pb


def dump(pb):
    # hier das Speichern


def foo(pb):
    print "Hier passsiert was mit pb", pb


def bar(pb):
    print "Hier was anderes...", pb


def manage_menu(pb):
    mapping = {
        # wie gehabt
    }
    while True:
        cmd = raw_input("Command:")
        # mit "q" kommt man hier raus
        if cmd == "q":
            return
        try:
            mapping[cmd](pb)
        except KeyError, e:
            print "Ungültiges Kommando"


def main():
    # von mir aus zu Beginn mal gleich was laden
    # z.B. Parameter 1 aus der Kommandozeile
    pb = load(sys.argv[1]) or {}
    # dict an den main_loop
    manage_menu(pb)
    # nach "q" landet man hier und damit sauber am Ende
Seeker
User
Beiträge: 70
Registriert: Mittwoch 16. September 2009, 19:52

Und man sollte das with-Statement beim öffnen von Dateien benutzen - wieso "wehrst" Du Dich dagegen?
Weil ich aus irgendeinem Grund immer noch nicht sehe, inwiefern mein "try - except" damit los wird :( .
Wenn ich load() aufrufe (mal egal von wo), dann soll es phonebook.data öffnen, oder, wenn dieses nicht existiert, eine Datei erstellen, die phonebook.data heisst.
Und 'with open('phonebook.data') as f:' gibt mir ja einen IOError, wenn ich nach einer Datei suche, die nicht existiert... also genauso, wie wenn ich es mit f = open('phonebook.data').
Oder mache ich was grundsätzlich falsch? =/

Test mit "with... as..." mit phonebookfile, das nicht existiert:

Code: Alles auswählen

Traceback (most recent call last):
  File "C:\Python26\Lib\site-packages\Programmieren\Test.py", line 1, in <module>
    with open('phonebook.data') as f:
IOError: [Errno 2] No such file or directory: 'phonebook.data'

####Deshalb hatte ich ein except IOError eingefügt, das eine Datei erstellt, wenn sie nicht existiert
Meine load und save Funktionen:

Code: Alles auswählen

def pb_load(f = 'phonebook.data'):
    with open('phonebook.data') as f:
        pb = pickle.load(f)
        return pb
    
def pb_save(pb):
    with open('phonebook.data', "w") as f:
        pickle.dump(pb, f)
        f.close()
Da ich meines Wissens nur im cmd argumente hinzufügen kann, dieses Programm aber meistens direkt ausführe, sollte der Name ('phonebook.data') wenn möglich als default drin sein.

Die neue Umstrukturierung von manage_menu ist super, danke. :)
Habe auch ein paar Ausgabeänderungen unternommen, aber ich poste die Version dann mal, wenn ich das mit dem "with open(---) as --:" verstanden hab.
Immerhin rufst du in Zeile 38 erneut die main-Funktion auf, du hast die Rekursion also nur sehr gut versteckt. Wie schon einmal gesagt: Parameter und Rückgabewerte. Erwähnte ich eigentlich Parameter und Rückgabewerte?
Ja, hast du =). Ich hab mich auch eingelesen, auch wenns an der Anwendung noch ein bisschen klemmt. Aber mein Fehler war, dass ich nach dem "break" im main() das "False" vergessen hatte, weshalb ich einfach wieder im Loop drin war. Weshalb ich mich dann gleich im manage_menu() wiederfand, ist mir noch unklar, aber das ist jetzt nicht so wichtig =).
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Seeker hat geschrieben:
Und man sollte das with-Statement beim öffnen von Dateien benutzen - wieso "wehrst" Du Dich dagegen?
Weil ich aus irgendeinem Grund immer noch nicht sehe, inwiefern mein "try - except" damit los wird :( .
Wirst Du auch nicht - aber das finally! Du musst nur noch den möglichen IOError abfangen, wenn die Datei nicht gefunden wird oder sonst wie nicht geöffnet werden kann. Es geht darum, dass das with automatisch sicher stellt, dass keine geöffneten Datein "zurückbleiben".

Code: Alles auswählen

try:
    with open()...
except IOError, e:
    # was auch immer dann
else:
    # wenn man mit den daten noch mehr machen will
Wenn ich load() aufrufe (mal egal von wo), dann soll es phonebook.data öffnen, oder, wenn dieses nicht existiert, eine Datei erstellen, die phonebook.data heisst.
Nein!!! Eine Funktion load() wird niemals eine Datei erstellen! Wozu auch? Es spielt doch später keine Rolle mehr, ob die existiert! Wenn Du zum Speichern kommst, wird doch sowieso eine neue Datei angelegt. Wenn Du also nichts laden konntest, startest Du eben mit einem leeren Dictionary... (Du kannst Dir z.B. überlegen, bei einem IOError eben ein leeres dict zurückzugeben)
Seeker
User
Beiträge: 70
Registriert: Mittwoch 16. September 2009, 19:52

Danke für die schnelle Antwort =).
Wirst Du auch nicht - aber das finally! Du musst nur noch den möglichen IOError abfangen, wenn die Datei nicht gefunden wird oder sonst wie nicht geöffnet werden kann. Es geht darum, dass das with automatisch sicher stellt, dass keine geöffneten Datein "zurückbleiben".
Dann hatte ich dich missverstanden, deshalb die Verwirrung.
Nein!!! Eine Funktion load() wird niemals eine Datei erstellen! Wozu auch? Es spielt doch später keine Rolle mehr, ob die existiert! Wenn Du zum Speichern kommst, wird doch sowieso eine neue Datei angelegt. Wenn Du also nichts laden konntest, startest Du eben mit einem leeren Dictionary... (Du kannst Dir z.B. überlegen, bei einem IOError eben ein leeres dict zurückzugeben)
Stimmt, macht eigentlich wenig Sinn. hm... ich glaube, ich werde einfach beim Start von main() gleich ein leeres dict einführen, welches ggf. durch load() durch ein gespeichertes ersetzt wird.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Seeker hat geschrieben: Stimmt, macht eigentlich wenig Sinn. hm... ich glaube, ich werde einfach beim Start von main() gleich ein leeres dict einführen, welches ggf. durch load() durch ein gespeichertes ersetzt wird.
Oder so :-)
Seeker
User
Beiträge: 70
Registriert: Mittwoch 16. September 2009, 19:52

So, jetzt hab ichs schon fast :). In dieser Form funktionierts:

http://paste.pocoo.org/show/141435/

Deine Idee mit dem pb = pb_load(sys.argv[1]) fand ich gut, da man so ein Phonebook laden kann, das nicht unter phonebook.data gespeichert ist.
Allerdings kommt immer die Meldung:

Code: Alles auswählen

Traceback (most recent call last):
  File "C:\Python26\Lib\site-packages\Programmieren\Phonebook3c.py", line 100, in <module>
    main()
  File "C:\Python26\Lib\site-packages\Programmieren\Phonebook3c.py", line 84, in main
    pb = pb_load(sys.argv[1]) or {}
IndexError: list index out of range
Müsste ich da wieder ein if-Statement benutzen? Oder gibt es einen eleganteren Weg?

Dann das letzte Detail:
Ich habe nun (fast) meine gewünschte Ausgabe erreicht:
Partial Code:

Code: Alles auswählen

Name: Adrian Smith

Tel. Number: 056 234 87 45
Mob. Number: 097 345 23 54

Occupation: Testsubject

Address: Upper left corner\n47538 Your Backyard

Email: thecakeisalie@portal.com
*********************************************
Ich verstehe nicht ganz weshalb das "\n" nicht funktioniert... kann es sein, dass ein string in einem dict() als rawstring behandelt wird?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.

Zu dem Indexfehler: Es wird erst versucht auf den Index 1 zuzugreifen, was natürlich nicht funktioniert. Das wirft dann eine Exception, der Rest wird nicht mehr ausgewertet. Du musst also vorher testen, ob der Index vorhanden ist.

Code: Alles auswählen

try:
    pb = pb_load_(sys.argv[1])
except IndexError:
    pb = {}
Das "or" benutzt du übrigens sematisch falsch. Es tut zwar das, was es auch tun soll, aber ein if/else passt besser.

Zur Ausgabe: Bei der Adressanfrage gibtst du doch sicher "Upper left corner\n47538 Your Backyard" ein und bestätigst mit Enter. Dort wird natürlich das "\n" sofort intern in ein "\\n" umgewandelt, da du das Zeichen "\" eingegeben hast. Ein newline erhältst du, wenn du Enter drückst.

Entweder musst du die Adressteile einzeln Abfragen oder du behandelst eine Adresse gesondert, indem du Beispielsweise ein Semikolon als Trennzeichen verwendest und dann daran aufteilst.
Das Leben ist wie ein Tennisball.
Seeker
User
Beiträge: 70
Registriert: Mittwoch 16. September 2009, 19:52

Alles klar =).
Vielen Dank für eure Hilfe/Geduld! :D
Zur Ausgabe: Bei der Adressanfrage gibtst du doch sicher "Upper left corner\n47538 Your Backyard" ein und bestätigst mit Enter. Dort wird natürlich das "\n" sofort intern in ein "\\n" umgewandelt,
Komischerweise war das eben nicht der Fall, als ich statt dem dict() noch eine Liste benutzte.

Nur ne letzte kleine Frage:
Ich hab gesehen, dass du oft z.b. "Sorry, Kommando '{0}' unbekannt".format(choice) benutzt hast, wo ich "Sorry, Kommand %s unbekannt" %(choice) genommen hätte.

Gibt es da einen Unterschied/vorzuziehende Version?

lg Seeker
Zuletzt geändert von Seeker am Freitag 25. September 2009, 21:44, insgesamt 1-mal geändert.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.

Der Wechsel von einer Liste auf ein Dictionary hat damit sicher nichts zu tun, da hast du sicher noch mehr geändert.

Zum String Formatting: Das steht alles in der Dokumentation ;-)

str.format und String Formatting.
Das Leben ist wie ein Tennisball.
Seeker
User
Beiträge: 70
Registriert: Mittwoch 16. September 2009, 19:52

Wird wohl schon so sein... wurde alles mehrmals neu geschrieben ;) (zu Recht).

Habe nun eine funktionierende (End)Version, wo dies auch gelöst ist:
Zugegeben, der Code-Aufwand für eine neue Zeile scheint etwas gross zu sein... und die Ausrichtung ist nicht gerade elegant. Die Idee fand ich aber noch gut... (war auch nicht von mir xD). Dieses Vorgehen ermöglicht es, Adressen von verschiedenen Längen einzutragen (2 Zeilen, 3 Zeilen), was z.T. von Nutzen sein kann.

http://paste.pocoo.org/show/141514/

lg Seeker
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.

Fallen dir die Gemeinsamkeiten in den Zeilen 39, 55/56 und 59 nicht auf? Hier schreit es geradezu nach Konstanten.

Zeilen 85 bis 88 würde man wieder mit einem try/except lösen.

Warum hast du 95 bis 102 nicht auch mit einem Dictionary gelöst?

Das "False" in 103 ist vollkommen überflüssig.

Zeilen 62 und 63 sind Unsinn. ein "else: pass" tut genau nichts.

Sehe ich es richtig, dass die Adresse einfach als Liste ausgegeben wird? Finde ich jetzt nicht besonders benutzerfreundlich.

Die Namen finde ich immer noch seltsam. Warum nennst du "e_address" nicht einfach "email" und "pb" nicht "phonebook"? Das "i" und "a" sind immer noch da.

Zeile 54 würde ich zwischen 56 und 57 packen, das "order" würde ich aus der Funktion ziehen.

Aber im Großen und Ganzen sieht es wirklich schon sehr gut aus.
Das Leben ist wie ein Tennisball.
Seeker
User
Beiträge: 70
Registriert: Mittwoch 16. September 2009, 19:52

Fallen dir die Gemeinsamkeiten in den Zeilen 39, 55/56 und 59 nicht auf? Hier schreit es geradezu nach Konstanten.
Naja, die Gemeinsamkeit liegt wohl auf der Hand... aber was für Konstanten? :/
Ich schätze nein ...
Zeilen 85 bis 88 würde man wieder mit einem try/except lösen.
hm... ok. Gibt's da einen bestimmten Grund? Oder sollte man einfach wenn immer möglich try/except und nicht if/else benutzen?
Ich meine, es ist ja eigentlich ein ziemlich klares if, else -statement. und kürzer wirds mit try/except nicht.
Warum hast du 95 bis 102 nicht auch mit einem Dictionary gelöst?
Ich schätze, weil es für mich (als Anfänger) als mit den if's noch klarer auf der Hand lag.
Aber wieder die gleiche Frage... weshalb? Es führt ja sogar zusätzliche Bezeichnungen ein. Nicht, dass ich was gegen die Idee habe, ich sehe nur den Vorteil nicht ganz. Wird die Rechenarbeit schneller?
Oder ist es einfach eine für Programmierer ästhetischere Lösung?

Das "False" in 103 ist vollkommen überflüssig.

Zeilen 62 und 63 sind Unsinn. ein "else: pass" tut genau nichts.
Hatte ich vergessen rauszunehmen, danke.
Sehe ich es richtig, dass die Adresse einfach als Liste ausgegeben wird? Finde ich jetzt nicht besonders benutzerfreundlich.
Jup, gebe ich sofort zu (habs ja schon im vorherigen Post gesagt), aber eine bessere Lösung fand ich nicht :). Genauer gesagt ist es ja sogar ein "stitching" von vielen Listen in eine, die ausgegeben wird.
Die Namen finde ich immer noch seltsam. Warum nennst du "e_address" nicht einfach "email" und "pb" nicht "phonebook"? Das "i" und "a" sind immer noch da.
e_address... für elektronische adresse (war wohl klar). Kann nicht sagen weshalb, ich fand den Namen einfach passend.

pb weil kürzer. (musste es ja oft schreiben)

Das "a" habe ich nun durch "nav" ersetzt. (Für navigate, da es genau das macht. "cmd" wollte ich nicht nehmen, da es schon im anderen loop gebraucht wird)
Das "i" heisst nun person_info.
1. wird es oben auch so genannt.
2. will ich es vom Hauptdict-Key unterscheiden, welches person genannt würde.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hi.
Seeker hat geschrieben:Naja, die Gemeinsamkeit liegt wohl auf der Hand... aber was für Konstanten?
Zum Beispiel "Name:" oder "Mob. Number:". Die Benutzt du sowohl oben als auch unten als Schlüssel. Daher solltest du sie einmal als Konstante definieren und dann nur noch die Konstante verwenden. Im Prinzip kannst du auch die Liste als Konstante erzeugen und dann per "zip"-Funktion in Zeile 39 das Dictionary zusammenfassen:

Code: Alles auswählen

ORDER = ['Name:', 'Tel. Number:', 'Mob. Number:', 'Occupation:', 'Address:', 'Email:']
person = dict(zip(ORDER, (name, tel_nr, mob_nr, ...)))
Dabei fällt mir doch auf, dass die Schlüsselname sehr unglücklich gewählt sind. Schlüssel so zu wählen, dass sie sowohl als Daten, als auch als Ausgabe dienen ist etwas ungeschickt.
Seeker hat geschrieben:hm... ok. Gibt's da einen bestimmten Grund? Oder sollte man einfach wenn immer möglich try/except und nicht if/else benutzen?
Ein try/except ist eben der Python-Weg: Versuche erst den normalen Weg zu gehen, wenn das nicht funktioniert, dann kümmere dich um die Ausnahme EAFP-Prinzip (Easier to Ask Forgiveness than Permission) im Gegensatz zu LBYL (Look Before You Leap).
Seeker hat geschrieben:Aber wieder die gleiche Frage... weshalb? Es führt ja sogar zusätzliche Bezeichnungen ein. Nicht, dass ich was gegen die Idee habe, ich sehe nur den Vorteil nicht ganz. Wird die Rechenarbeit schneller?
Oder ist es einfach eine für Programmierer ästhetischere Lösung?
Das ist ein einfacher Weg lange if/elif-Kaskaden zum umgehen. Wenn eine gewisse Größe nicht überschritten wird, dann ist ein einfaches elif sicher einfacher, allerdings kommen bei Menü-Strukturen doch öfter mal neue Einträge hinzu. Warum also nicht gleich richtig schreiben? Da du das Programm aber wohl nur zu lernen einsetzt, musst du es natürlich nicht extra umschreiben, du hast es ja auch schon einmal so umgesetzt.

Um Geschwindigkeiten macht sich bei so kleinen Beispielen sicher niemand Gedanken. Auch noch nicht bei größeren Programmen.
Seeker hat geschrieben:Jup, gebe ich sofort zu (habs ja schon im vorherigen Post gesagt), aber eine bessere Lösung fand ich nicht Smile. Genauer gesagt ist es ja sogar ein "stitching" von vielen Listen in eine, die ausgegeben wird.
Hier hätte man den seltenen Fall, wo ein "isinstance" angebracht wäre und eine einfache Verzweigung aufgebaut wird. Zwei, wie ich finde weniger geeignete, Alternativen fallen mir noch ein: alle Einträge als Listen speichern. Das funktioniert zwar prima, aber macht überhaupt keinen Sinn. Oder den Java-Weg und eine Klasse um die Einträge bauen. Aber den will niemand beschreiten ^^

Zu den Namen: was hast du nur mit diesen Abkürzungen? Die Namen sind nun wirklich nicht so lang, dass das nötig wäre. Als nächstes kürzt du noch "list" noch mit "lst" ab ^^

Du kannst die selben Namen in verschiedenen Funktionen verwenden, die Namensräume sind sauber getrennt. Etwas "navigation" zu nennen, weil an einer anderen Stelle schon "command" benutzt wurde ist unsinnig. Nenne Sachen einfach danach was sie sind, dann ist der Code am einfachsten zu verstehen. Und wenn beides Anweisungen sind, dann hast du eben zweimal ein "command".

Zu "person_info": in Zeile 39 behauptest du, dass es eine Person ist. Daher verstehe ich nicht von welchen Hauptdict-Key(?) du das unterscheiden möchtest.

Ich hoffe, dass ich alle Fragen klären konnte. Zu EAFP empfehle ich dir noch ein wenig die Suchmaschine deiner Wahl zu befragen.
Das Leben ist wie ein Tennisball.
Seeker
User
Beiträge: 70
Registriert: Mittwoch 16. September 2009, 19:52

Ich hoffe, dass ich alle Fragen klären konnte. Zu EAFP empfehle ich dir noch ein wenig die Suchmaschine deiner Wahl zu befragen.
Jup, fast, danke für die ausführliche Erklärung :). Fun Trivia: EAFP steht unter anderem für "The European Association of Fish Pathologists", :P.
Die Benutzt du sowohl oben als auch unten als Schlüssel. Daher solltest du sie einmal als Konstante definieren und dann nur noch die Konstante verwenden.
Meinst du in diesem Stil?:

Code: Alles auswählen

def new():
    a = "Name:"
    b = "Address:"
    c = "Tel. Number:"

    name = raw_input("Name:")
    address = raw_input("Address:")
    tel_nr = raw_input("Tel. Number:")

    person = {a:name, b:address, c:tel_nr}
    pb[name] = person
Aber dann müsste ich ja alle Konstanten in jedem Block wieder definieren... irgendwie unnötige Verlängerung des Codes (ausser ich führe sie alle durch Parameter oder als globals ein... ) oder verstehe ich das falsch?
Im Prinzip kannst du auch die Liste als Konstante erzeugen und dann per "zip"-Funktion in Zeile 39 das Dictionary zusammenfassen:
Das ist ne tolle Sache, kannte ich noch nicht :D. Aber irgendwie bekomme ich dann schnell Probleme. Die Liste 'order' habe ich ja erstellt, damit die Angaben in einer bestimmten Reihenfolge ausgegeben werden. Wenn ich die Liste in das Dictionary nehme, geht das wieder verloren. Die einzige Möglichkeit wäre wieder, die Liste separat mitzunehmen.

Bsp:

Code: Alles auswählen

def main ():
    keys = ['b', 'a', 'c']
    values = ['bee', 'apple\ntree', 'cedar']
    pairs = dict(zip(keys, values))
    output(pairs)

def output(pairs):
    print pairs
    for key in pairs:
        print "%s:%s" %(key,pairs[key])
        
if __name__ == "__main__":
    main()
Ausgabe:

Code: Alles auswählen

{'a': 'apple\ntree', 'c': 'cedar', 'b': 'bee'}
a:apple
tree
c:cedar
b:bee
(Anstatt bee - apple - cedar)

Dabei fällt mir doch auf, dass die Schlüsselname sehr unglücklich gewählt sind. Schlüssel so zu wählen, dass sie sowohl als Daten, als auch als Ausgabe dienen ist etwas ungeschickt.
Aber ansonsten müsste ich ja für jedes Attribut ein print-statement machen (um zu spezifizieren, was vorne dran steht), nicht? Dazu kommt, dass ich dann wieder eine ganze Reihe von if-statements machen müsste.
Ein try/except ist eben der Python-Weg
Alles klar ;)
Hier hätte man den seltenen Fall, wo ein "isinstance" angebracht wäre und eine einfache Verzweigung aufgebaut wird.
Dafür müsste ich aber zuerst eine Klasse aufbauen, oder?
Da mir Klassen zur Zeit noch eher fremd sind, belasse ich es mal wies ist, aber werde ggf. später darauf zurückkommen :).
Zu den Namen: was hast du nur mit diesen Abkürzungen? Die Namen sind nun wirklich nicht so lang, dass das nötig wäre. Als nächstes kürzt du noch "list" noch mit "lst" ab ^^

Du kannst die selben Namen in verschiedenen Funktionen verwenden, die Namensräume sind sauber getrennt. Etwas "navigation" zu nennen, weil an einer anderen Stelle schon "command" benutzt wurde ist unsinnig. Nenne Sachen einfach danach was sie sind, dann ist der Code am einfachsten zu verstehen. Und wenn beides Anweisungen sind, dann hast du eben zweimal ein "command".
Kommt vielleicht von der Mathematik... je kürzer desto besser ;).
phonebook_load(phonebook) finde ich einfach erdrückend :D. Aber dies lässt sich mit find/replace schnell lösen =).
Zu "person_info": in Zeile 39 behauptest du, dass es eine Person ist. Daher verstehe ich nicht von welchen Hauptdict-Key(?) du das unterscheiden möchtest.
Das Phonebook ist folgendermassen aufgebaut:

Code: Alles auswählen

phonebook = {
    Person1:{
        Name:Smith,
        Tel.:987987},
    Person2:{
        Name:Jackson,
        Tel.:234754}
    }

Hauptdict-keys:
    Person1, Person2 usw.

Unterdict-keys:
    Name, Tel., usw.
BlackJack

@Seeker: Es war nicht gemeint die einzelnen Schlüssel als Konstante zu definieren, sondern alle zusammen als Liste, wie EyDu das in seinem Beispiel mit `zip()` gezeigt hat. Und das einmal am Anfang global, dann kannst Du sie zur Ein- *und* Ausgabe verwenden. Den Doppelpunkt würde ich übrigens aus den Schlüsseln herauslassen.

Bei ``phonebook_load(phonebook)`` könnte man sich überlegen, ob das erste 'phonebook_' überhaupt notwendig ist und ob der Name des Arguments nicht besser `filename` lauten sollte. Denn das wird ja höchstwahrscheinlich in einem Modul mit dem Namen `phonebook` stecken, und damit wäre auch bei nur `load()` durch den umschliessenden Namensraum klar, dass es sich um eine Funktion zum Laden von einem Telefonbuch handelt. Wenn das im Namen der Ladefunktion steht, dann würde eine Benutzung von aussen so aussehen ``phonebook.phonebook_load(filename)`` vs. ``phonebook.load(filename)``.
Seeker
User
Beiträge: 70
Registriert: Mittwoch 16. September 2009, 19:52

Es war nicht gemeint die einzelnen Schlüssel als Konstante zu definieren, sondern alle zusammen als Liste, wie EyDu das in seinem Beispiel mit `zip()` gezeigt hat. Und das einmal am Anfang global, dann kannst Du sie zur Ein- *und* Ausgabe verwenden. Den Doppelpunkt würde ich übrigens aus den Schlüsseln herauslassen.
Ja, dann ist alles klar. Ich hatte meinen Weg nur gewählt, um eben eine global definiertes Argument zu vermeiden. Wenn ich das Modul phonebook.py als ganzes importiere, würde diese globale Konstante dann auch mit-importiert werden, oder?
Bei ``phonebook_load(phonebook)`` könnte man sich überlegen, ob das erste 'phonebook_' überhaupt notwendig ist und ob der Name des Arguments nicht besser `filename` lauten sollte. Denn das wird ja höchstwahrscheinlich in einem Modul mit dem Namen `phonebook` stecken, und damit wäre auch bei nur `load()` durch den umschliessenden Namensraum klar, dass es sich um eine Funktion zum Laden von einem Telefonbuch handelt. Wenn das im Namen der Ladefunktion steht, dann würde eine Benutzung von aussen so aussehen ``phonebook.phonebook_load(filename)`` vs. ``phonebook.load(filename)``.
Stimmt schon... Ich hatte daran gar nicht wirklich gedacht, da ich nie vorhatte, das Modul irgendwo zu importieren. Aber werds mir merken :).
Antworten