@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()``.
Eine Art RS-FlipFlop
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
@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
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
@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.
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.
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
@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:
Es gibt durchaus Systeme, für die man eine solche Funktion schreiben muss, ist aber für Python unangebrachtt.
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))
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
@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:
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):
Beispiel für print(my_object.text):
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")
Eine bessere Möglichkeit, wäre dann eine Verwendung eines Indexes, weil dann die if else Logik überflüssig wird:
Code: Alles auswählen
print(text[index])
Code: Alles auswählen
print(my_text)
Code: Alles auswählen
print(my_object.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)
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)
@Alfons Mittelmeyer: wenn es um kompliziertere Sachen geht, reicht doch ein Index in eine Liste nicht mehr aus. Dann muß man mit if-else arbeiten oder Funktionen in einer Liste. Dass man sich selbst eine verkettete Liste programmiert, ist heutzutage und dazu noch in Python eher unüblich, da man dafür schon fertige Konstrukte hat. Wie das geht, hat kbr ja schon gezeigt.
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
Es geht hier nicht um eine Patentlösung auch für die kompliziertesten Sachen. Es geht um einen Ablauf, bei dem sich in einigen Details das Verhalten ändert.Sirius3 hat geschrieben:@Alfons Mittelmeyer: wenn es um kompliziertere Sachen geht, reicht doch ein Index in eine Liste nicht mehr aus.
Dass man um if else bei einem Programm nicht ganz herum kommt ist klar, aber zur Unterscheidung des Verhaltens braucht man dann kein if else, wenn man auf ein Objekt, welches das geänderte Verhalten beschreibt, umschaltet, sei es durch Ändern einer Referenz oder eines IndexesSirius3 hat geschrieben:Dann muß man mit if-else arbeiten oder Funktionen in einer Liste.
Es geht hier nicht um die Programmierung einer verketteten Liste, nur wenn man sowieso schon Objekte mit diversen Eigenschaften hat, warum soll man dann noch extra ein weiteres Konstrukt für eine Referenz auf das nächste Element benützen, wenn man das ganz einfach in die Objekte eintragen kann und sich so Zusätzliches spart.Sirius3 hat geschrieben:Dass man sich selbst eine verkettete Liste programmiert, ist heutzutage und dazu noch in Python eher unüblich, da man dafür schon fertige Konstrukte hat. Wie das geht, hat kbr ja schon gezeigt.
Etwas Anderes wären natürlich verkettete Listen, in die man nachträglich noch etwas einfügt oder herauslöscht. Klar, dass man sich so etwas nicht selber nochmals programmiert. Python hat da schon solche Konstrukte.
@Alfons Mittelmeyer: wenn man die »einigen Details« nicht genau kennt, kann man kein Patentrezept geben.
So und jetzt fangen wir ganz primitiv mit Zählen an: __init__ braucht ein zusätzliches Argument und ein zusätzliches Attribut, beim Erzeugen brauch ich ein Argument mehr und ich muß mir das erste Objekt merken, um den Ring zu schließen. Und dann mußt Du das ganze noch von Hinten her aufbauen!
Alternativ:
So muß das Objekt nichts mehr davon wissen, wie es in irgendeine übergeordnete Struktur eingebunden wird, ist schön schlank (hier so schlank, dass man es gleich weglassen kann), Zuständigkeiten sind klar getrennt.
Der Aufwand ist auf keinen Fall größer als bei Deiner Art zu Programmieren, die Vorteile sind aber hoffentlich auch Dir klar geworden.
Genau das ist ja das Problem bei Deinem Vorgehen. Du sparst nicht, sondern Du packst was zusätzlich in ein Objekt, das da nichts verloren hat. Ein Objekt sollte eine Sache gut machen, und nicht noch eine zweite schlecht. Wie man mit einer Liste umgeht weiß jeder, wie das Attribut für die Verkettung heißt, muß man immer wieder nachschauen. Nächster Grund, warum man keine Objekte um eine Verkettung erweitert: so kann das Objekt nur in einer Liste vorkommen.Alfons Mittelmeyer hat geschrieben:... wenn man das ganz einfach in die Objekte eintragen kann und sich so Zusätzliches spart.
So und jetzt fangen wir ganz primitiv mit Zählen an: __init__ braucht ein zusätzliches Argument und ein zusätzliches Attribut, beim Erzeugen brauch ich ein Argument mehr und ich muß mir das erste Objekt merken, um den Ring zu schließen. Und dann mußt Du das ganze noch von Hinten her aufbauen!
Alternativ:
Code: Alles auswählen
from itertools import cycle
import time
class AnimationProperty():
def __init__(self, text):
self.text = text
# evtl. weitere Eigenschaften
properties = cycle([
AnimationProperty("Text1"),
AnimationProperty("Text2"),
])
max_breite = 10
breite = 0
property = next(properties)
while True:
#draw.rectangle(hoehe, breite)
time.sleep(1)
breite += 5
if breite >= max_breite:
property = next(properties)
breite = 0
print(property.text)
Der Aufwand ist auf keinen Fall größer als bei Deiner Art zu Programmieren, die Vorteile sind aber hoffentlich auch Dir klar geworden.
@Alfons Mittelmeyer: Wenn man sowieso schon ein Objekt hat, kann man da ja gleich noch andere Funktionalität mit reinbasteln statt für die andere Funktionalität ein eigenes Objekt zu schreiben klingt nach einem schönen Rezept unübersichtliche Programme zu schreiben und das selbe an mehreren Stellen immer wieder neu zu erfinden. Es gibt doch bereits `itertools.cycle()`. Das ist einmal eine Lösung für dieses Problem nicht irgendwo reingebastelt wo es nicht hingehört, sondern separat und wiederverwendbar.
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
@BlackJack:
statt my_object = my_object.next_object soll ich also itertools nehmen.
was nehme ich aber dann für my_strasse = my_object.strasse
Gibt es dafür vielleicht ein Adressverwaltungstool, das man dafür nehmen soll?
Oder schreibt man besser:
my_object = my_object2 if my_object == my_object1 else my_object1
statt my_object = my_object.next_object soll ich also itertools nehmen.
was nehme ich aber dann für my_strasse = my_object.strasse
Gibt es dafür vielleicht ein Adressverwaltungstool, das man dafür nehmen soll?
Oder schreibt man besser:
my_object = my_object2 if my_object == my_object1 else my_object1
@Alfons Mittelmeyer: »my_xxx« schreibst man sowieso nicht, weil das my-Präfix gar nichts aussagt. Und wie ich schon geschrieben habe, sollte ein Objekt nichts über seine Einordnung in eine übergeordnete Datenstruktur wissen müssen. Was Du mit einer Straße machen sollst, wirst nur Du wissen.
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
Es geht ja hier nicht um konkreten Code, sondern ein allgemeines Beispiel. Ist das jetzt besser?Sirius3 hat geschrieben:@Alfons Mittelmeyer: »my_xxx« schreibst man sowieso nicht, weil das my-Präfix gar nichts aussagt.
x = z if x == y else y
Ich wollte kar keine übergeordnete Datenstruktur haben. Und ein Objekt weiß sowieso nichts, denn es ist nicht intelligent. Oder ist ein zugeordnetes Attribut bereits Wissen?Sirius3 hat geschrieben:Und wie ich schon geschrieben habe, sollte ein Objekt nichts über seine Einordnung in eine übergeordnete Datenstruktur wissen müssen
Außerdem, warum soll jemand nicht seinen Nachfolger selbst bestimmen können. Muss das ein Höherer sein, der das bestimmt?
Außerdem, bestimmt das Objekt nicht seinen Nachfolger, der ist nur hier erfasst und warum soll man noch eine übergeordnete Datenstruktur haben? Oder eine Logik, die den Nachfolger ermittel?. Warum diesen nicht gleich vorgeben? Bzw. wenn man ihn vorgibt, warum dann extra in einer übergeordneten Datenstruktur?
@Alfons Mittelmeyer: warum sollte das jetzt besser sein, wenn es ›cycle‹ gibt? Natürlich ist ein Attribut Wissen, das ein Objekt hat. Aber ein Objekt sollte eben kein Wissen darüber haben, wie es verwendet wird. Das Kapseln ist ja gerade der Sinn von Objektorientierung. Du stellst die falschen Fragen. Warum sollte das Objekt etwas über ihren Nachfolger wissen? Das ist für die Aufgabe, die das Objekt erfüllen soll, nicht nötig.
- DeaD_EyE
- User
- Beiträge: 1020
- Registriert: Sonntag 19. September 2010, 13:45
- Wohnort: Hagen
- Kontaktdaten:
Der Titel des Themas zieht wahrscheinlich viele an, die wirklich ein Flipflop programmieren möchten.
Wie programmiert ihr ein FlipFlop in Python?
Hier mein Ansatz:
Gibt sicherlich bessere Ideen. GGf. das Thema splitten und das alte umbenennen.
Wie programmiert ihr ein FlipFlop in Python?
Hier mein Ansatz:
Code: Alles auswählen
class FlipFlop:
def __init__(self, state=False):
self.state = state
def __bool__(self):
return self.state
def __int__(self):
return 1 if self.state else 0
def __index__(self):
return int(self)
def __lshift__(self, val):
return int(self) << val
def __repr__(self):
return '{}(state={})'.format(self.__class__.__name__, self.state)
class SR(FlipFlop):
"""Rücksetzdominaz"""
def __call__(self, in_set=None, in_reset=None):
if in_reset:
self.state = False
elif in_set and not in_reset:
self.state = True
return self.state
class RS(FlipFlop):
"""Setzdominaz"""
def __call__(self, in_set=None, in_reset=None):
if in_set:
self.state = True
elif not in_set and in_reset:
self.state = False
return self.state
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Angenommen state sei ein boolean:DeaD_EyE hat geschrieben:Wie programmiert ihr ein FlipFlop in Python?
Code: Alles auswählen
state = not state
- DeaD_EyE
- User
- Beiträge: 1020
- Registriert: Sonntag 19. September 2010, 13:45
- Wohnort: Hagen
- Kontaktdaten:
Ja, das wäre die Invertierung mit Zuweisung. Ich habs mit einer direkten Zuweisung gemacht.
Die Implementierung ist recht billig. Ich glaube, dass die Resultate auch richtig sind.
Jemand der den Code verwendet, sollte erstmal mit einer Wahrheitstabelle prüfen ob das überhaupt stimmt
Diese Magic-Methoden finde ich einfach cool. Könnte man noch mit logischen Operationen erweitern (__and__, __or__, __xor__).
Sind hier eigentlich noch Menschen unterwegs, die SPS programmieren?
Die Implementierung ist recht billig. Ich glaube, dass die Resultate auch richtig sind.
Jemand der den Code verwendet, sollte erstmal mit einer Wahrheitstabelle prüfen ob das überhaupt stimmt
Code: Alles auswählen
In [4]: flipflop1 = SR()
In [5]: flipflop1
Out[5]: SR(state=False)
In [6]: flipflop1(in_set=True, in_reset=True)
Out[6]: False
In [7]: flipflop1(in_set=True, in_reset=False)
Out[7]: True
In [8]: flipflop1
Out[8]: SR(state=True)
In [9]: bool(flipflop1)
Out[9]: True
In [10]: int(flipflop1)
Out[10]: 1
In [11]: flipflop1 << 2
Out[11]: 4
Sind hier eigentlich noch Menschen unterwegs, die SPS programmieren?
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server