E-Check: kleines Anfänger Programm - suche etwas Hilfe

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Antworten
AlphaX2
User
Beiträge: 53
Registriert: Dienstag 28. Juni 2011, 10:42

Hallo Leute,

vor einiger Zeit habe ich angefangen mich mit Python zu beschäftigen - zunächst "a byte of python" und "learn pyton the hardway" als Tutorials soweit durchgearbeitet - dann keine Zeit mehr und jetzt das Erste eigene Programm geschrieben, zunächst würde ich es gern vorstellen, Verbesserungsvorschläge hören und an einer Stelle etwas Hilfe beanspruchen. :wink: Bitte bedenkt, dass ich wirklich blutiger Anfänger bin. :)

Zunächst mal Grundlegende Info:
Das kleine Programm gibt die Möglichkeit die E-Nummern für Lebensmittel zu checken - bisher noch alles nur im Terminal, folgen soll noch eine Qt-Oberfläche. Außerdem kann man sich die volle Liste aller Stoffe anzeigen lassen oder eine kurze Info zu den Stoffen. Grundlegend funktioniert das ganze auch schon. Im übrigen sind einige Stellen EXTRA als Funktion gemacht - einfach zum üben, so z.B. die start() oder auch wto_function().
Auch die Liste mit Stoffen ist bisher nur auf 2 Einträge reduziert und wird aus einer txt eingelesen - um das öffnen und auslesen zu üben.

Zunächst mal der Code:

Code: Alles auswählen

#!/usr/bin/python
#-*- coding: utf8 -*-

#-------------------
#imports
from sys import exit

#-------------------
#functions:
#start of the app/script and question about what to do
def start():
	print "Willkommen bei E-Check!"
	print "Was wollen Sie tun?"
	print "a: Einen Stoff checken."
	print "b: Kurze Infos zu E-Stoffen."
	print "c: Komplette Liste zeigen"
	print "q: Beenden!"
	
	global wto
	wto = raw_input(">")
	wto_function(wto)

#wto = what to do function for first choice about: check numbers, infos or quit.		
def wto_function(choice): 
	if wto == "a": 
		check_e()
	elif wto == "b":
		print_info()
	elif wto == "c":
		list_()	
	elif wto == "q":
		exit(0)
	else:
		start()

#function to give the user the hole list - not clever
def list_():
	lst = file('e_list_db.txt', 'r')
	while True:
		line = lst.readline()
		if len(line) == 0:
			break
		print line
	lst.close()
	raw_input("Enter um zurück zum Menü zu gehen!")
	start()

#check number and gives back only conntent of one special number, if again - check2 is used
def check_e():
	print "Geben Sie bitte die Nummer ein."
	number = input("E:")
	f = file('e_list_db.txt', 'r')
	
	while True:
		line = f.readline()
		if len(line) == 0:
			break
		
		for line in f:
			if line.startswith('E%r' %number):
				print line
				check_e2()
			#else: pass
	f.close()

#checks if there is wish for checking another one, if not - back to menu
def check_e2():
	check = raw_input("Wollen Sie eine weitere Zahl kontrollieren? J/N")

	if check == "J":
		check_e()
	elif check == "N":
		start()
	else: 
		check_e2()

#function prints out information text about e-numbers from txt file (just done this way to learn it)
def print_info():
	print """Gemeint ist damit die Liste der in der Europäischen Union zugelassenen Lebensmittelzusatzstoffe. 

Sie wird unterteilt in: 
- Lebensmittelfarbstoffe
- Konservierungsstoffe
- Antioxidantien und Säureregulatoren
- Süßstoffe
- Emulgatoren, Stabilisatoren, Verdickungsmittel und Geliermittel
- Rieselhilfen, Säureregulatoren
- Geschmacksverstärker
- und Weitere Stoffe.

In Deutschland ist die Liste als Anhang der Zusatzstoffzulassungsverordnung mit Höchstmengen und Eingrenzung auf bestimmte Lebensmittel enthalten. Der ADI-Wert (für Acceptable Daily Intake), engl. für erlaubte Tagesdosis (ETD), beschreibt die täglich tolerierbare Aufnahmemenge von Nahrungsmittelzusatzstoffen für den menschlichen Körper in Milligramm pro Kilogramm Körpergewicht (mg/kg) und gibt die Menge an, die über die gesamte Lebenszeit täglich gegessen werden kann, ohne dass dadurch gesundheitliche Gefahren zu erwarten wären.
"""
	raw_input(">Enter für Menü")
	start()

#-------------------

#starting first function - it's the menu
start()

So an einer Stelle brauche ich allerdings noch Hilfe und zwar hier:

Code: Alles auswählen

#check number and gives back only conntent of one special number, if wished again - check2 is used
def check_e():
	print "Geben Sie bitte die Nummer ein."
	number = input("E:")
	f = file('e_list_db.txt', 'r')
	
	while True:
		line = f.readline()
		if len(line) == 0:
			break
		
		for line in f:
			if line.startswith('E%r' %number):
				print line
				check_e2()
			#else: pass
	f.close()
Grundlegend funktioniert die "Suche" hier, aber ich denke fast das es einfach geht. Durch die While-Schleife lässt sich allerdings das else nicht nutzen. Im Moment hab ich keine Idee wie man das besser, anders lösen könnte. :(

So also dann - Feuer frei! :D
Benutzeravatar
hendrikS
User
Beiträge: 420
Registriert: Mittwoch 24. Dezember 2008, 22:44
Wohnort: Leipzig

AlphaX2 hat geschrieben:the hole list
Kein besonders wertvolles Feedback. Solltest Du aber trotzdem verbessern, wenn Du schon englische Kommentare verwendest.
frabron
User
Beiträge: 306
Registriert: Dienstag 31. März 2009, 14:36

Ein paar ungeordnete Gedanken:
global ist böse und an der Stelle auch unnötig. Du rufst "wto_function" ja schon mit dem Rückgabewert von raw_input auf, also musst du in der "wot_function" den Rückgabewert mit "choice" weiterverarbieten.

Die if/else Kaskaden kann man auch als Dictionary schreiben

Code: Alles auswählen

handler = {
    'a' : check_e,
    'c' : list_,
    ...
}
try:
    handler[choice]()
except KeyError:
    start()
In check_e: In Python handhabt man Dateien mit den with-statement, das sorgt auch dafür, dass die Datei wieder geschlossen wird, sobald kein Zugriff mehr erfolgt. Und über die Zeilen einer Datei kann man mittels einer for-Schleife iterieren

Code: Alles auswählen

with open("x.txt") as f:
    for line in f:
        print f
Desweiteren finde ich die Aufteilung deiner check_e's unlogisch. Ich würde mir wohl eine Funktion schreiben, die mir anhand eines Kriteriums eine Zeile aus einer Datei holt und in einer anderen die Ausgabelogik implementieren. Das kommt deinem Vorhaben einer Qt-GUI sicherlich auch entgegen.

Code: Alles auswählen

def search_in_file(param):
    with open() as e_file:
        for line in e_file:
            if line.startswith(param):
                return line
                
                
def print_e_code(e_code):
    print "this is pretty"
    print e_code
    print "--------------"
        
        
        
def get_code_info(code):
    result = search_in_file(code)
    # das hier könnte auch ein GUI - Fenster sein ...
    print_e_code(result)
Generell könntest du auch noch hier im Forum nach effektiveren Methoden suchen, Benutzereingaben in einer Schleife abzufragen, das geht sicher schöner, als mit deine verschachtelten check_e und check_e2 Tricks ...
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Noch ein paar Anmerkungen:

- Deine Namen sind kryptisch. Spätestens dann, wenn man einen Kommentar benötigt, um den Funktionsnamen zu erklären, hat man etwas falsch gemacht ;-)

- Zu Textmenüs haben wir hier unzählige Male etwas geschrieben. Versuche doch mal, da etwas über die Suchfunktion zu finden. Da bekommst Du dann noch mehr Varianten zu frabrons Vorschlag.

- Du solltest mal über eine passende Datenstruktur nachdenken, in der Du Deine Daten ablegst. Diese kannst Du beim Start einmal befüllen und musst dann nicht für jeden Zugriff eine Datei durchsuchen. Ich würde da eine Dictionary-Struktur vorschlagen:

Code: Alles auswählen

data = {
    "e100": {
        "name": "Kurkumin",
        "info": "Naturfarbstoff, orangegelb."
    },
    "e101": {
        ...
    }
}
Der Zugriff auf einen passenden Eintrag ist dann sehr einfach:

Code: Alles auswählen

# z.B. durch User Eingabe
key = "e100"
additive = data[key]
# und dann z.B.
print additive["name"]
- Diese Struktur kannst Du dann zudem ziemlich trivial in einer JSON-Datei speichern bzw. aus einer solchen generieren

- Falls es noch nicht gesagt wurde: Deine aktuelle `wto_function` beinhaltet eine ungewollte Rekursion (Aufruf von `start`) Für frabrons Variante dürfte das auch zutreffen.

- Du solltest Code auf Modulebene vermeiden. Benutze dieses Idiom:

Code: Alles auswählen

def main():
    pass

if __name__ == "__main__":
    main()
- Ich würde den Shebang universeller gestalten:

Code: Alles auswählen

#!/usr/bin/env python
Damit läuft das ganze auch auf Systemen, bei denen python nicht in /usr/bin enthalten ist oder durch PATH-Manipulation eine andere Version bevorzugt wird.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
AlphaX2
User
Beiträge: 53
Registriert: Dienstag 28. Juni 2011, 10:42

Erstmal: DANKE!!!

Ich bin ehrlich gesagt völlig geflasht von den ganzen Ideen und Ratschlägen. :D

Muss ich mir nochmal in Ruhe ansehen und durchdenken, gibt eben (leider) noch viele Sachen die ich entweder gar nicht kenne, oder wo ich nicht auf die Idee komme die so zu verwenden.

@Hyperion:
Daran das ganze als ein Dictionary oder so anzulegen hab ich auch schon gedacht - wollte aber erstmal mit der Datei rumspielen, auch weil man die dann einfach updaten kann - sprich nur die Zeile mit der neuen Nummer rein, sollte das mal kommen. Deine Ausgabe ist natürlich genial, weil man exakt ansteuern könnte was man will.

Eine Frage mal noch was ich nicht verstehe ist das folgende:
- Du solltest Code auf Modulebene vermeiden. Benutze dieses Idiom:

Code: Alles auswählen

def main():
    pass

if __name__ == "__main__":
    main()
Meint das quasi die Funktion aufzurufen, die aber nichts richtiges ausführen zu lassen und dann mit Schleife oder sowas zu starten! :?:

AlphaX2
frabron
User
Beiträge: 306
Registriert: Dienstag 31. März 2009, 14:36

Nein, Hyperion hat es nur unterlassen, Code in die main() Funktion zu schreiben, das ist dir überlassen. In deinem Fall hätte man, wenn nicht noch einiges zu restrukturieren wäre ;), auch

Code: Alles auswählen

if __name__ == '__main__':
    start()
schreiben können.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

AlphaX2 hat geschrieben: @Hyperion:
Daran das ganze als ein Dictionary oder so anzulegen hab ich auch schon gedacht - wollte aber erstmal mit der Datei rumspielen, auch weil man die dann einfach updaten kann - sprich nur die Zeile mit der neuen Nummer rein, sollte das mal kommen.
Naja, ich würde es mal so sagen: Datenstrukturen sind erst einmal wichtiger als Persistenz! Letztere ergibt sich ja oftmals basierend auf der Struktur (aber natürlich auch anderen Anforderungen).
Meint das quasi die Funktion aufzurufen, die aber nichts richtiges ausführen zu lassen und dann mit Schleife oder sowas zu starten! :?:
Nein. In die main()-Funktion kommt eben der Code Deines bisherigen Einstiegs (also die `start`-Funktion iirc). Diese wird durch das `if` auf Modulebene nur dann aufgerufen, wenn man das Modul als Script startet. Wenn Du das Modul in einem anderen Modul importierst, dann wird die `main`-Funktion nicht aufgerufen.

AlphaX2[/quote]
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Antworten