Regeln zu gemischten Ausdrücken in Python

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
bernhart
User
Beiträge: 2
Registriert: Montag 5. November 2018, 11:40

Hallo allerseits,
1)
habe eine Frage zu gemischten Ausdrücken.

Beispiel:
x bool
y float
z int

z = x and y

Ist so ein gemischter Ausdruck (mit gemischten Datentypen) möglich ?

2)
Gibt es allgemeine Regeln (mit Quelle) bzw. Kriterien für gemischte Ausdrücke?
Wo wird dies genau festgelegt bzw. spezifiziert ?

3)
Wie reagiert Python auf Fehler in gemischten Ausdrücken (mit verschiedenen nicht kompatiblen Datentypen)?
Syntaktische Fehlermeldung oder Laufzeitfehler (Exception) ?

Mfg
bh
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Den ersten Teil haettest du ja schneller ausprobieren als formulieren koennen - aber die Antwort lautet "ja". Frage 2 wird hier beantwortet: https://docs.python.org/3/reference/exp ... operations

Und Frage 3 lautet zur Laufzeit, denn dadurch das es keine Typannotationen gibt, kann da ja auch nichts statisch analysiert werden. Fuer and/or/not kommt es da aber nie zu fehlern, bei Vergleichsoperationen hingegen durchaus.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Wobei sich Python bis Version 2.7 bei Vergleichen von verschiedenen Typen noch anders verhalten hat. Hier kam es nicht zu Laufzeitfehlern, sondern zu undefiniertem Verhalten. Ein Wahrheitswert kam dabei immer heraus.
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Benutzeravatar
__blackjack__
User
Beiträge: 13069
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@snafu: Undefiniertes Verhalten? Es war garantiert das bei einem Programmlauf immer das gleiche Ergebnis heraus kam. Implementierungsdetail: Bei kleiner/grösser Vergleichen bei verschiedenen (nicht ”autokonvertierten”) Datentypen wurde der Typ selbst verglichen. Weiteres Implementierungsdetail Typen wurden anhand ihrer ID verglichen. Und noch ein Implementierungsdetail die ID basiert auf der Adresse im Speicher.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

__blackjack__ hat geschrieben: Montag 5. November 2018, 18:55 @snafu: Undefiniertes Verhalten? Es war garantiert das bei einem Programmlauf immer das gleiche Ergebnis heraus kam..
Es wurde nicht definiert, was genau wann herauskommt. Andere Implentierungen waren nicht gezwungen, sich wie CPython zu verhalten. Mal ehrlich: Hast du dich auf das Python 2.x Verhalten dabei verlassen?
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

__blackjack__ hat geschrieben: Montag 5. November 2018, 18:55 @snafu: Undefiniertes Verhalten? Es war garantiert das bei einem Programmlauf immer das gleiche Ergebnis heraus kam. Implementierungsdetail: Bei kleiner/grösser Vergleichen bei verschiedenen (nicht ”autokonvertierten”) Datentypen wurde der Typ selbst verglichen. Weiteres Implementierungsdetail Typen wurden anhand ihrer ID verglichen. Und noch ein Implementierungsdetail die ID basiert auf der Adresse im Speicher.

Code: Alles auswählen

>>> class A(object):
...     pass
... 
>>> class B(object):
...     pass
... 
>>> id(A) < id(B)
False
>>> A() < B()
True
Comparisons hat geschrieben: CPython implementation detail: Objects of different types except numbers are ordered by their type names; objects of the same types that don’t support proper comparison are ordered by their address.
Benutzeravatar
__blackjack__
User
Beiträge: 13069
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@snafu: Das ist trotzdem nicht undefiniert. Undefiniert wäre wenn andere Implementierungen etwas völlig anderes machen könnten, zum Beispiel wie Python 3 einen Vergleich mit einer Ausnahme quittieren oder auswürfen was sie machen. Und ja, ich habe mich da mindestens zweimal auch drauf verlassen das ich Listen mit verschiedenen Typen sortieren kann, und da zumindest innerhalb eines Programmablauf ein konstantes Ergebnis bei heraus kommt und die Werte der verschiedenen Typen im Ergebnis zusammenhängend sind. Und das man solche sortierten Listen dann vergleichen kann.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
bernhart
User
Beiträge: 2
Registriert: Montag 5. November 2018, 11:40

Hallo allerseits,
1)
Erst mal vielen Dank für eure Antworten und die interessanten Links.

2)
Anhand welcher Referenz kann ich entscheiden, wer von euch beiden in eurem Dissens recht hat?

mfg
bh
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Der Dissens ist nicht zu entscheiden, weil er eine Frage der Beurteilung darstellt. Die Semantik von Python 2 ist, wie sie ist. Ob man sich darauf verlaesst, oder nicht, ist eine Geschmackssache. Da aber Python 3 dieses Problem NICHT mehr hat, und es wenig Sinn machen wuerde, mit Python 2 anzufangen, ist das fuer dich eh irrelevant.
Benutzeravatar
__blackjack__
User
Beiträge: 13069
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@bernhart: Wenn das wirklich darauf hinausläuft das wir eine unterschiedliche Auffassung von „undefiniertes Verhalten“ haben, dann eigentlich an keiner, denn dann haben wir beide recht. :-)
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

DasIch hat geschrieben: Montag 5. November 2018, 20:43
Comparisons hat geschrieben: CPython implementation detail: Objects of different types except numbers are ordered by their type names; objects of the same types that don’t support proper comparison are ordered by their address.
Ganz genau. Dieses in der Doku beschriebene Verhalten ist ein Detail von CPython 2.x. Die Anordnung einer sortierten Liste mit unterschiedlichen Typen wäre demnach auf einer anderen Plattform womöglich eine andere. Ist zwar als Spezialfall für CPython dokumentiert, aber nicht von der Sprachspezifikation vorgeschrieben. Ähnlich wie die Anordnung von Schlüsseln und Werten in einem Dictionary. Es ist innerhalb eines Interpreter-Durchlaufs gleich, aber man kann sich prinzipiell nicht darauf verlassen, dass an einem anderen Rechner genau so ist. Wie nennt man das denn sonst, wenn nicht undefiniert?
Benutzeravatar
__blackjack__
User
Beiträge: 13069
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@snafu: Das ist nicht undefiniert. Es steht ja nicht nur das CPython-Implementierungsdetail in der Dokumentation sondern schon etwas was definiert und damit garantiert ist, nämlich das es eine Ordnung gibt, und die innerhalb eines Programmlaufs auch konsistent ist. Die Implementierung hat da gewisse Freiheiten das konkret umzusetzen was definiert ist, aber sie darf an der Stelle nicht einfach *irgendwas* machen. Was bei „undefiniert“ erlaubt wäre. „Nasal demons“ und so. :-) Und wie gesagt, ich habe mich auf den garantierten Teil auch schon mal verlassen. Das war sortieren von gemischten Listen und vergleichen. Also im Grunde was man mit `set()` machen könnte – wenn denn alle Objekte hashbar gewesen wären, was sie leider nicht waren.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

@__blackjack__: hier sind gerade aber ne Menge gespaltene Haare in der Luft ;) An anderer Stelle hast du dich schon oefter deutlich dagegen ausgesprochen, sich auf genau solche Details zu verlassen. ZB bei dem Multi-Threading-Verhalten von CPython das dank des GIL sehr viel mehr atomare Operationen aufweist, als man das sonst unterstellen koennte. Und undefiniertes Verhalten ist ja ungleich nicht-deterministischem Verhalten! Es kann durchaus stabil sein, aber halt nicht garantiert. Muss aber auch nicht, doch in diesem Fall... da bin ich dann schon eher bei der Definiton von snafu. Das ist undefiniert.

Das man sowas trotzdem mal benutzt (oft wahrscheinlich sogar unabsichtlich), und dafuer nicht gleich im 7 Zirkel der Hoelle schmort - das steht auf einem anderen Blatt. Besser ist das neue Verhalten (weil definiert) in jedem Fall.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Es gibt schon einen Unterschied zwischen undefiniert und definiert durch die Implementation. Ich würde ja mal stark hoffen dass niemand jemals auf die Idee kommt undefiniertes Verhalten in Python einzuführen, dass ist schon bei C eine schlechte Idee.

Ansonsten verhält sich PyPy soweit wie möglich, einschließlich Implementationsdetails, wie CPython. Es gibt keine andere Implementation, die maintained ist und man ernsthaft nutzen könnte.
Benutzeravatar
__blackjack__
User
Beiträge: 13069
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@__deets__: Eben doch: undefiniert kann eben auch nicht-deterministisch sein. Da kann das Universum untergehen oder man kann dem Programmierer Dämonen aus der Nase kommen lassen, ohne das man gegen die Sprachbeschreibung verstösst. Und was von beiden man macht, darf man bei jedem Programmlauf auswürfeln. Also so das typische was man eben bei Compilern unter undefiniertes Verhalten versteht. Dagegen ist das Verhalten bei Vergleichen sehr wohl definiert. Und im Gegensatz zum Threading-Verhalten mit dem GIL kann man sich da auch drauf verlassen. Auf das GIL kann man sich nicht verlassen, weil eine Python-Implementierung das nicht haben muss. Das die Vergleiche von unterschiedlichen Typen während eines Programmlaufs konsistent sind, darf man dagegen nicht einfach ändern. Sonst verstösst man gegen die Sprachbeschreibung. Die Implementierungsdetails muss man nicht nachbauen, aber man kann auch anders konsistente Vergleiche implementieren.

@DasIch: Jython ist vielleicht nicht mehr maintained, aber da die Python 2.7 sich eh nicht weiterentwickelt, kann man das durchaus benutzen. Ich habe das im Einsatz für Fälle wo ich auf Java-Bibliotheken angewiesen bin, aber ansonsten die Programmiersprache frei wählen kann. Mittlerweile würde ich da Kotlin bevorzugen, aber bestehenden Code wollte ich erst einmal nicht umschreiben. :-)
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Okay, also gilt manchmal: definiertes Verhalten != definiertes Ergebnis bzw undefiniertes Ergebnis != undefiniertes Verhalten. Wenn ein Vergleich unterschiedlicher Typen auf der Speicheradresse beruht, dann ist das nur bedingt robust, da man diese ja nicht beeinflussen kann. Man weiß also nicht, was genau heraus kommt. Aber das Verhalten des Programms ist insofern definiert, dass zumindest das Vorgehen bekannt ist. Hab ich das so richtig verstanden?
Benutzeravatar
__blackjack__
User
Beiträge: 13069
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@snafu: Nein, das Vorgehen ist eben nicht bekannt. Es ist aber definiert das es eines gibt das die definierten Eigenschaften garantiert. Nämlich das die Vergleiche während eines Programmlaufs konsistente Ergebnisse liefern, egal wie sie das tun. Das ist definiert. Und damit ist das Ergebnis letztlich ja auch definiert. Mit einem Teil den die Implementierung frei festlegen kann, innerhalb der definierten Grenzen. *Das* ist aber letztlich bei sehr vielen Sachen so.

Zum Beispiel das Ergebnis von `id()`. Das muss eine Zahl liefern, so das bei keinen zwei zur gleichen Zeit existierenden Objekten der gleiche Wert heraus kommt. *Wie* das passiert, kann die Implementierung entscheiden. Das bedeutet ja aber nicht dass das Ergebnis von `id()` undefiniert ist. CPython's `id()` basiert auf der Speicheradresse des Werts. Bei Jython ist es AFAIK einfach ein Zähler. (Das heisst nachdem ca. 2 Milliarden Objekte erzeugt wurden, bekommt Jython ein Problem. :-))

Ebensowenig ist `hash()` exakt definiert. Nur die Randbedingungen die erfüllt werden müssen, und man kann natürlich auch ein wenig gesunden Menschenverstand erwarten.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten