Funktionen richtig formuliert ?

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
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Viele Leute haben das gleiche Problem - 1000mal geschaut 1000mal hab ich nichts kapiert - oder so! :-)

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

Hinter "if", "def", "while" und "for" kommen keine Leezeilen, das macht den Code etwas unleserlich.

Sachen wie:

Code: Alles auswählen

for anzahl_eintraege in range (len(adressbuch)): 

        s=adressbuch[anzahl_eintraege].upper().find(suche.upper()) 
Kannst du noch vereinfachen auf:

Code: Alles auswählen

for anzahl_eintraege in adressbuch: 
        s=anzahl_eintraege.upper().find(suche.upper()) 
Dann, sparst du dir die ganzen unnötigen Indexzugriffe.

Und aus Zeilen wie dieser:

Code: Alles auswählen

print "-------------------"
Kannst du folgendes machen:

Code: Alles auswählen

print "-"*15
Am besten gleich mit Konstanten, oder einer Funktion die solche Zeilen ausgibt (oder gar beides :D ).
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Danke für die Antwort EyDu !

Das mit dem split() müsste ja nicht sein, doch habe ich halt zur Darstellung einfach Name:, Wohnort etc: eingefügt. Das habe ich nur gemacht, weil ich nicht an die Eintäge in den Einträgen pro Person gekommen bin. Habe es mit adressbuch[1,2] oder so versucht. Wie komme ich daran.

gruss frank und danke
BlackJack

Man kann über Einträge in einer Liste direkt iterieren, dazu braucht man nicht den Umweg über einen Index. Und einen Index `anzahl_*` zu nennen ist etwas irreführend.

Wenn man nach einem ``if`` mit einem weiteren ``if`` auf die genau gegenteilige Bedingung prüft, dann kann man dafür auch ein ``else`` benutzen.

Anstelle von `find()` könnte man den ``in``-Operator benutzen, was wesentlich leichter lesbar ist:

Code: Alles auswählen

if suchbegriff.upper() in eintrag.upper():
In `suchen()` ist dann auch gleich wieder eine Menge Quelltext, der nahezu identisch mit der `ausgabe()` ist. Das Programm würde kürzer, wenn man in `suchen()` einfach eine Liste mit den Adressen erstellt, auf die der Suchbegriff passt und damit dann `ausgabe()` aufruft.

Beim `eintragen()` wird wieder ein unnötiger Umweg über den Index gemacht und die vorletzte Zeile ist eine umständliche Art ``adressbuch.append(neu_eintrag)`` zu schreiben. Da taucht auch wieder dieses `spkrit` auf. Ich würd's `FELDNAMEN` oder so nennen und an den Anfang des Quelltextes verschieben.

Beim `beenden()` ist das ``f.seek(0)`` überflüssig. Und ob man die Anzahl der Datensätze wirklich in die Datei schreiben muss, hatte ich früher ja schon einmal hinterfragt. Man weiss ja, dass ein Datensatz sieben Zeilen lang ist, also kann man beim einlesen einfach alle sieben Zeilen einen neuen Datensatz an die Adressen-Liste anfügen.

Das schreiben ist dann wieder maximal umständlich. Wieder ein unnötiger Index und dann wird für eine einzelne Zeichenkette `writelines()` benutzt. Die Funktion erwartet ein "iterable" über Zeichenketten und schreibt jedes Element nacheinander in die Datei. In diesem Fall wird also jeder Buchstabe einzeln geschrieben. Da die Adressenliste schon Zeichenketten enthält, reicht ein einfaches ``f.writelines(adressbuch)`` um alles zu schreiben. Danach sollte man die Datei schliessen.

Das laden des Adressbuchs würde ich auch in eine Funktion verpacken. Auf Modulebene sollte so wenig wie möglich ausführbarer Code stehen.

Die Überprüfung der Auswahl ist auch wieder umständlich. Wieso wird auf enthaltensein in einer Liste mit einem Element geprüft, wenn ein einfacher Vergleich genügen würde?

So wie es jetzt da steht, könnte man die Funktionen so schreiben, dass alle das Adressbuch als einzelnes Argument entgegennehmen und eine Abbildung von Buchstabe zu Funktion benutzen.

Das speichern der Feldnamen in den Daten ist etwas ungünstig. Man sollte zum Beispiel nicht nach dem Vornahmen 'Andy' suchen, weil der durch 'Handy:' Bestandteil von jedem Datensatz ist.

Angepasste Version: http://paste.pocoo.org/show/1426/
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Danke BlackJack !

Deine Hilfe und Kritik ist immer sehr ausführlich und du gibst dir sehr viel Mühe mit deinen Erklärungen. Ich verstehe es oft nicht und deswegen mache ich die gleichen Fehler wieder. Mein "schräger" Stiel liegt in meinem "Unwissen" und falls es klappt bin ich zufrieden und lasse es so. Es gibt bestimmt für alles eine schöne "pythonische" Lösung - die kenne ich halt leider nicht bzw. noch nicht. Jetzt hast du mein "schönes" Programm perfekt gemacht und mir den Spass verdorben :-). Wolltest dem Trauerspiel ein Ende machen - ok - schon verstanden!

gruss und dank frank
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Oh - mit vielen "blöden" Fragen wird man zum Poweruser - eher powerposter :oops:

frank
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Mache jetzt aus dem Adressbuch eine "Medikamentenverwaltungsprogramm"
Einfach ein Programm zum Medikamentenkarten ausdrucken und verwalten.

So nun müsste ich aber an die einzelnen Einträge um z.B. eine Medikamentenänderung einzutragen. Es könnte der Ort z.B. ein Medikamenten sein, welches in der Dosierung verändert wurde. Diese will ich nun neu eintragen und nicht den ganzen Datensatz ändern ?

gruss und dank frank
BlackJack

Dann darfst Du einen einzelnen Datensatz nicht in *eine* Zeichenkette packen. Eine Liste, ein Dictionary oder ein Objekt einer eigenen Klasse pro Datensatz wäre geeigneter.
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Ah - so wie ich es mit dem einzelnen einlesen aus der Textdatei gemacht habe mit f.seek() - nur nicht halt mehr so, sondern den einzelnen Datensatz in eine eigene Liste einlesen und die dann mit eintrag[1] ansprechen. Kann ich Listen in Listen packen - habe ich irgendwo gelesen ?

danke und gruss
BlackJack

Vergiss doch mal dass es `file.seek()` gibt. ;-) Damit steuert man in Binärdateien ein bestimmtes Byte an, für Textdateien ist das total ungewöhnlich.

Schau Dir Dein einlesen bei den Adressen, oder vielleicht auch meine Variante an. Anstatt jede Zeile an eine Zeichenkette anzuhängen bis ein Eintrag komplett ist, hängst Du die Zeilen an eine Liste an. Und schon hast Du eine Liste mit einem Eintrag mit einem Datenfeld pro Zeile.

Und ja, man kann Listen in Listen stecken. In eine Liste kann man *jedes* Objekt stecken. Das ist der Liste vollkommen egal.
schlangenbeschwörer
User
Beiträge: 419
Registriert: Sonntag 3. September 2006, 15:11
Wohnort: in den weiten von NRW
Kontaktdaten:

kaytec hat geschrieben:Kann ich Listen in Listen packen - habe ich irgendwo gelesen ?
Es ist, oder besser es kann, nur etwas doof sein, listen in listen zu packen, denn mit indexen wie ´meineliste[2][3]´ wird das Programm unübersichtlich. Ab 3 Listen ineinander ist das Chaos dann wohl perfekt. Wie BlackJack schon sagte, ist es besser mit Dicts oder anderen geordneten (und komplexeren) Datenstrukturen zu arbeiten, da dann durch die bessere Codelesbarkeit auch weniger Fehler entstehen und man das Script auch nach ein paar Wochen noch einigermaßen versteht.
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Das ist mir schon klar, doch war ja mein Programm auch so kopliziert geschrieben. Ich habe grundsätzliche Verständnisprobleme.

Meine Probleme bei der ersten Programmversion war.

Wie "erkläre" ich dem Programm wieviel und wo steht was in der Textdatei.

Deswegen die ganze Positonsberechnung, einzelnes Einlesen der Daten und die Zahl der Einträge am Anfang des Textdatei.

Bei der Version von BlackJack wird (galub ich mal) getestet, ob es da
schon Einträge gibt und dann werden sie ausgelesen

Code: Alles auswählen

for line_nr, line in enumerate(adress_datei):
        if line_nr and line_nr % len(FELDNAMEN) == 0:
Wie auch immer das geht ? Das mit der 0 finde ich ja komisch, weil ich das als Bedingung sehen würde, wenn die Textdatei leer ist.

Da ich solch einen Version gar nicht kenne bzw. verstehe, habe ich mit den Anzahl der Eintäge am Anfang der Textdatei gemacht.

Die letzte Version von mir ging ja schon in die richtige Richtung, da ich ja den Datensatz komplett eingelesen habe. Natürlich wieder mit der Angabe der Anzahl am Anfang der Textdatei, da ich dem Programm sagen wollte lese etwas aus oder nicht und natürlich wieviel.

Das mit der erzeugen ein von mir gewünschten Liste machte mir auch Probleme, da ich dem Programm ja sagen muss wieviele ich brauche, um die Datensätze einzulesen. Die Anzahl kann das Programm ja nicht wissen .Die werden ja erst erzeugt beim Einlesen. Bei einer Liste ist das kein Probleme - Kommt alles in eine. Ich brauche ja aber für jeden Datensatz eine, um an alle Daten aus- bzw. einlesen zu können. Deswegen auch meine Frage: Listen In Listen speichern.

adressbuch[((Name1), (Ort1), (...)), ((Name2), (Ort2), (....))]

Beispiele für eine Dictionary finde ich in meinem Buch etwa so:
{1: 'a', 2: 'b'} über die keys könnte ich die einzelnen Einträge ein -auslesen. Ich Benötige aber doch so was:

adressbuch{1: 'Name1' , 'Ort1' ,'....' , 2: 'Name2' , 'Ort2' ,'.....'}

Ansprechen irgendwie so key(1,2) ?.

Viel Fragen und ich hoffe auch Antworten - schon mal vielen Dank!

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

kaytec hat geschrieben: Beispiele für eine Dictionary finde ich in meinem Buch etwa so:
{1: 'a', 2: 'b'} über die keys könnte ich die einzelnen Einträge ein -auslesen. Ich Benötige aber doch so was:

adressbuch{1: 'Name1' , 'Ort1' ,'....' , 2: 'Name2' , 'Ort2' ,'.....'}

Ansprechen irgendwie so key(1,2) ?.

Viel Fragen und ich hoffe auch Antworten - schon mal vielen Dank!

frank
Auch wenn ich so langsam müde werde:

Code: Alles auswählen

adressbuch={1:{"name":..., "ort":...}, 2:{"name":..., "ort":...}}
Wobei ich die "1" und die "2" als Schlüssel total unsinnig finde, außer es gibt Einträge mit dem selben Namen. Daher würde ich so etwas empfehlen:

Code: Alles auswählen

adressbuch={"Name einer Person":{"ort":...}, "Name einer anderen Person":{"ort":...}}
Unter Umständen bietet es sich auch an, die inneren Dictionaries als Liste von Tupeln zu realisieren, falls man beispielsweise mehrere E-Mail-Adressen zu einer Person aufnehmen möchte:

Code: Alles auswählen

adressbuch={"Name einer Person":[("ort",...), ("email","..."), ("email",..)]}
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

kaytec hat geschrieben:Viel Fragen
Hallo Frank!

Wie immer bei solchen Diskussionen, werfe ich hier mal diesen Link in die Runde.

http://www.python-forum.de/topic-6157.html

Vielleicht findest du darin eine Anregung (shelve oder sqlite z.B.).

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Vielen Dank EyDu!

Habe es mal abgetippt und so umgeschrieben das es zu meinem Programm passen würde!

Code: Alles auswählen

# -*- coding: cp1252 -*-
adressbuch = {'Muster Max':[('Strasse:', 'Musterstrasse 1'),
                            ('Ort:', 'Musterhausen 1000'),
                            ('Festnetz:', '0123456789'),
                            ('Handy:', '087654321'), 
                            ('email:', 'max-muster@max.de'),
                            ('Bemerkung:', 'muster')]}


print adressbuch['Muster Max'] # das funktioniert

# Für den Aufruf des Inhaltes der Strasse würde ich folgendes versuchen:
print adressbuch['Muster Max'], [0] # ergibt keine sinnvolle ausgabe
# print adressbuch['Muster Max', 0] gibt Fehlermeldungen


adressbuch = [['Muster Max', 'Musterstrasse 1', 'Musterhausen 1000',
               '012345678', 'max-muster@max.de', 'muster'],['Muster Maxi',
               'Musterhausen 2000', '021234567', '028765432',
               'maxi-muster@max.de', 'muster']]


print adressbuch[1] # das funktioniert

# Für den Aufruf des Inhaltes der Strasse würde ich folgendes versuchen:
print adressbuch[0], [1] # ergibt keine sinnvolle Ausgabe
# print adressbuch[0, 1] # Fehlermeldungen
Wo liegt mein Fehler?

Danke Gerold!!

Das habe ich mir angeschaut und wenn ich es abschreibe geht es natürlich auch ! Wie ich es für mich anpasse ?

gruss unf dank frank
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Code: Alles auswählen

print adressbuch['Muster Max'][0]
:D

Aber die Einträge über Indizes ansprechen ist immer eine schlechte Idee. Da solltest du dir lieber eine Funktion schreiben, die alle Eintraege ueber einen Namen zusammensammelt.

Dinen zweiten Ansatz im letzten Post solltest du lieber gleich vergessen ;-)
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Danke EyDu !

Ok - ich vergesse ihn ja gerne, doch was ist an dem schlechter ? Die Ausgabe würde ich so gestalten - bestimmt nicht schön - so kann ich es halt !

Code: Alles auswählen

adressbuch = [['Muster Max', 'Musterstrasse 1', 'Musterhausen 1000',
               '012345678','02345677', 'max-muster@max.de', 'muster'],
              ['Muster Maxi', ' Mustergasse 1', 'Musterhausen 2000',
               '021234567', '028765432', 'maxi-muster@max.de', 'muster']]


for eintrag in range (len(adressbuch)):
    for feldname in range(len(FELDNAMEN)):
        print FELDNAMEN[feldname], adressbuch[eintrag][feldname]
Bei meinem ersten Ansatz ...? Das mit dem len würde ja nicht gehen ?

Code: Alles auswählen

adressbuch = {'Muster Max':['Musterstrasse 1', 'Musterhausen 1000',
                             '0123456789', '087654321', 'email:',
                             'max-muster@max.de', 'Bemerkung:', 'muster']}

#for eintrag in range (len(adressbuch)):
    #for feldname in range(len(FELDNAMEN)):
        #print FELDNAMEN[feldname], adressbuch[key[eintrag]][feldname]
geht narürlich nicht !
Da wären meine Probleme wieder !

Einträge über Indizes ansprechen - mh - also nicht über die Zahlenwerte !? Warum nicht ? Eine Funktion die alle Einträge über die Namen zusammensammelt - mh - alle Namen? - alle Orte? - was habe ich davon?

gruss und dank frank
BlackJack

Wenn Du aus Fehlern lernen willst, solltest Du wissen was die Fehler waren. Erkläre mal was hierbei herauskommt und *warum*:

Code: Alles auswählen

print adressbuch[0], [1] # ergibt keine sinnvolle Ausgabe
Und bitte, bitte hör mit diesem ``range(len(liste))`` auf. Das wurde Dir jetzt schon mehrfach gesagt. Die Namen `eintrag` und `feldname` sind in dem Quelltext für die "Listen von Listen" irreführend weil es Indexe und keine Einträge oder Namen sind. Hier würden sie passen:

Code: Alles auswählen

for eintrag in adressbuch:
    for feldname, feld_wert in zip(FELDNAMEN, eintrag):
        print feldname, feld_wert
Ein Dictionary enthält Schlüssel und Werte und man kann über diese Paare mit den entsprechenden Methoden, wie `items()` was eine Liste erzeugt, oder `iteritems()` was einen Iterator über die Elemente zurückgibt, in einer Schleife iterieren und sie darin ausgeben. Oder `keys()`, `iterkeys()`, `values()` oder `itervalues()` für Schlüssel oder Werte.

Im Dictionary-Versuch sind zu viele Daten im Wert. Da haben sich Feldbezeichnungen eingeschlichen. Und man sollte den Namen mit in den Wert einfügen, sonst muss man ihn bei der Ausgabe gesondert behandeln.

Code: Alles auswählen

adressbuch = {'Muster Max':['Muster Max', 'Musterstrasse 1',
                            'Musterhausen 1000', '0123456789', '087654321',
                            'max-muster@max.de', 'muster']}

for name, felder in adressbuch.iteritems():
    for feldname, feld_wert in zip(FELDNAMEN, felder):
        print feldname, feld_wert
Ich denke aber nicht das ein Dictionary hier die richtige Datenstruktur ist, weil man selten exakt den kompletten Namen sucht. Für andere Suchen muss man dann trotzdem wieder linear alle Einträge durchgehen. Und Dictionaries sind ungeordnet, Adressen sortiert man aber ganz gerne.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

BlackJack hat geschrieben:Ich denke aber nicht das ein Dictionary hier die richtige Datenstruktur ist, weil man selten exakt den kompletten Namen sucht. Für andere Suchen muss man dann trotzdem wieder linear alle Einträge durchgehen. Und Dictionaries sind ungeordnet, Adressen sortiert man aber ganz gerne.
Am einfachsten ist es wahrscheinlich alles in eine SQLite-DB zu prügeln, aber die Aufgabe sieht doch eher nach einer Übung aus, als nach einem konkreten Projekt. Daher kann man sich ja auch langsam an eine schöne Lösung ranarbeiten.
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Dank BlackJack !

Warst ja mal wieder hart aber gerecht mit mir !

Es gibt für mich keine sinnvolle Ausgabe - für Python schon - gab ja keine Fehlermeldung. Eigentlich habe ich print [1] geschrieben und das ist ja auch passiert. So was evt.: schreibe Liste mit dem Element 1 ?

Das mit range(len(liste)) kann ich ja lassen - warum darf man Dinge nicht, die das gleiche machen. Macht für mich erst mal kein Sinn?!.

So was darf man schreiben: for i in range (len(liste)) ? Weil i für index steht und ich nicht auf die Elemente der Liste zugreife, sondern auf die Indexe der Element in der Liste.

for eintrag in adressbuch ist ok, weil ich nicht auf die indexe, sondern auf die wirklichen Einträge zugreife - auf die Elemnete der Liste (Der Ausdruck Element stimmt hoffentlich - steht so in meinem Buch)

Das mit den Dictionarys habe ich mal so verstanden: Eigentlich gelange ich nur über den Schlüssel an den gesamten Datensatz und nicht an die einzelnen Elemente. Das kann man nur über einen Zeiger(Iterator). Dieser zeigt mir im Speicher(ich nehme mal an Arbeitsspeicher) auf die Adresse wo es ja schon steht, da die Dictionary schon in den Speicher geladen wurde. ? Das wird völliger Quatsch sein :?


gruss und dank frank
Antworten