Hallo, ich bin sowohl in diesem Forum als auch in der Python-Programmierung neu. Darum soll es jetzt aber garnicht gehen, nämlich um folgendes: Wie gesagt bin ich noch ziemlich bei den Anfängen, habe ein Buch welches eig. gut und ausführlich erklärt. Aufgaben sind auch enthalten, nur folgende machen mir sehr zu schaffen:
1. Man soll eine Funktion zeichne(figur, laenge) definieren, die entweder ein Dreieck oder ein Quadrat mit gewünschter Seitenlänge zeichnet. Ein möglicher Aufruf soll so aussehen: figur("quadrat", 150) (Oder anstelle von "quadrat" eben "dreieck")
2. Man soll ein Programm schreiben, dei dem der User eine Zahl zwischen 1 und 100 eingibt und diese dann als Zahlwort ausgegen wird. (Also z.B. der Nutzer gibt 43 ein und es wird "dreiundvierzig" ausgegeben.
Ich frag mich dabei ob ich einen gewaltigen Logikfehler habe und fürs Programmieren einfach nicht gemacht wurde oder ich mit meinem bisherigen Wissen diese Aufgaben einfach noch nicht lösen kann. Die ganzen "Standardanweisungen" wie eben print() input(), if - else, def(), .format() wurden schon erklärt, aber ich komme damit einfach nicht weiter.
Wäre euch sehr dankbar wenn mir jemand erklären könnte wie auch auch von mir aus nur eine der Aufgaben lösen kann.
Mfg,
Gulash
Frage eines Anfängers
Hallo gulash willkommen im Forum,
hast du schon mal hier nach Lösungen für deine Aufgaben geschaut? Erst letztens gab es einen Beitrag, der alles für deine Aufgabe 2 behandelt hat.
hast du schon mal hier nach Lösungen für deine Aufgaben geschaut? Erst letztens gab es einen Beitrag, der alles für deine Aufgabe 2 behandelt hat.
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
Da fehlt eine Angabe, nämlich womit, also mit welcher Grafikbibliothek, soll man zeichnen?gulash hat geschrieben:1. Man soll eine Funktion zeichne(figur, laenge) definieren, die entweder ein Dreieck oder ein Quadrat mit gewünschter Seitenlänge zeichnet. Ein möglicher Aufruf soll so aussehen: figur("quadrat", 150) (Oder anstelle von "quadrat" eben "dreieck")
Hier wäre eine Lösung für tkinter mit python3
Code: Alles auswählen
# -- python 3 ------
import tkinter as tk
from threading import Thread
class Application(tk.Tk):
def __init__(self,**kwargs):
tk.Tk.__init__(self,**kwargs)
self.canvas = tk.Canvas(self,bg = 'white',width=400,height=400)
self.canvas.pack()
self.parameters = None
self.after(1000,self.call_function)
def zeichne(self,figur,laenge):
if figur == "quadrat":
x0 = 10
y0 = 10
x1 = x0 + laenge
y1 = y0
x2 = x0 + laenge
y2 = y0 + laenge
x3 = x0
y3 = y0 + laenge
self.canvas.create_line(x0,y0,x1,y1,x2,y2,x3,y3,x0,y0)
# einfacher ginge es mit
# self.canvas.create_rectangle(x0,y0,x0+laenge,y0+laenge)
# aber mit dem Dreieck muss man es mit create_line machen
elif figur == "dreieck":
# selber machen
pass
def call_function(self):
if self.parameters != None:
self.canvas.delete(tk.ALL)
self.zeichne(self.parameters[0],self.parameters[1])
self.parameters = None
self.after(100,self.call_function)
root = Application()
def eingabe():
figuren = { 'q' : 'quadrat', 'd' : 'dreieck' }
while True:
figur_buchstabe = input("quadrat = q, dreieck = d : ")
if figur_buchstabe == '':
break
if figur_buchstabe in figuren:
figur = figuren[figur_buchstabe]
else:
print('\n? Fehler: falsche Eingabe\n')
continue
while True:
abbruch = False
laenge_string = input("laenge: ")
if laenge_string == '':
abbruch = True
break
try:
laenge = int(laenge_string)
break
except ValueError:
print('\n? Fehler: das war keine Zahl\n')
if abbruch:
break
print()
root.parameters = (figur,laenge) # zeichne
root.quit()
Thread(target=eingabe).start()
root.mainloop()
@Alfons Mittelmeyer: ein GUI-Programm mit Kommandozeileneingaben zu kombinieren ist seltsam. Eingaben von einem Thread aus zu machen, riskant. Die eingabe-Funktion enthält viel zu viele Leerzeilen und zu viel Code. Ein paar mehr Funktionen könnten nicht schaden, dann braucht es auch keine Flags oder continue. Parameter aus anderen Threads heraus zu setzen ist ein Fehler. Dafür gibt es Queues.
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
In diesem Falle braucht es aber keine Queue, denn der Benutzer kann gewiß nicht so schnell eine neue Eingabe machen, wie die Figur gezeichnet wird. Ganz gewiß macht der Benutzer keine neue Eingabe in einer Zehntelsekunde!Sirius3 hat geschrieben:Parameter aus anderen Threads heraus zu setzen ist ein Fehler. Dafür gibt es Queues
Außerdem ist die Eingabe nur zum Testen gedacht
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
@Sirius3: so übersichtlicher?
Durch die Funktion eingabeschleife kann man sich das Flag ersparen, weil man auch aus der inneren Schleife heraus durch return abbrechen kann. Die erste innere Schleife ist nur wegen der Symmetrie zur zweiten, weil das dann übersichtlicher ist.
Code: Alles auswählen
# -- python 3 ------
import tkinter as tk
from threading import Thread
class Application(tk.Tk):
def __init__(self,**kwargs):
tk.Tk.__init__(self,**kwargs)
self.canvas = tk.Canvas(self,bg = 'white',width=400,height=400)
self.canvas.pack()
self.parameters = None
self.after(1000,self.call_function)
def zeichne(self,figur,laenge):
if figur == "quadrat":
x0 = 10
y0 = 10
x1 = x0 + laenge
y1 = y0
x2 = x0 + laenge
y2 = y0 + laenge
x3 = x0
y3 = y0 + laenge
self.canvas.create_line(x0,y0,x1,y1,x2,y2,x3,y3,x0,y0)
# einfacher ginge es mit
# self.canvas.create_rectangle(x0,y0,x0+laenge,y0+laenge)
# aber mit dem Dreieck muss man es mit create_line machen
elif figur == "dreieck":
# selbermachen
pass
def call_function(self):
if self.parameters != None:
self.canvas.delete(tk.ALL)
self.zeichne(self.parameters[0],self.parameters[1])
self.parameters = None
self.after(100,self.call_function)
root = Application()
def eingabeschleife():
figuren = { 'q' : 'quadrat', 'd' : 'dreieck' }
while True:
while True:
figur_buchstabe = input("quadrat = q, dreieck = d : ")
if figur_buchstabe == '':
return
if figur_buchstabe in figuren:
figur = figuren[figur_buchstabe]
break
else:
print('\n? Fehler: falsche Eingabe\n')
while True:
laenge_string = input("laenge: ")
if laenge_string == '':
return
try:
laenge = int(laenge_string)
break
except ValueError:
print('\n? Fehler: das war keine Zahl\n')
print()
root.parameters = (figur,laenge) # zeichne
def eingabe():
eingabeschleife()
root.quit()
Thread(target=eingabe).start()
root.mainloop()
@gulash: der hier präsentierte Code ist wieder einmal mit Vorsicht zu genießen. Zum einen sind Threads nichts für Anfänger, denn ein threadsicheres Programm zu schreiben ist nicht leicht. Und wenn es dennoch um Threads geht, dann sollte als erstes gezeigt werden, warum der Zugriff mehrerer Threads auf einen gemeinsamen Namensraum ohne Locks schlecht ist, wo die Vorzüge aber auch Probleme von Locks liegen, und welche Lösungen es zur Kommunikation gibt, z.B. Queues. Auf die Nutzung von Threads solltest Du zunächst besser verzichten.
@Alfons Mittelmeyer: es geht hier doch nicht darum, wie schnell jemand tippen kann, sondern dass generell keine gemeinsamen Zustände zwischen verschiedenen Threads existieren dürfen. Ähnlich, wie dass man bei globalen Variablen keinen Überblick hat, wer was wann ändert, ist bei Threads mit gemeinsamen Zuständen nicht nachzuvollziehen wer wann was ändert. Zudem ist root eine globale Variable, siehe anderen Thread. root.quit darf auch aus dem Eingabethread heraus nicht aufgerufen werden!
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
Warum alles als generell ansehen und daraus ein Dogma machen? Es ging nur darum, dass der User gulash es ausprobieren kann. Und ihn auch noch mit Queues und events zu konfrontieren sprengt den Rahmen für einen Anfänger.Sirius3 hat geschrieben:@Alfons Mittelmeyer: es geht hier doch nicht darum, wie schnell jemand tippen kann, sondern dass generell keine gemeinsamen Zustände zwischen verschiedenen Threads existieren dürfen.
Wichtig ist jedenfalls:
Man darf von einem Thread keine Funktionen eines anderen Threads aufrufen. Und normalerweise auch auf keine Variablen des anderen Threads zugreifen. Im vorliegenden Fall macht es nichts aus, weil man nicht so schnell neue Eingabe machen kann, und wenn es vielleicht hier in diesem Fall doch crashen würde? Na und? Ist eh nur zum Ausprobieren. Jedenfalls besser, als das Programm jedes mal neu zu starten.
@gulash, wenn Du mittels Programm mehr in den Canvas hineinschreiben wolltest, dann bitte nicht mit dem Verfahren, das für die Eingabe benutzt wurde, sondern in der __init__ Methode von class Application!!!
Besser als zweimal Strg C zu drücken.Sirius3 hat geschrieben:root.quit darf auch aus dem Eingabethread heraus nicht aufgerufen werden!
Warum soll man dem Fahranfänger zeigen, wo die Bremse ist? Das macht das Fahren für den Anfang nur kompliziert. Solange er weiß, wo das Gaspedal ist, reicht das ja, weil so kann er wenigstens mal losfahren. Wird schon kein Auto an der nächsten Kreuzung kommen.Alfons Mittelmeyer hat geschrieben:Es ging nur darum, dass der User gulash es ausprobieren kann. Und ihn auch noch mit Queues und events zu konfrontieren sprengt den Rahmen für einen Anfänger.
@Alfons Mittelmeyer: GUI-Rahmenwerke sind in der Regel nicht thread-safe. Man darf also den Zustand der GUI nur aus dem Thread ändern, in dem auch die GUI-Hauptschleife läuft. Anfängern keine kaputten Programme mit der Bemerkungen wie „Na und? Ist eh nur zum ausprobieren…“ zu zeigen ist kein Dogma. Insbesondere wenn es nicht deterministisch zu Problemen führt, und der Anfänger das somit nicht gleich merkt das das Murks ist.
`root.quit()` ist nicht besser als zweimal Strg+C zu drücken (warum eigentlich 2×?) weil beim Ausführen der `quit()`-Funktion potentiell zwei Threads gleichzeitig auf die Interna von Tk/Tcl zugreifen was zu Fehlern führen kann und somit falsch ist.
Wenn Queues und Ereignisse für Anfänger zu viel sind, dann sind es auch Threads. Denn mit Threads kann man nicht sinnvoll etwas anfangen ohne die Probleme und deren Lösungen zu kennen die man sich mit nebenläufiger Programmierung einfangen kann. Eben insbesondere weil das alles nicht mehr deterministisch ist und man Fehler erst viel später bemerkt wo es dann sehr viel Arbeit machen kann alles so umzuschreiben das es tatsächlich funktioniert.
`root.quit()` ist nicht besser als zweimal Strg+C zu drücken (warum eigentlich 2×?) weil beim Ausführen der `quit()`-Funktion potentiell zwei Threads gleichzeitig auf die Interna von Tk/Tcl zugreifen was zu Fehlern führen kann und somit falsch ist.
Wenn Queues und Ereignisse für Anfänger zu viel sind, dann sind es auch Threads. Denn mit Threads kann man nicht sinnvoll etwas anfangen ohne die Probleme und deren Lösungen zu kennen die man sich mit nebenläufiger Programmierung einfangen kann. Eben insbesondere weil das alles nicht mehr deterministisch ist und man Fehler erst viel später bemerkt wo es dann sehr viel Arbeit machen kann alles so umzuschreiben das es tatsächlich funktioniert.
- noisefloor
- User
- Beiträge: 3854
- Registriert: Mittwoch 17. Oktober 2007, 21:40
- Wohnort: WW
- Kontaktdaten:
Hallo,
eine Dreieck als ASCII-Art:
[codebox=pycon file=Unbenannt.txt]>>> def draw_triangle(edge_length):
... for i in range(edge_length):
... current_line = '/{}\\'.format(' '*i*2)
... print('{:^{edge_length}}'.format(current_line, edge_length=edge_length*2))
... print('-'*edge_length*2)
...
>>> draw_triangle(10)
/\
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
--------------------
>>>
[/code]
Das Quadrat ist ja ein bisschen einfacher, weil man da nicht auf die Zentrierung achten braucht.
Gruß, noisefloor
eine Dreieck als ASCII-Art:
[codebox=pycon file=Unbenannt.txt]>>> def draw_triangle(edge_length):
... for i in range(edge_length):
... current_line = '/{}\\'.format(' '*i*2)
... print('{:^{edge_length}}'.format(current_line, edge_length=edge_length*2))
... print('-'*edge_length*2)
...
>>> draw_triangle(10)
/\
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
/ \
--------------------
>>>
[/code]
Das Quadrat ist ja ein bisschen einfacher, weil man da nicht auf die Zentrierung achten braucht.
Gruß, noisefloor
@noisefloor: Wobei das nicht gleichschenklig ist, oder nur unter gewissen Rahmenbedingungen die eher unwahrscheinlich sind.
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
@Blackjack: OK, dann mit sicherer Queue und keine globalen Variablen
Code: Alles auswählen
# -- python 3 ------
import tkinter as tk
from threading import Thread
import queue
from math import sqrt
class Application(tk.Tk):
def __init__(self,app_queue,**kwargs):
tk.Tk.__init__(self,**kwargs)
self.queue = app_queue
self.canvas = tk.Canvas(self,bg = 'white',width=400,height=400)
self.canvas.pack()
self.execute_queue()
def execute_queue(self):
while not self.queue.empty():
self.queue.get()()
self.after(100,self.execute_queue)
def zeichne(self,figur,laenge):
if figur == "quadrat":
x0 = 10
y0 = 10
x1 = x0 + laenge
y1 = y0
x2 = x0 + laenge
y2 = y0 + laenge
x3 = x0
y3 = y0 + laenge
self.canvas.create_line(x0,y0,x1,y1,x2,y2,x3,y3,x0,y0)
# einfacher ginge es mit
# self.canvas.create_rectangle(x0,y0,x0+laenge,y0+laenge)
# aber mit dem Dreieck muss man es mit create_line machen
elif figur == "dreieck":
# eigentlich selbermachen
x0 = 10
ybase = 10
y0 = ybase + laenge*sqrt(3)/2
x1 = x0 + laenge
y1 = y0
x2 = x0 + laenge/2
y2 = ybase
self.canvas.create_line(x0,y0,x1,y1,x2,y2,x0,y0)
def eingabeschleife(app_queue,root):
figuren = { 'q' : 'quadrat', 'd' : 'dreieck', 'e' : 'erase' }
while True:
while True:
figur_buchstabe = input("quadrat = q, dreieck = d, e = erase : ")
if figur_buchstabe == '':
return
if figur_buchstabe in figuren:
figur = figuren[figur_buchstabe]
break
else:
print('\n? Fehler: falsche Eingabe\n')
if figur == 'erase':
app_queue.put(lambda : root.canvas.delete(tk.ALL))
print()
continue
while True:
laenge_string = input("laenge: ")
if laenge_string == '':
return
try:
laenge = int(laenge_string)
break
except ValueError:
print('\n? Fehler: das war keine Zahl\n')
print()
app_queue.put(lambda figur = figur, laenge = laenge: root.zeichne(figur,laenge))
def eingabe(app_queue,root):
eingabeschleife(app_queue,root)
app_queue.put(lambda : root.quit())
def main():
app_queue = queue.Queue()
root = Application(app_queue)
Thread(target=eingabe,args=(app_queue,root)).start()
root.mainloop()
main()
- noisefloor
- User
- Beiträge: 3854
- Registriert: Mittwoch 17. Oktober 2007, 21:40
- Wohnort: WW
- Kontaktdaten:
Hallo,
Gruß, noisefloor
Du meinst "gleichseitig", oder? Gleichschenklig ist es. Gleichseitig ist mit ASCII-Zeichensatz in der Tat ein wenig schwierig.BlackJack hat geschrieben:@noisefloor: Wobei das nicht gleichschenklig ist, oder nur unter gewissen Rahmenbedingungen die eher unwahrscheinlich sind.
Gruß, noisefloor
@Alfons Mittelmeyer: Du schaffst es tatsächlich eine Queue zu benutzen und trotzdem root als threaduberschreitende Variable zu benutzen. In die Queue gehören die Variablen und nicht die Methoden, die Auflösung gehört in execute_queue.
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
Dann wohl besser so?Sirius3 hat geschrieben:@Alfons Mittelmeyer: Du schaffst es tatsächlich eine Queue zu benutzen und trotzdem root als threaduberschreitende Variable zu benutzen. In die Queue gehören die Variablen und nicht die Methoden, die Auflösung gehört in execute_queue.
Code: Alles auswählen
# -- python 3 ------
import tkinter as tk
from threading import Thread
import queue
from math import sqrt
class Application(tk.Tk):
def __init__(self,app_queue,**kwargs):
tk.Tk.__init__(self,**kwargs)
self.queue = app_queue
self.canvas = tk.Canvas(self,bg = 'white',width=400,height=400)
self.canvas.pack()
self.execute_queue()
def execute_queue(self):
while not self.queue.empty():
exec(self.queue.get())
self.after(100,self.execute_queue)
def zeichne(self,figur,laenge):
if figur == "quadrat":
x0 = 10
y0 = 10
x1 = x0 + laenge
y1 = y0
x2 = x0 + laenge
y2 = y0 + laenge
x3 = x0
y3 = y0 + laenge
self.canvas.create_line(x0,y0,x1,y1,x2,y2,x3,y3,x0,y0)
# einfacher ginge es mit
# self.canvas.create_rectangle(x0,y0,x0+laenge,y0+laenge)
# aber mit dem Dreieck muss man es mit create_line machen
elif figur == "dreieck":
# eigentlich selbermachen
x0 = 10
ybase = 10
y0 = ybase + laenge*sqrt(3)/2
x1 = x0 + laenge
y1 = y0
x2 = x0 + laenge/2
y2 = ybase
self.canvas.create_line(x0,y0,x1,y1,x2,y2,x0,y0)
def eingabeschleife(app_queue):
figuren = { 'q' : 'quadrat', 'd' : 'dreieck', 'e' : 'erase' }
while True:
while True:
figur_buchstabe = input("quadrat = q, dreieck = d, e = erase : ")
if figur_buchstabe == '':
return
if figur_buchstabe in figuren:
figur = figuren[figur_buchstabe]
break
else:
print('\n? Fehler: falsche Eingabe\n')
if figur == 'erase':
app_queue.put("self.canvas.delete(tk.ALL)")
print()
continue
while True:
laenge_string = input("laenge: ")
if laenge_string == '':
return
try:
laenge = int(laenge_string)
break
except ValueError:
print('\n? Fehler: das war keine Zahl\n')
print()
format_string = "self.zeichne('{0}',{1})".format(figur,laenge)
print(format_string)
app_queue.put(format_string)
def eingabe(app_queue):
eingabeschleife(app_queue)
app_queue.put('self.quit()')
def main():
app_queue = queue.Queue()
Thread(target=eingabe,args=(app_queue,)).start()
Application(app_queue).mainloop()
main()
In gewisser Weise ist dies ja schon kreativ ...Sirius3 hat geschrieben:@Alfons Mittelmeyer: Du schaffst es immer noch, eins draufzusetzen. Dann doch lieber die vorherige Version.
@gulash, sofern Du noch nicht erfolgreich vertrieben bist: don't do this at home and especially not at work. Dieser Code ist mal wieder ... Mist.