Bin neu hier und lerne ;-)

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.
Antworten
Blaster
User
Beiträge: 2
Registriert: Freitag 4. Januar 2013, 09:32

Hallo Gemeinde,

bin seit einigen Tagen hier angemeldet und absoluter Programmieranfänger.
Habe mir vorgenommen aus Spaß an der Freud ein wenig Python zu lernen.
Ich denke, da bin ich hier genau richtig :wink:

Um mir das gelernte ein wenig besser zu verdeutlichen habe ich mich an einem Rechen-"Parser" gewagt.
Ich bin irgendwie ziemlich erstaunt das ich das, wenn auch rudimentär, hinbekommen habe.

Anbei mein Code-Schnipsel des "Parser"
Vielleicht habt Ihr noch den ein oder anderen Verbesserungsvorschlag für mich!
Kann ich etwas vereinfachen oder sollte ich teile komplett anders gestalten?

Freue mich auf Eure positive Kritik und Anregung.

Grüße
Blaster

Code: Alles auswählen

#! /usr/bin/python
# -*- coding: utf-8 -*-

import re

print """
----------------------------------------------------------------------------
Es dürfen keine Leerzeichen zwischen Zahl und Operand stehen!
Am Ende der Formel muss ein = stehen.
Beispiel: 40*20/2+3= 
----------------------------------------------------------------------------
"""
formel = raw_input ("Bitte gebe die Formel ein: ")


#Ist ein = am Ende der Formel?
#Wie lang ist die Formel?
if formel[len(formel)-1] == "=":
    laenge = len(formel)
    
    #Formel in eine Liste uebertragen
    #formelListe = formel.split(" ")
    formelListe = (re.split(r'(\D+)',formel))
    
    
    #Feststellen wieviele Zahlen berechnet werden muessen
    #Wieviele Operatoren sind vorhanden?
    anzahlOps = 0
    anzahlWerte = 0
    for x in range(len(formelListe)):        
        if formelListe[x] == "*" or formelListe[x] == "/" or formelListe[x] == "+" or formelListe[x] == "-" or formelListe[x] == "=": 
            anzahlOps = anzahlOps + 1
        else:
            anzahlWerte = anzahlWerte +1
            
    #Ist die Formel in Ordnung?
    if anzahlOps >= anzahlWerte:
        print """
        ------------------------------------------
        In Deiner Formel befindet sich ein Fehler"
        ------------------------------------------
        """

    #Rechnen
    zs = float(formelListe[0])
    for x in range(len(formelListe)):
        if formelListe[x] == "*":
            zs = zs * float(formelListe[x+1])           
        if formelListe[x] == "/":
            zs = zs / float(formelListe[x+1])
        if formelListe[x] == "-":
            zs = zs - float(formelListe[x+1])
        if formelListe[x] == "+":
            zs = zs + float(formelListe[x+1])
                 
    print "Ergebnis:", zs
           
else:
    print """
    -----------------------------------------
    !!! ACHTUNG - Es ist kein = vorhanden!!!!
    Bitte starte das Programm neu.
    -----------------------------------------
    """
BlackJack

@Blaster: Python kennt bei Sequenzen negative Indizes um relativ zum Ende der Sequenz auf Elemente zuzugreifen. Also zum Beispiel ``formel[-1]`` um auf das letzte Element zuzugreifen. Allerdings haben Zeichenketten auch eine Methode um zu testen ob sie mit einer bestimmten Teilzeichenkette enden. Die hat den Vorteil, dass sie auch bei einer leeren Zeichenkette keine Ausnahme auslösen.

Zur Konvention zur Schreibweise von Namen könntest Du mal einen Blick in den Style Guide for Python Code werfen.

Konkrete Datentypen sollte man nicht in Namen verwenden, denn wenn man den Typ mal ändert, dann hat man entweder falsche und damit irreführende Namen im Quelltext, oder man muss die Namen überall ändern. Ausserdem sollte man Abkürzungen vermeiden die nicht allgemein bekannt sind.

Die Klammern um die rechte Seite von der Zuweisung an `formelListe` sind unnötig.

Quelltext der Form ``for i in range(len(sequence)):`` um dann mit `i` als Index auf die Elemente zuzugreifen ist in Python ein „anti pattern” weil man *direkt* über die Elemente iterieren kann, ohne den Umweg über einen Index. Falls man *zusätzlich* einen Index benötigt kann man die `enumerate()`-Funktion verwenden.

Statt der vielen ``or``\s hätte man einfach prüfen können ob das Element in einer Liste der Operatoren enthalten ist:

Code: Alles auswählen

    operatoren_anzahl = 0
    werte_anzahl = 0
    for token in formel_token:        
        if token in ['+', '-', '*', '/', '=']: 
            operatoren_anzahl += 1
        else:
            werte_anzahl += 1
Dein Test ob die Formel in Ordnung ist nicht ausreichend. Der wäre auch zutreffend wenn man '+-*/42' eingibt. Und vor allem machst Du selbst wenn der Test feststellt, dass die Formel *nicht* in Ordnung ist, einfach weiter als wäre nichts passiert.

Beim Ausrechnen könnte man eine Indexschleife schreiben die bei 1 beginnt und in Zweierschritten weitergeht, aber eleganter wäre auch hier den Index weg zu lassen und mit einem Iterator zu arbeiten und sich die Elemente die man erwartet/braucht mit `next()` holen. Man könnte sich den rudimentären Test vorher auch sparen und hier gleich die Fehlerbehandlung einbauen.

Statt ``if`` für jeden Operator zu verwenden, sollte man mit ``elif`` arbeiten. Wenn man einen Operator gefunden hat macht es keinen Sinn das gleiche Element auch noch auf die anderen Operatoren zu testen.

Der Parser/Rechner kennt keinen Operatorvorrang. Das konnten selbst billige Taschenrechner in den 80ern schon. ;-)

Statt das alles auf Modulebene zu schreiben, hätte man das in Funktionen aufteilen können, die man separat testen und wiederverwenden könnte.
Blaster
User
Beiträge: 2
Registriert: Freitag 4. Januar 2013, 09:32

Vielen Dank für Deine Anregungen,
werde das ganze dann mal versuchen umzusetzen.

Eines habe ich nicht ganz verstanden.
Wenn ich "meine" Variablen mit den Konventionen des Style Guide vergleiche, kann ich nichts "schlechtes" an meinen Variablen finden.
Oder meinst Du die Namensgebung an sich?


Grüße
Blaster
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Hallo,

was mir bezüglich Deiner Namensgebung auffällt:

formelListe -> formel_liste
Allerdings würde ich das gar nicht mehr an einen neuen Namen binden sondern einfach 'formel' beibehalten. Denn letztlich wandelst Du das, was an 'formel' gebunden ist ja nur in eine Liste um und arbeitest damit weiter.

anzahlOps -> anzahl_ops
Mein Vorschlag: 'operations'

anzahlWerte -> anzahl_werte
Mein Vorschlag: 'values'

zs -> Was verbirgt sich dahinter? Und: Weißt Du das auch in 2 Wochen noch? :wink:

Generell würde ich Dir auch raten, englische Begriffe für Deine Namen zu verwenden. Im Laufe der Zeit wirst Du sehen, dass sich für vieles bereits gängige (englische) Namen durchgesetzt haben und auch verwendet werden sollten. Damit versteht ein Außenstehender Deinen Code oftmals besser.
BlackJack hat es ja auch schon gesagt: Was sich für eine Datenstruktur hinter dem Namen verbirgt sollte sich nicht im Namen wiederfinden. Eine Nummer nenne ich z. B. 'number'. Sollte es sein, dass es auch mehr Nummern werden könnten oder schon sind, nenne ich das einfach 'numbers'.

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@mutella: Naja, die "Rechenzeichen" heißen schon "Operatoren", nicht "Operationen". Letzteres steht eher für die konkrete Durchführung eine bestimmten Berechnung. An der Stelle geht es jedoch erstmal um die Analyse der Zeichen bzw Tokens. Auch eine Benennung mit "Anzahl" (engl. meist "num") finde ich nicht verkehrt, dass man ja keine Auflistung von Operatoren hat, sondern deren Vorkommen zählen möchte.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Das leidige Thema Syntax der Namensgebung :D
Die Diskussion um Unterstrich- oder CamelCase-Notation kommt bei uns auch immer mal wieder auf. Der Styleguide von Python empfiehlt zwar die Unterstriche, ich würd das allerdings nicht so eng sehen und eher von den Rahmenbedingungen abhängig machen:
- will man was zur Pythonwelt beitragen --> an Sprachkonvention halten
- braucht man es intern --> auf Teamvorlieben bzw. Bibliothekabhängigkeit Rücksicht nehmen (z.B. Qt kommt CamelCase'd daher)
Gerade bei letzterem zeigt sich, dass die Leute von Java/C++/Obj-C kommend eher CamelCase bevorzugen.
BlackJack

@jerch: Eine CamelCase-Diskussion findet man $GOTT sei Dank selten und auch bei C++/C#/Java/… macht man das ja nicht für die Namen um die es hier geht. Gegen CamelCase für etwas anderes als Klassennamen würde ich ganz entschieden sein. Bei den verbreiteten Sprachen kenne ich das nur von BASIC-Dialekten und Pascal. C++/C#/Java/… verwendet ausser für Klassen (und Konstanten) mixedCase.

Ich verstehe nicht so wirklich warum es so schwer ist sich an Konventionen zu halten. Bei Java verwenden die Leute doch auch keine_kleinbuchstaben_mit_unterstrichen sondern halten sich an die Gepflogenheiten dort. Und zwar ohne Diskussionen.

Bei Anbindungen an externe Bibliotheken, die in anderen Programmiersprachen geschrieben sind, ist es einfach nur pragmatisch die Namensgebung des Originals beizubehalten. Das kann man gerade bei GUIs auch ganz gut dazu verwenden um die Trennung GUI und Programmlogik durch die Namensgebung deutlich zu machen.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

@jerch: Dein letzter Punkt ist doch kein Argument gegen die Verwendung des typischen Styles einer Sprache, sondern gegen die betreffenden Entwickler. Natürlich gibt es Situationen, in denen das Abweichen vom Standard sinnvoll ist: z.B. wenn man eine C++-Bibliothek ganz direkt wrapped oder wenn das zu erweiternde Modul bereits signifikant vom Standard abweicht.

Dein Argument klingt aber eher nach: warum sollten die armen Programmierer noch einen Style lernen, die kennen doch schon einen aus einer anderen Programmiersprache. Dabei ist die Formatierung des Quelltext viel mehr als ein wenig Dekoration. Typischerweise impliziert eine bestimmte Schreibweise oder ein bestimmtes Muster noch einige Informationen. Wenn man nach Hilfe sucht oder durch die Dokumentation geht, dann kann dieses Wissen enorm Hilfreich sein.

Hinzu kommt natürlich noch, dass jede Sprache auch eine gewisse Umwelt mitbringt. Typischerweise halten sich die mitgelieferten Module sehr nah am Standard. Mischt man das ganze nun noch mit seinen eigenen Standards, dann führt das gerne mal zu unübersichtlichem Quelltext, bzw. zu einem Mix verschiedenster Standards.
Das Leben ist wie ein Tennisball.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@BlackJack und EyDu:
Naja, vllt liegts an "Was der Bauer nicht kennt..." - die Camel/mixedCase-Sache ist durch Java & Co. doch recht verbreitet. Die Unterstrich-Notation kenn ich eher von C her, und da "verliert" diese Form wohl gegen die Omnipräsenz in der Lehre von Java & Co. und macht Camel/mixedCase zum Quasistandard. Zumindest ein Erklärungsversuch, warum sich manche Leute so schwer tun damit und die Pythonempfehlung zuerst als fremdartig wahrnehmen.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

jerch hat geschrieben:Die Unterstrich-Notation kenn ich eher von C her, und da "verliert" diese Form wohl gegen die Omnipräsenz in der Lehre von Java & Co. und macht Camel/mixedCase zum Quasistandard.
Quasistandard? Würde ich nicht unbedingt sagen, wenn ich mit so übliche Libraries anschaue sind die meist mit Underscores und manchmal auch alles zusammengeschieben. mixedCase sehe ich in C extrem selten und da ists dann meist auch jemand der nicht so Ahnung hat, der das so schreibt.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@Leonidas:
Ok, war vllt etwas missverständlich ausgedrückt. Was ich meinte, war, dass man in C kaum mixedCase findet (systemnah unter Windows sieht man z.B. noch viel Camel und mixedCase Varianten der ungarischen Notation) und die Unterstriche recht häufig anzutreffen sind.
So haben, bezogen auf die ersten 10 Sprachen des Tiobe-Indexes, eigentlich nur C, PHP und Python eine gewisse Unterstrichvorliebe. Das war mit Omnipräsenz von Java und Co gemeint.
Antworten