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

Danke BlackJack !!

Ich habe mir shelve angeschaut und es macht ja eigentlich genau das was ich machen wollte - nur halt eben viel einfacher. Wie ich auf die keys zugreifen kann habe ich schon verstanden, doch auf die einzelnen Eintäge bzw. alphab. Sortierung etc ?. In pyhthon ge-packt ist das Modul gar nicht aufgeführt (oder ich kann es nicht finden). Den Zugrif mit dem modul operator ? Das habe ich in dem How To/Sorting gefunden.

gruss und dank frank
BlackJack

`shelve` ist genau wie ein Dictionary unsortiert. Man kann den Sortierschlüssel als Schlüssel für das Dictionary benutzen und dann die Liste mit Schlüsseln abfragen und sortieren.

Aber wie schon gesagt, ist das datensatzweise zugreifen auf ein paar Adressen komplizierter als die Daten immer komplett zu lesen und zu schreiben. Dann kann man sie auch problemlos im Speicher sortieren bevor man sie rausschreibt.
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Meinst Du es so ?!

Die Daten speichern und nich sortieren. Beim auslesen sortieren und anzeigen - ncht sortiert abspeichern.

Mit .intervalues() oder .['...'] komme ich an die Einträge
Mit keys() an die Anzahl der Einträge.

Wie greife ich auf die Einträge in den Einträgen pro Person ?

gruss und dank frank
BlackJack

Da ich jetzt gerade gar nicht weiss in welcher Datenstruktur Du die Einträge verwalten willst, kann ich fast keine von den Fragen beantworten.

Ich meine am einfachsten ist es die Daten immer komplett im Speicher zu haben, und zwar sortiert. Wenn man eine Adresse ändert, hinzufügt oder entfernt, dann sortiert man die Adressen sofort danach.

Und am Programmanfang und Programmende bzw. auch auf Wunsch des Anwenders lädt und speichert man alle Adressen. Dabei sind `pickle` oder `csv` wohl die einfachsten Formate. Bei letzterem würde ich auch nach dem Laden vorsichtshalber sortieren, weil da ja zwischenzeitlich jemand mit einem Texteditor etwas verändert haben könnte.
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

So und nun eine neue Variation meines Adressbuches - noch nicht ganz fertig ! Ein neues Adressbuch legt man mittels einer texdatei an und als 1. Eintrag eine 0. Die Suche muss ich irgendwie mit split und ':' ändern, damit es nur in den Einträgen sucht.

Code: Alles auswählen

# adressbuch.py
def ausgabe(adressbuch):

    for anzahl_eintraege in range (len(adressbuch)):

        print '____________________________________'
        print
        print adressbuch[anzahl_eintraege]
        print '===================================='
        raw_input()
                         
    anzahl_eintraege = anzahl_eintraege + 1
    
    if anzahl_eintraege == 1:
             
        print
        print anzahl_eintraege,'Eintrag im Adressbuch'
        print
                          
    if anzahl_eintraege > 1:
        
        print
        print anzahl_eintraege,'Eintraege im Adressbuch'
        print

        
def suchen(adressbuch):

    suche = raw_input('Suchbegriff:')                    

    zaehler = 0
         
    for anzahl_eintraege in range (len(adressbuch)):

        s=adressbuch[anzahl_eintraege].upper().find(suche.upper())
        
        if s >= 0:

            zaehler = zaehler + 1
            print '____________________________________'
            print
            print adressbuch[anzahl_eintraege]
            print '===================================='
            raw_input()

    if zaehler == 1:
             
        print
        print zaehler,'Eintrag im Adressbuch gefunden'
        print
                          
    if zaehler > 1 or zaehler == 0:
        
        print
        print zaehler,'Eintraege im Adressbuch gefunden'
        print


def eintragen(adressbuch, spkrit):
   
    neu_eintrag = ''
    
    for x in range (len(spkrit)):
        
        neu_eintrag = neu_eintrag + spkrit[x] + ' ' + raw_input(spkrit[x]) +'\n'

    adressbuch.insert((len(adressbuch)+1), neu_eintrag)
    adressbuch.sort()


def beenden(adressbuch):

    f = file('adressbuch.txt','w')
    
    f.seek(0)
    f.write(str(len(adressbuch)) + '\n')
    
    for anzahl_eintraege in range (len(adressbuch)):
        
        f.writelines(adressbuch[anzahl_eintraege])
        

adressbuch = []
eintrag = ''
spkrit=('Name:      ', 'Strasse:   ', 'Ort:       ',
      'Festnetz:  ', 'Handy:     ', 'email:     ', 'Bemerkung: ')

f = file('adressbuch.txt','r')

for anzahl_eintrag in range (int(float(f.readline()))):

    for anzahl_kriterien in range(len(spkrit)):
        
        eintrag = eintrag + f.readline()
        
    adressbuch.insert(anzahl_eintrag, eintrag)
    eintrag=''
    
f.close()

while True:
       
    print
    print '____(A)nzeigen des Adressbuches____'
    print '____(E)ingabe neuer Adresse________'
    print '____(S)uche von Adressen___________'
    print '____(B)eenden des Adressbuches_____'
    print
                  
    auswahl=raw_input('Auswahl:')
                        
    if auswahl.upper() in ['A']:
          
        ausgabe(adressbuch)

    if auswahl.upper() in ['E']:
          
        eintragen(adressbuch, spkrit)
                       
    if auswahl.upper() in ['S']:
          
        suchen(adressbuch)
                              
    if auswahl.upper() in ['B']:
          
        beenden(adressbuch) 
        break
pocco.org hat nicht funktioniert

gruss un dank frank
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
Antworten