Seite 1 von 2
Eine Art RS-FlipFlop
Verfasst: Donnerstag 20. April 2017, 19:10
von CrytoChris
Hallo, ich habe eine bestimmt einfach zu beantwortende Frage, komme aber einfach nicht drauf:
Ich möchte in Python eine wechselnde Anzeige haben. Unter der eine Art Ladebalken läuft. Sobald der Balken am Ende ist, soll die Anzeige wechseln. Wenn er dann wieder am Ende ist, soll die Anzeige wieder das erste Anzeigen.
Quasi:
Code: Alles auswählen
If Balkenlänge < max
Print Text 1
If Balkenlänge war mal max und ist wieder auf dem Weg dahin
Print Text 2
If Balkenlänge hat wieder max erreicht
Print Text 1
Usw...
Ich hoffe man verstehg das Problem
Danke
Chris
Re: Eine Art RS-FlipFlop
Verfasst: Donnerstag 20. April 2017, 19:17
von Sirius3
@CrytoChris: Und wo ist Dein konkretes Problem? Du hast ja schon verschiedene if-Abfragen. Du brauchst nur noch ein Flag, das sagt, ob Du schoneinmal bei max warst, oder noch nicht.
Re: Eine Art RS-FlipFlop
Verfasst: Donnerstag 20. April 2017, 19:27
von CrytoChris
Ich glaub genau am flag.
das Ganze läuft in einer While-Schleife. Ich bekomme gerade nicht hin, wie ich das flag auch innerhalb der Schleife gesetzt lasse.
Code: Alles auswählen
flag =0
While True:
draw.rectangle(höhe, breite)
breite += 5
if breite >= max_breite:
print ("Text 1")
breite = 0
?? flag = 1 ??
if breite <= max_breite and flag == 1:
print ("Text 2")
?? flag = 0 ??
Mein Problem ist, dass ich nicht genau weiss, wann ich das Flag zurücksetze. Denn in dem Code oben würde Text 2 genau für einen Durchlauf der Schleife angezeigt werden, statt eine ganze "Balkenlänge" lang.
Re: Eine Art RS-FlipFlop
Verfasst: Donnerstag 20. April 2017, 20:01
von Sirius3
@CrytoChris: wenn ich Dich richtig verstanden habe, sollte das doch das sein, was Du möchtest:
Code: Alles auswählen
flag =0
while True:
draw.rectangle(höhe, breite)
breite += 5
if breite >= max_breite:
print ("Text 1")
breite = 0
flag = 1
else:
if flag == 1:
print ("Text 2")
else:
print ("Text 1")
Re: Eine Art RS-FlipFlop
Verfasst: Donnerstag 20. April 2017, 20:08
von CrytoChris
Hi Siruis,
danke, aber das ist auch nur die halbe Lösung.
Text 1 und Text 2 sollen immer im Wechsel angezeigt werden.
In deinem Code klappt der Wechsel nur 1x, danach wird Text 1 wieder nur für einen Durchlauf der Schleife angezeigt.
Vielleicht kann ich es auch nicht gut genug erklären
Im Prinzip will ich Text 1 und Text 2 alle 5 Sekunden wechseln lassen. Endlos lang.
Jedoch soll der Trigger zum Wechsel des Textes keine Zeit sein, sondern das Erreichen der max_breite des sich erweiternden Ladebalkens.
Re: Eine Art RS-FlipFlop
Verfasst: Donnerstag 20. April 2017, 20:23
von BlackJack
@CrytoChris: Eine Liste mit beiden Texten und `itertools.cycle()` könnten Teil der Lösung sein. Immer wenn der Balken voll ist lässt Du Dir mit der `next()`-Funktion den ”nächsten” Text geben für die Ausgabe.
Re: Eine Art RS-FlipFlop
Verfasst: Donnerstag 20. April 2017, 20:30
von Zizibee
Oder so etwas in der Art?
Code: Alles auswählen
flag = False
while True:
draw.rectangle(höhe, breite)
breite += 5
if breite >= max_breite:
breite = 0
flag = not flag
if flag:
print ("Text 1")
else:
print ("Text 2")
Re: Eine Art RS-FlipFlop
Verfasst: Donnerstag 20. April 2017, 20:40
von CrytoChris
Hey,
@Zizibee:
Das war es. Danke
Ich vermute, es fehlte mir an dem Wissen, dass es so etwas wie "not" gibt.
"not" negiert, oder? Ein voriges True, wird False und umgekehrt?
Das erklärt auch, warum ich schon beim Betreff überlegen musste, was ich genau suche und es versuchte mit dem alten Set/Reset-FlipFlop der SPS-Programmierung in der Ausbildung zu beschreiben

Re: Eine Art RS-FlipFlop
Verfasst: Freitag 21. April 2017, 01:09
von noisefloor
Hallo,
"not" negiert, oder? Ein voriges True, wird False und umgekehrt?
Genau, `not` negiert den folgenden Ausdruck.
Gruß, noisefloor
Es geht auch ohne Flag
Verfasst: Freitag 21. April 2017, 21:19
von Alfons Mittelmeyer
Code: Alles auswählen
texts = ("Text 1", "Text 2")
index = 0
while True:
draw.rectangle(hoehe, breite)
breite += 5
if breite >= max_breite:
breite = 0
index ^= 1
print(texts[index])
Re: Eine Art RS-FlipFlop
Verfasst: Freitag 21. April 2017, 21:35
von BlackJack
@Alfons Mittelmeyer: Ein Flag durch eine Variable zu ersetzen, welche die Zahlen 0 oder 1 annehmen kann, zu verwenden um ein Flag loszuwerden ist ein kleines bisschen sinnlos. Zumal das ``not`` noch einfach lesbar und verständlich ist, während die Verwendung Exlusiv-Oder-Bitverknüpfung in Hochsprachen eher ein Exot ist der eigentlich nur bei Bitfummeleien in Binärdaten zum Einsatz kommt. Und das ist eher selten.
Re: Eine Art RS-FlipFlop
Verfasst: Samstag 22. April 2017, 10:04
von kbr
@CrytoChris: auch wenn Alfons hier oft fragwürdigen Code postet (bisweilen hat es auch den Anschein, dies sei Absicht), so ist die Idee auf ein Flag zu verzichten eine Variante, die je nach Einsatzzweck Vorteile haben kann. Zum Beispiel dann, wenn mehr als ein Zustand unterschieden werden soll. Hier ein Beispiel, wie es ohne Flag geht:
Code: Alles auswählen
import time
texts = ('text 1', 'text 2')
text_index = 0
print(texts[text_index])
width = 0
max_width = 50
width_increment = 5
while True:
# statt draw.rectangle hier ersatzweise time.sleep:
time.sleep(0.05)
width += width_increment
if width >= max_width:
text_index = (text_index + 1) % 2
print(texts[text_index])
width = 0
Und wie so oft bietet die Standard Library für solche Zwecke bereits fertige Lösungen:
Code: Alles auswählen
import time
from itertools import cycle
texts = ('text 1', 'text 2')
text = cycle(texts)
print(next(text))
width = 0
max_width = 50
width_increment = 5
while True:
# statt draw.rectangle hier ersatzweise time.sleep:
time.sleep(0.05)
width += width_increment
if width >= max_width:
print(next(text))
width = 0
Re: Eine Art RS-FlipFlop
Verfasst: Samstag 22. April 2017, 10:42
von Alfons Mittelmeyer
@kbr: sorry, wenn man zB. etwas blinken lassen will und dann einen Pin von 0 auf 1 oder von 1 auf 0 umschalten will, dann macht man das sicher nicht mit:
pin_status = (pin_status + 1) % 2
So etwas ist eine grauenhafte Zeile, welche von solchen geschrieben wird, für die Bits und Bytes etwas ganz Exotisches sind
Der grebräuchliche Ausdruck ist hierfür eben:
pin_status ^= 1
auch wenn das für solche, die nichts mit Hardwareregistern und hardwarenaher Programmierung zu tun haben, spanisch vorkommt. Meiner Meinung nach sollte man mit den Operatoren und dabei auch mit den bitweisen Operaturen vertraut sein. Diese Operatoren gehören zu ziemlich jeder Programmiersprache und sollten Grundwissen sein.
Recht hast Du, dass der Index einen Vorteil bringt gegenüber dem Flag, was BlackJack anscheinend nicht gesehen hatte, denn:
ist sicher schöner als so eine Flag Abfrage Logik:
Bei Flags sollte man überlegen, ob man sie wirklich braucht, oder nicht besser durch etwas ersetzen kann, das den Zustand bereits enthält und so die Logik der Flagauswertung überflüssig macht.
Wenn man nicht mal einen Index braucht, wie Deine Lösung :
print(next(text))
Ist natürlich noch schöner
Re: Eine Art RS-FlipFlop
Verfasst: Samstag 22. April 2017, 11:07
von kbr
@Alfons Mittelmeyer: sorry, aber wenn ich hardwarenah programmieren möchte, nehme ich C. Und wenn mir Bits und Bytes nicht exotisch genug sind, wähle ich auch die Elektronen einzeln aus. Und statt Pins nehme ich lieber Spins, dann habe ich auch mehr Zustände als nur 0 und 1.
Re: Eine Art RS-FlipFlop
Verfasst: Samstag 22. April 2017, 11:32
von Alfons Mittelmeyer
@kbr: sorry, es geht hier nicht darum, was Du machst und ob Du dafür C oder C++ nehmen würdest, da würde man das Toggeln nämlich auch mit "^=" machen.
Es geht hier auch um andere Mitglieder oder Leser dieses Forums. Und in diesem Forum gibt es auch das Programmierforum "Raspberry Pi und Co". Und beim Raspberry sind besonders die GPIO Pins interessant, über welche in diesem Programmierforum LEDs, Motoren, Sensoren und dergleichen angesteuert werden. Und das in Python. Das ist also gar nichts Exotisches, und kein Mensch außer Dir beschwert sich, dass man auch in Python die GPIO Pins ansteuert.
Und sicher sollte man zum Toggeln das verwenden:
pin_status ^= 1
Und nicht so etwas grauenhaftes wie:
pin_status = (pin_status + 1) % 2
Ach so, was man noch kennen sollte, wenn man flags verwedet. Statt einer Flag Programmlogik eine flagabhängige Ausgabe verwenden, das wäre etwa:
print("Text 1" if flag else "Text 2")
Hier sieht man gleich, dass es ein "print" ist und hat keine vier Zeilen mit if else Programmlogik, die etwas ablenken würden.
Re: Eine Art RS-FlipFlop
Verfasst: Samstag 22. April 2017, 12:12
von BlackJack
@Alfons Mittelmeyer: Der in Python gebräuchliche Ausdruck etwas blinken zu lassen ist ``pin_status = not pin_status``, weil das ein Wahreitswert ist und die üblichen Python-APIs für GPIOs mit `True` und `False` klar kommen. Das mit dem ``^``-Operator ist aus Sprachen die in Maschinensprache übersetzt werden, wo man näher an der Hardware ist und auch eher in Zahlen mit einer bestimmten Anzahl Bits denkt und auf diesen Bits dann operiert und wo die boole'sche Negation bei einigen Sprachen auch mehr macht als nur das unterste Bit zu togglen. Sofern es überhaupt eine boole'sche Negation gibt. Oft haben solche Sprachen nicht einmal einen dedizierten Datentyp für Wahreitswerte.
Das ``not`` muss man sowieso kennen, weil die Negation von Wahreitswerten auch in nicht-hardwarenahen Pythonprogrammen regelmässig zur Anwendung kommt.
Mit `flag` hätte man übrigens auch ``print(texts[flag])`` schreiben können, ohne ``if``/``else``.
Eigentlich muss man sich damit auch gar nicht auseinandersetzen wenn man nicht will und nimmt einfach eine Bibliothek wie `gpiozero` und schreibt: ``led.toggle()``, oder wenn es wirklich kontinuierlich blinken soll ``led.blink()``.
Re: Eine Art RS-FlipFlop
Verfasst: Samstag 22. April 2017, 17:34
von Alfons Mittelmeyer
@BlackJack: ja es gibt Vieles, das in Python geht und wo es mich graust, etwa:
print(1 + True)
Aber überzeugen kannst Du mich nicht, dass man so etwas tun sollte. In vielen Programmiersprachen geht so etwas überhaupt nicht wegen Typinkompatibilität und in manchen Programmiersprachen ist True auch 0xFFFFFFFFFFFFFFFF, also 4294967295 oder -1, bei Vorzeichenbehaftung. Da würde der Index ganz schön daneben gehen.
Und ich empfinde so etwas:
value = (value +1) % 2
genauso häßlich wie so etwas:
value = ~value + 2
wenn es um togglen zwischen 0 und 1 geht
schöner wäre da noch:
value = 1 - value
Re: Eine Art RS-FlipFlop
Verfasst: Samstag 22. April 2017, 18:45
von kbr
@Alfons Mittelmeyer: es ging bei dem ursprünglichen Beispiel mit sinngemäß
value = (value +1) % 2
zwar um das toggeln zwischen zwei Texten, der mögliche Vorteil dieser Variante war bei der Erklärung aber daran geknüpft, dass im Gegensatz zu einem Flag auch mehr als zwei Zustände auf diese Weise behandelt werden können, so dass sich der allgemeine Fall von
text_index = (text_index +1) % len(texts)
ergibt. Diese Abstrahierung ergibt eine flexible und elegante Lösung. Bei nur zwei Zuständen ist die Negierung des Zustands eines boolschen Flags der pythonische Weg. Bitfummelei a la C ist in Python zumeist ein Zeichen für einen schlechten Lösungsansatz.
Re: Eine Art RS-FlipFlop
Verfasst: Samstag 22. April 2017, 19:27
von Alfons Mittelmeyer
@kbr:
value = 1 - value ist keine Bitfummelei. Sorry dass ich Bits nicht als Fummelei verstehe, sondern so etwas als elegant empfinde:
value ^= 1
Bitfummelei wäre, wenn jemand unnötiger Weise eine Funktion schriebe, mit der man zwei Integerwerte miteinander multiplizieren kann, etwa:
Code: Alles auswählen
def multiply_integer(a,b):
c = 0
for i in range(32):
c <<= 1
if b & 0x80000000:
c += a
b <<= 1
return c
# Test
print(multiply_integer(12,8))
Es gibt durchaus Systeme, für die man eine solche Funktion schreiben muss, ist aber für Python unangebrachtt.
Re: Eine Art RS-FlipFlop
Verfasst: Samstag 22. April 2017, 21:36
von Alfons Mittelmeyer
@CrytoChris: Brechen wir an dieser Stelle die sinnlose Diskussion ab, mit welchem Ausdruck man am Besten einen Index umstellt und widmen wir uns der Frage, welche Möglichkeiten wir haben, und welche am Besten in Frage kommt.
Die einfachste Möglichkeit ist das Flag:
Code: Alles auswählen
if flag:
print ("Text 2")
else:
print ("Text 1")
# oder
print("Text 2" if flag else "Text 1")
Wenn es um eine einfache Sache geht, ist nichts einzuwenden. Doch wenn das Flag an mehreren Stellen abzufragen ist, wenn nicht nur der Text, sondern auch anderes geändert behandelt werden soll, und wenn es auch noch andere Flags gibt, dann wird der Code leicht ein unübersichtlicher Verhau mit jeder Menge von if else Abfragen auf Flags, die evtl. dann auch noch tief verschachtelt sind.
Eine bessere Möglichkeit, wäre dann eine Verwendung eines Indexes, weil dann die if else Logik überflüssig wird:
Noch besser ist es, auch auf den Index zu verzichten, sondern gleich den geänderten Text zu haben:
Wenn sich nicht nur der Text ändern soll, sondern auch noch Anderes, empfiehlt sich, ein geändertes Objekt zu verwenden:
Beispiel für print(my_text):
Code: Alles auswählen
import time
max_breite = 10
breite = 0
my_text = "Text 1"
while True:
#draw.rectangle(hoehe, breite)
time.sleep(1)
breite += 5
if breite >= max_breite:
my_text = "Text 1" if my_text == "Text 2" else "Text 2"
breite = 0
print(my_text)
Beispiel für print(my_object.text):
Code: Alles auswählen
import time
class My_Object():
def __init__(self,next_object = None,text=''):
self.next_object = self if next_object == None else next_object
self.text = text
# evtl. weitere Eigenschaften
my_object2 = My_Object(None,"Text 2")
my_object1 = My_Object(my_object2,"Text 1")
my_object2.next_object = my_object1
max_breite = 10
breite = 0
my_object = my_object1
while True:
#draw.rectangle(hoehe, breite)
time.sleep(1)
breite += 5
if breite >= max_breite:
my_object = my_object.next_object
breite = 0
print(my_object.text)