Eingabe interpretieren

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
Benutzeravatar
jonas
User
Beiträge: 156
Registriert: Dienstag 9. September 2008, 21:03

Nabend,
erstmal hallo an alle im Forum!
Freue mich dabei zu sein. ;-)
ich bin noch neu in der Pythonwelt,
habe bereits das einschlägig angepriesene Tutorial
angefangen jedoch noch nicht vollendet.
Habe jetzt eine Frage:
Ich würde gerne ein Programm schreiben, welches mit
dem sog. Sehnentrapezverfahren ein Integral näherungsweise
bestimmen kann.
Bin bis zu dem Punkt gekommen an dem ich mich frage:
Wie kann das Programm die Eingabe des Benutzers interpretieren
(z.B. x**2 )?
Da kriege ich nur 3 Fragezeichen.
Ich habe bereits mit verschiedenen Sucheingaben die SuFu gequält,
jedoch meiner Meinung nach nichts passendes zum Thema gefunden.
Wenn ihr von einem Thema wisst oder auf eins stoßt könntet ihr es mir
ja melden.
Hier den Code von meinem bisherigen Programm:
(Die Python-Gurus dürfen mich gern zerreißen...:"Modulebene..."etc. Wenn ihr es nicht tut werde ich es langsamer lernen also nur zu!)

Code: Alles auswählen

##Hiermit sollen Integrale numerisch durch das Sehnentrapezverfahren angen?hert werden

import math, os

beenden=True

print """
*******************************
*  Integralannaeherung durch  *
*   Sehnentrapezverfahren     *
* (Fuer weitere Informationen *
*   einfach "info" eintippen) *
*******************************
"""
def was_soll_ich_machen():
    global beenden
    was_tun=raw_input("Bitte eingeben was zu tun ist:")
    try:
        was_tun=str(was_tun)
    except:
        pass
    if (was_tun=="info"):
        print """
        *****************************************************
        *  Version: v 0.1                                   *
        *  Author: Jonas W.                                 *
        *  Moegl. Eingaben:                                 *
        *   "info" : Hilfe                                  *
        *   "eingabe" : Um einen Term einzugeben            *
        *   "auswertung" : Um den letzten Term auszuwerten  *
        *   "exit" : Um das Programm zu beenden             *
        *****************************************************
        """
    elif (was_tun=="exit"):
        beenden=False
    elif (was_tun=="eingabe"):
        term_eingabe()
    elif (was_tun=="auswertung"):
        term_auswertung()
    else:
        pass

def term_eingabe():
    term=raw_input("Bitte Funktionsterm eingeben:")
    o_grenze=raw_input("Bitte obere Grenze eingeben:")
    u_grenze=raw_input("Bitte untere Grenze eingeben:")
    anz_str=raw_input("Bitte Anzahl Streifen eingeben:")
    betr_o_grenze=0
    betr_u_grenze=0
    streifenbreite=0.0
    
    try:
        o_grenze=str(o_grenze)
    except:
        pass
    try:
        u_grenze=str(u_grenze)
    except:
        pass
    try:
        anz_str=int(anz_str)
    except:
        pass
    
    if (u_grenze[0]=="-"):
        betr_u_grenze=int(u_grenze)*(-1)
    else:
        betr_u_grenze=int(u_grenze)
    
    if (o_grenze[0]=="-"):
        betr_o_grenze=int(o_grenze)*(-1)
    else:
        betr_o_grenze=int(o_grenze)

    if (int(o_grenze) & int(u_grenze) > 0):
        streifenbreite=(float(betr_o_grenze)-float(betr_u_grenze))/float(anz_str)
    elif (int(o_grenze) & int(u_grenze) < 0):
        streifenbreite=(float(betr_o_grenze)-float(betr_u_grenze))/float(anz_str)
    else:
        streifenbreite=(float(betr_o_grenze)+float(betr_u_grenze))/float(anz_str)
        
    print "Funktionsterm: "+term
    print "Obergrenze: "+o_grenze
    print "Untergrenze: "+u_grenze
    print "Anzahl Streifen: ",anz_str
    print "Betrag Obergrenze: ",betr_o_grenze
    print "Betrag Untergrenze: ",betr_u_grenze
    print "Streifenbreite: ",streifenbreite
    pass


def term_auswertung():
    streifenbreite_test=0.0 ##Bitte hier nicht wundern ist nur zu Dummy-
    if (streifenbreite_test==0.0): ##Zwecken da.
        print "Zuerst muss ein Term eingegeben werden!"
        pass
    else:
        pass


while (beenden == True):
        was_soll_ich_machen()




Über Anregungen und Verbesserungen zum Code würde ich mich sehr freuen, wenns geht erstmal die nicht ganz so komplizierten.
Mit freundlichen Grüßen
Jonas
BlackJack

Tja Code auf Modulebene: Nicht gut. In einer "Hauptfunktion" verschwinden lassen, zum Beispiel `main()` und so aufrufen:

Code: Alles auswählen

if __name__ == '__main__':
    main()
Dann wird der Code nur ausgeführt, wenn man die Datei als Programm ausführt, aber nicht, wenn man es von einem anderen Modul oder im Interpreter importiert um einzelne Funktionen "live" zu testen.

Klammern um Bedingungen sind nicht nötig und sollten nur gesetzt werden um Operatorvorrang deutlicher zu machen oder eine Auswertungsreihenfolge zu erzwingen. Leerzeichen um binäre Operatoren und Zuweisungen machen den Quelltext leichter lesbar.

``global`` ist Böse™, vergiss am besten sofort die Existenz dieses Schlüsselwortes. Werte betreten und verlassen Funktionen über Argumente und ``return``.

``else: pass`` ist überflüssig.

Ein ``except`` sollte nicht ohne konkrete Ausnahme verwendet werden und in der Regel auch eine Behandlung der Ausnahme beinhalten und nicht einfach nur ``pass``. Du "verschluckst" damit sämtliche Fehler die zur Laufzeit im ``try``-Block auftreten können, inklusive Tippfehler bei Namen oder Attributen.

Zumal Deine ``try``/``except``-Blöcke fast alle Nulloperationen enthalten. `raw_input()` gibt eine Zeichenkette zurück und Du wandelst die fast immer nochmal in eine Zeichenkette um. Das hat keinen Effekt und was für Fehler erwartest Du denn da bitte?

Einzige Ausnahme ist `anz_str`, dass in einem ``try``/``except``-Block in ein `int` umgewandelt wird. Falls das nicht funktioniert, ignorierst Du den Fehler einfach, womit aber gar nichts gewonnen ist, denn später in der Funktion kracht es dann, wenn Du `anz_str` als Zahl verwenden willst.

Für den Betrag gibt es bereits eine eingebaute Funktion: `abs()`. Selbst wenn es die nicht gäbe, sollte man sie über Zahlen implementieren und nicht bei der Zeichenketteneingabe schauen ob da ein '-' als erstes Zeichen steht.

Der ``&`` Operator ist eine Bitverknüpfung von ganzen Zahlen, auch wenn das oft funktioniert, ist für Bool'sche Verknüpfungen das Schlüsselwort ``and`` gedacht. Ausserdem fällst Du da anscheinend auf die umgangssprachliche Doppeldeutigkeit von "wenn x und y grösser Nulls sind" herein. Das ist *nicht* ``if x and y > 0:`` denn der Grössenvergleich bindet stärker als das ``and``. Die Bedingung wird so ausgewertet: ``if x and (y > 0):``.

Das Problem würde ich aber sowieso anders lösen. Entweder Ober- und Untergrenze vertauschen, wenn Obergrenze kleiner als Untergrenze ist, oder bei der Berechnung von `streifenbreite` die Betragsfunktion verwenden um ein positives Ergebnis zu erzwingen.

Wahrheitswerte in Bedingungen explizit auf `True` oder `False` zu testen, wird im allgemeinen als schlechter Stil angesehen, weil der Test redundant ist. Und der Name `beenden` ist schlecht gewählt. Die Schleife sagt ja: "Solange "beenden" wahr ist, mache folgendes…", das klingt genau falsch herum.

Für den Ausdruck, der vom Anwender eingegeben werden kann, schau Dir mal `compile()` und `eval()` an.
Benutzeravatar
jonas
User
Beiträge: 156
Registriert: Dienstag 9. September 2008, 21:03

Hallo Blackjack, :D
erstmal vielen Dank für deine Antwort.
Das das Programm noch nicht gut ist, war mir klar:
Ich versuche mich heute daran zu setzen mich weiter einzuarbeiten
und möglichst viele Verbesserungsvorschläge umzusetzen ;-)
Also schon mal vielen Dank für das Auseinanderpflücken von
meinem Code.
Danach poste ich eine überarbeitete Version.
Also machs gut,
Mit freundlich Grüßen
Jonas

PS: Ich denke nur so lernt man es.... :lol:
Benutzeravatar
jonas
User
Beiträge: 156
Registriert: Dienstag 9. September 2008, 21:03

Hi!
Wollte jetz mal die neue Version posten:
Bitte Anregungen, Fragen alles gern gesehen ;-)
Hier habt ihr wieder was zu zerreissen GURUS!
Bitte auch Vergleich zum ersten Code!

Code: Alles auswählen

##IMPORT
import math
##Funktionen
def funktion_enter():
    funktionsterm=raw_input("Funktionsterm>>>")
    return funktionsterm

def o_grenze_enter():
    o_grenze=raw_input("Obergrenze>>>")
    o_grenze=int(o_grenze)
    return o_grenze

def u_grenze_enter():
    u_grenze=raw_input("Untergrenze>>>")
    u_grenze=int(u_grenze)
    return u_grenze

def anz_str_enter():
    anz_str=raw_input("Anzahl Streifen>>>")
    anz_str=float(anz_str)
    return anz_str

def streifenbreite(o_grenze,u_grenze,anz_str):
    betr_o_grenze=abs(o_grenze)
    betr_u_grenze=abs(u_grenze)
    
    if o_grenze>0 and u_grenze>0:
        streifenbreite=(float(betr_o_grenze)-float(betr_u_grenze))/float(anz_str)
    elif o_grenze<0 and u_grenze<0:
        streifenbreite=(float(betr_o_grenze)-float(betr_u_grenze))/float(anz_str)
    else:
        streifenbreite=(float(betr_o_grenze)+float(betr_u_grenze))/float(anz_str)
    return streifenbreite

def funktion_use(funktionsterm,x):
    pi=3.141592654
    funktionswert=eval(funktionsterm)
    return funktionswert

def funktionen_aufrufen():
    x=0.0
    y=0.0
    y_alt=0.0
    z=0
    m=0.0
    streifenbreite_r=0.0
    funktionsterm=funktion_enter()
    o_grenze=o_grenze_enter()
    u_grenze=u_grenze_enter()
    anz_str=anz_str_enter()
    streifenbreite_r=streifenbreite(o_grenze,u_grenze,anz_str)
    while x!=o_grenze:
        x=u_grenze+streifenbreite_r*z
        z=z+1
        y=funktion_use(funktionsterm,x)
        m=(1/anz_str)*(y_alt+y)
        y_alt=y
        print x,"   ",y,"   ",m
   
##Funktionsaufruf
while True:
    funktionen_aufrufen()
    
Mit freundliche Grüßen
Jonas
PS: Schönes Wochenende!
Könnte man vllt auch zum Benchmark benutzen, Grenzen +100000 und -1000000 und ne tolle Funktion und dann Zeit abwarten^^
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Das sieht auf jeden Fall schonmal ein ganzes Stück besser aus!

Wenn du nicht vorhast, die Funktionalität der vier Funktionen für die Eingabe von Term und Eckdaten noch zu erweitern, dann würde ich auf diese Funktionen ganz verzichten, weil sich deren gesamte Funktionalität in einer Zeile innerhalb von funktionen_aufrufen realisieren lässt und den Quelltext sicher nicht schlechter lesbar macht. Also z.B.:

Code: Alles auswählen

u_grenze = int(raw_input("Untergrenze>>>"))
an Stelle der entsprechenden Funktion.

Und: Bei Zuweisungen links und rechts des Gleichheitszeichens noch ein Leerzeichen lassen.

Und einfach:

Code: Alles auswählen

streifenbreite = (o_grenze-u_grenze)/float(anz_str)
Die ganzen Fallunterscheidungen und damit die gesamte Funktion streifenbreite() sind nicht nötig ... :wink:
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Etwas gekürzt aber natürlich ungetestet ;-) :

Code: Alles auswählen

import operator 
import math 

def funky(text, func=lambda x: x): 
    return func(raw_input(text + ">>>"))


def streifenbreite(o_grenze, u_grenze, anz_str): 
    op = operator.sub if o_grenze*u_grenze > 0 else operator.add 
    return op(abs(o_grenze), abs(u_grenze)) / anz_str 


def la_function: 
    x, y_alt, z = 0.0, 0.0, 0 
    
    funktionsterm = funky("Funktionsterm")
    o_grenze = funky("Obergrenze", int)
    u_grenze = funky("Untergrenze", int)
    anz_str = funky("Anzahl Streifen", float)
    breite = streifenbreite(o_grenze,u_grenze,anz_str) 
    
    while abs(x-o_grenze)>=0.0001:
        x = u_grenze + breite*z 
        z += 1 
        y = eval(funktionsterm, math.__dict__, {"x":x}) 
        m = (1/anz_str)*(y_alt+y) 
        y_alt = y 
        
        print "%f    %f    %f" % (x, y, m) 


if __name__ == "__main__": 
    while True: 
        la_function()
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

Ich werde auch mal ein wenig 'zerreissen': :wink:

Wie berechnest Du das Integral nach der Trapez-Methode?
Was macht das 'm' ?
Warum benutzt Du das 'x' als Kontrollvariable und
iterierst nicht über die *Anzahl* der Streifen?
In welcher Sprache willst Du programmieren
(UK-Englisch, US-Englisch, Deutsch, Denglisch,...)?

Tip(p)s:

Das Programm nach dem Eingabe-Verarbeitung-Ausgabe-Prinzip
organisieren, diese Bausteine sollten unabhängig voneinander
lauffähig sein.

Sinnvolle Namen erleichtern nicht nur das spätere Lesen,
sondern sind auch für eine gute Programmplanung unabdingbar.

Mehr Listen, Tupel und Dictionaries verwenden.

Die Anzahl der Rechenschritte hängt nicht von den Grenzen,
sondern von der Anzahl der Streifen ab.


Die 3. Version wird noch besser.
Und erst die 4. ...

:wink:
yipyip
Benutzeravatar
snafu
User
Beiträge: 6732
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Du musst übrigens auch nicht kommentieren, dass jetzt ein Import oder die Funktionen kommen. Das sieht man auch so. ;)
Benutzeravatar
name
User
Beiträge: 254
Registriert: Dienstag 5. September 2006, 16:35
Wohnort: Wien
Kontaktdaten:

Vom ueberfliegen scheints als wuerde dir das cmd Modul helfen.

Code: Alles auswählen

cmd - A generic class to build line-oriented command interpreters.
Ohloh | Mein Blog | Jabber: segfaulthunter@swissjabber.eu | asynchia – asynchrone Netzwerkbibliothek

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.
Benutzeravatar
jonas
User
Beiträge: 156
Registriert: Dienstag 9. September 2008, 21:03

Hallo!
Da die Trapezregel folgender Maßen geht,
Bild
(hierzu siehe:http://de.wikipedia.org/wiki/Trapezregel
außerdem: a ist der Beginn auf der x-Achse, b das Ende)
sollte klar sein, das m jeweils den Flächeninhalt eines Trapezes darstellt.
Habe den unteren Abschnitt noch nicht euren Angaben entsprechend geändert sry. Die oben vorgeschlagene Änderung mit "Lambda", hat sich
mir leider noch nicht erschlossen... :oops:
Habe nur noch eingebaut, dass aus den Trapezen auch ein mittlerer Flächeninhalt gebildet wird, der ein Näherungwert des jeweiligen Integrals darstellt...

Code: Alles auswählen

def funktionen_aufrufen():
    x=0.0
    y=0.0
    y_alt=0.0
    z=0
    m=0.0
    mittelwert=0.0
    streifenbreite_r=0.0
    funktionsterm=funktion_enter()
    o_grenze=o_grenze_enter()
    u_grenze=u_grenze_enter()
    anz_str=anz_str_enter()
    streifenbreite_r=streifenbreite(o_grenze,u_grenze,anz_str)
    while x!=o_grenze:
        x=u_grenze+streifenbreite_r*z
        z=z+1
        y=funktion_use(funktionsterm,x)
        m=(1/anz_str)*(y_alt+y)
        y_alt=y
        mittelwert=mittelwert+m
        print x,"   ",y,"   ",m
    print "\nMITTELWERT: ",mittelwert
Zur Sprache:
Wollte die Bezeichnungen etc. erst Englisch machen aber hatte
sich dann irgendwie ergeben, dass sie teilweise doch wieder
Deutsch geworden sind
ERGEBNIS: Denglisch
Zu Kommentaren:
Stört ich nich weiter dran sind mehr für mich^^

Werde in den nächsten Tagen nochmal weiter machen und
sehen, was sich noch umsetzen lässt...
Melde mich dann wieder!
MitFreundlichenGrüßen Jonas :D
BlackJack

Die ``while``-Schleife solltest Du durch eine ``for``-Schleife über die Nummer des gerade berechneten Streifens ersetzen. Auf jeden Fall solltest Du nicht Fliesskommazahlen auf exakte (Un)Gleichheit testen, da die Berechnungen mit diesem Datentyp Ungenauigkeiten aufweisen können und Du so unter Umständen eine Endlosschleife im Programm hast.
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

Was Du mit 'm' berechnen *willst*, ist mir schon klar gewesen,
wollte Dir nur den Tip geben, Deine Berechnungen
noch einmal zu ueberdenken.

Sollte es nicht
m = streifenbreite_r * (y + y_alt) / 2
heissen ?

Vor der Schleife musst Du auch noch
y_alt = meine_funktion(u_grenze)
setzen.

Das 'eval()' ist zugegebenermassen ein etwas
fortgeschritteneres Thema,
an Deiner Stelle wuerde ich das Programm
zunächst mit einer 'fest verdrahteten' Funktion
testen, z.B. sin(x), 2 * x, o.ä. .

:wink:
yipyip
Benutzeravatar
jonas
User
Beiträge: 156
Registriert: Dienstag 9. September 2008, 21:03

Hi Leute!
Habe leider fatalen Denkfehler eingebaut!
Richtig muss das nämlich so heißen :

Code: Alles auswählen

def funktionen_aufrufen():
    x=0.0
    y=0.0
    y_alt=0.0
    z=0
    m=0.0
    mittelwert=0.0
    streifenbreite_r=0.0
    funktionsterm=funktion_enter()
    o_grenze=o_grenze_enter()
    u_grenze=u_grenze_enter()
    anz_str=anz_str_enter()
    streifenbreite_r=streifenbreite(o_grenze,u_grenze,anz_str)
    while x!=o_grenze:
        x=u_grenze+streifenbreite_r*z
        z=z+1
        y=funktion_use(funktionsterm,x)
        m=((o_grenze-u_grenze)/anz_str)*((y_alt+y)/2)
        y_alt=y
        mittelwert=mittelwert+m
        print x,"   ",y,"   ",m
    print "\nMITTELWERT: ",mittelwert
Mit Freundlichen Grüßen
Jonas
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Für die Eingabe könnte man sowas machen:

Code: Alles auswählen

def input2(text, func):
    while True:
        try:
            return func(raw_input("%s (%s): " % (text, func.__name__)))
        except ValueError, e:
            print "Eingabefehler:", e

funktionsterm = input2("Funktionsterm", str)
o_grenze = input2("Obergrenze", int)
u_grenze = input2("Untergrenze", int)
anz_str = input2("Anzahl Streifen", float)
Wobei repr(func).split("'")[1] schon etwas unschön ist, da fällt mir aber nix besseres ein ;)

EDIT (jens): repr(func).split("'")[1] durch func.__name__ ersetzt.
Zuletzt geändert von jens am Donnerstag 18. September 2008, 11:59, insgesamt 1-mal geändert.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten