Input ist vom Typ int oder String?

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.
RIN67630
User
Beiträge: 141
Registriert: Sonntag 29. April 2018, 08:07

Hallo,
ich bin etwas verduzt

die gleiche Variable gmtoff wird einmal moniert, dass sie String ist, und woanders moniert, dass sie int ist:


gmtoff = 3600 # Offset to GMT in secs
gmtoff = input("How much seconds ahead (or behind -) Greenwitch is normally the device ?") or gmtoff
assert( gmtoff <= 43200 and gmtoff >= -43200 ), "GMT offset must be in range -43200,43200"
^^^^^^^^^^^^^^^
TypeError: '<=' not supported between instances of 'str' and 'int'


Lasse ich testweise die assert Zeile weg, kommt gleich danach:
gmtoff = gmtoff.encode("ascii")
^^^^^^^^^^^^^
AttributeError: 'int' object has no attribute 'encode'


Wat nu? Ist gmtoff jetzt ein int oder ein String?
Oder ist gmtoff wie Schrödingers Katze: mal so, mal so, wie man es betrachtet?
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

@RIN67630: da Python der Typ am Objekt hängt und nicht am Namen, ist beides richtig.
Erst weist Du dem Name ›gmtoff‹ ein int zu, dann über `input` ein String, oder falls man nichts eingibt doch wieder ein int. Wobei der Code sehr schwer lesbar ist. Mit ›or‹ in dieser Form sollte man nicht arbeiten.
Besser wäre also:

Code: Alles auswählen

DEFAULT_TIMEZONE_OFFSET = 3600
timezone_input = input("How much seconds ahead (or behind -) Greenwitch is normally the device ?")
device_timezone_offset = int(timezone_input) if timezone_input else DEFAULT_TIMEZONE_OFFSET
if not (-43200 <= device_timezone_offset <= 43200):
    raise ValueError("GMT offset must be in range -43200 to 43200")
Damit wird jedem Namen immer Werte des selben Typs zugewiesen; damit gibt es auch keine Verwirrung.
Benutzeravatar
__blackjack__
User
Beiträge: 14047
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@RIN67630: `input` ist vom Typ `function`. 🤡

Und gibt Werte vom Typ `str` zurück. Du bindest da also eine Zeichenkette oder eine Zahl an den Namen `gmtoff`, je nach dem was konkret eingegeben wird bei dem `input()`. Und je nach dem was es dann konkret ist, schlägt halt bei `str` der Vergleich mit einer Zahl fehl, oder bei einer Zahl der Versuch `encode()` darauf aufzurufen.

Es ist in sofern wie Schrödingers Katze als das man allein am Code nicht im Voraus sehen kann was der Benutzer eingibt, und was es dann konkret ist nach der Zuweisung mit dem `input()` im Ausdruck.

Nur um sicherzugehen: Du hast das ``or gmtoff`` in dem Ausdruck auf dem Schirm und weisst was das bewirkt?
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Benutzeravatar
pillmuncher
User
Beiträge: 1530
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@RIN67630:

Code: Alles auswählen

>>> x = 123
>>> type(x)
<class 'int'>
>>> x = 'hallo'
>>> type(x)
<class 'str'>
>>> x = 456
>>> type(x)
<class 'int'>
Außerdem lassen sich Bereichsvergleiche in Python so formulieren:

Code: Alles auswählen

assert -43200 <= gmtoff <= 43200, "GMT offset must be in range -43200,43200"
Die bedeutungsleeren Klammern habe ich weggelassen,.
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
DeaD_EyE
User
Beiträge: 1239
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Die Funktion input liefert als Rückgabewert einen str.

Der logische Operator or ist was Besonderes.
Als Ergebnis bekommt man das Objekt, welches als erstes nach True evaluiert. Es wird von links nach rechts evaluiert.

Ein leerer String evaluiert nach False. D.h. wenn der Anwender nur Enter betätigt, liefert die Funktion input einen leeren str.
Dann wird der int 3600 gmtoff zugewiesen.

Wenn der Anwender irgendetwas eingibt (können auch Buchstaben sein), evaluiert der resultierende str nach True, d.h. dann wird gmtoff ein str zugewiesen.

Je nach Benutzerinteraktion ist gmtoff ein str oder ein int.

Code: Alles auswählen

gmtoff = input("...") or 3600
Ich würde es so machen:

Code: Alles auswählen

def ask_offset(default_offset=3600):
    while True:
        user_input = input(f"Wie groß soll der offset sein? ({default_offset}): ").strip()

        if not user_input:
            return default_offset

        try:
            return int(user_input)
        except ValueError:
            print("Der Offset muss eine Ganzzahl sein.")



if __name__ == "__main__":
    offset = ask_offset()
    print(f"Rückgabewert der Funktion ask_offset: {offset}")

sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Benutzeravatar
DeaD_EyE
User
Beiträge: 1239
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Der Aufruf der Methode strip() nach dem iinput(...) ist unnötig. Wenn der Nutzer ein Leerzeichen eingibt, wird er belehrt, dass er eine Ganzzahl eingeben soll.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
RIN67630
User
Beiträge: 141
Registriert: Sonntag 29. April 2018, 08:07

Danke an allen.
Jetzt habe ich es so geändert:

Code: Alles auswählen

gmtoff    = "3600"       # Offset to GMT in secs
Placeholder_TZ_OFF   = b"TZ_OFF  "                 # Offset to GMT in secs (exactly  8 chars incl spaces)
gmtoff = input("How many seconds ahead (or behind -) Greenwitch is normally the device ?") or gmtoff
assert -43200 <= gmtoff <= 43200, "GMT offset must be in range -43200...43200"
gmtoff =  gmtoff.encode("ascii")
User_TZ_OFF   = gmtoff.ljust(len(Placeholder_TZ_OFF), b"\0")
So bleibe ich bei String, bis ich es anders brauche.
Benutzeravatar
sparrow
User
Beiträge: 4538
Registriert: Freitag 17. April 2009, 10:28

Namen werden in Python klein_mit_unterstrich geschrieben.

Dein Code ist genauso kaputt wie vorher. Du vergleichst noch immer Zeichenketten mit Zahlen.
RIN67630
User
Beiträge: 141
Registriert: Sonntag 29. April 2018, 08:07

sparrow hat geschrieben: Donnerstag 25. Juli 2024, 05:49 Namen werden in Python klein_mit_unterstrich geschrieben.
TZ_OFF ist der Macro-Name des C++ programs. Dort wird es als Konstante Kapitalgeschrieben
Dein Code ist genauso kaputt wie vorher. Du vergleichst noch immer Zeichenketten mit Zahlen.
War ein Kopierfehler, ist im Code korrigiert.

Code: Alles auswählen

assert -43200 <= int(gmtoff) <= 43200, "GMT offset must be in range -43200...43200"
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn Du eh schon im Binärcode herumpatchst, warum nicht gleich per:

Code: Alles auswählen

struct.pack("<i", timezone_offset)
als Zahl einfügen?
Benutzeravatar
pillmuncher
User
Beiträge: 1530
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@RIN67630:

Code: Alles auswählen

gmtoff = input("How many seconds ahead (or behind -) Greenwitch is normally the device ?") or gmtoff
assert -43200 <= gmtoff <= 43200, "GMT offset must be in range -43200...43200"
assert dient dazu, Invarianten zu testen. Benutzereingaben sind das Paradebeispiel für Nicht-Invarianten. Deswegen sollte hier ein if-Statement und nicht assert stehen. Außerdem gibt es die -O Option, mit der alle assert ausgeschaltet werden können:

Code: Alles auswählen

usage: /usr/bin/python3 [option] ... [-c cmd | -m mod | file | -] [arg] ...
Options (and corresponding environment variables):
[…]
-O     : remove assert and __debug__-dependent statements; […]
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
DeaD_EyE
User
Beiträge: 1239
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Code: Alles auswählen

assert -43200 <= int(gmtoff) <= 43200, "GMT offset must be in range -43200...43200"
Das erinnert mich an kaputten Testcode, der auch noch selbst Exceptions auslöst.
Der Aufruf der Funktion int kann zu einem Fehler (ValueError) führen, wenn der Anwender keine gültige Ganzzahl eingegeben hat.
Achja und -O optimiert assert weg.

Man kann nicht immer Code in eine Zeile pressen, wenn man auch Exceptions abfangen möchte/muss.
Wenn man das nicht tut und das Programm externe Daten verwendet, wie z.B. durch eine Benutzerinteraktion, ist das Programm fehlerhaft.

Dann noch das Problem mit den unterschiedlichen Datentypen.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
RIN67630
User
Beiträge: 141
Registriert: Sonntag 29. April 2018, 08:07

Sirius3 hat geschrieben: Donnerstag 25. Juli 2024, 08:20 Wenn Du eh schon im Binärcode herumpatchst, warum nicht gleich per:

Code: Alles auswählen

struct.pack("<i", timezone_offset)
als Zahl einfügen?
...weil der User auch noch die Werte überschreiben können muss.
Ich mache ihm das leicht, in dem ich die Geo-Werte von der IP ableite, wenn er sein Gerät dort nutzen will, wo er es auch flasht.
Wenn er es aber woanders einsetzen will, kann er immer noch die Werte manuell eingeben.
Nennt sich "Convenient Programming" !
Ausserdem soll das Patchen nur als ASCII-Array passieren: Integer oder Floats sind nicht immer gleich intern codiert (z.B: andere Endians)
RIN67630
User
Beiträge: 141
Registriert: Sonntag 29. April 2018, 08:07

pillmuncher hat geschrieben: Donnerstag 25. Juli 2024, 08:47 assert dient dazu, Invarianten zu testen. Benutzereingaben sind das Paradebeispiel für Nicht-Invarianten. Deswegen sollte hier ein if-Statement und nicht assert stehen.
Interessante Information, die die Mantra dieses Forums: "Alles steht in der Doku" widerspricht. Das steht nämlich nicht drin.
https://python-reference.readthedocs.io ... ssert.html
Ich werde es mit if() machen.
Benutzeravatar
__blackjack__
User
Beiträge: 14047
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@RIN67630 Die Dokumentation hat das hier zu ``assert``: https://docs.python.org/3.10/reference/ ... -statement

Du hast da nicht die Python-Dokumentation verlinkt, sondern etwas externes das als „Entwurf“ gekennzeichnet ist, und das seit Mitte 2015 diese Notiz vom Autor schmückt: „This project is put on the back-burner now. However, I aim to finish uploading the materials sometime this year.“
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

RIN67630 hat geschrieben: Donnerstag 25. Juli 2024, 12:36...weil der User auch noch die Werte überschreiben können muss.
Dazu ist ja Dein Programm da.
RIN67630 hat geschrieben: Donnerstag 25. Juli 2024, 12:36Ich mache ihm das leicht, in dem ich die Geo-Werte von der IP ableite, wenn er sein Gerät dort nutzen will, wo er es auch flasht.
Hat ja auch nichts mit der Frage zu tun, denn das macht ja Dein Programm dann wohl auch.
RIN67630 hat geschrieben: Donnerstag 25. Juli 2024, 12:36Wenn er es aber woanders einsetzen will, kann er immer noch die Werte manuell eingeben.
Dazu nutzt er ja Dein Programm.
RIN67630 hat geschrieben: Donnerstag 25. Juli 2024, 12:36Nennt sich "Convenient Programming" !
Hat auch nichts zu damit zu tun, wie Dein Programm die Daten in das Binary schreibt.
RIN67630 hat geschrieben: Donnerstag 25. Juli 2024, 12:36Ausserdem soll das Patchen nur als ASCII-Array passieren: Integer oder Floats sind nicht immer gleich intern codiert (z.B: andere Endians)
Deshalb ja auch little-endian, weil der Prozessor, den Du einsetzt little-endian ist.
RIN67630
User
Beiträge: 141
Registriert: Sonntag 29. April 2018, 08:07

__blackjack__ hat geschrieben: Donnerstag 25. Juli 2024, 13:17 @RIN67630 Die Dokumentation hat das hier zu ``assert``: https://docs.python.org/3.10/reference/ ... -statement
Du hast da nicht die Python-Dokumentation verlinkt, sondern etwas externes das als „Entwurf“ gekennzeichnet ist, und das seit Mitte 2015 diese Notiz vom Autor schmückt: „This project is put on the back-burner now. However, I aim to finish uploading the materials sometime this year.“
...und wo steht bei der nun "richtige" Doku in einem Meer von "falschen" Dokus, dass assert nur for immutables ist?
Benutzeravatar
__blackjack__
User
Beiträge: 14047
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@RIN67630: Nirgends, weil ``assert`` nicht nur für unveränderliche Werte ist. Wo kommt das denn jetzt her? Das wurde bei Dir ja für Zahlen und Zeichenketten eingesetzt, also für unveränderliche Werte. *Das* war ja nicht das Problem.

Ansonsten ist das Thema nicht auf Python beschränkt: https://de.wikipedia.org/wiki/Assertion_(Informatik)

Beispielsweise kennt C++ ``static_assert`` für Prüfungen zur Übersetzungszeit und ”erbt” `assert()` von C: https://cplusplus.com/reference/cassert/assert/

Von C wird wahrscheinlich auch Pythons ``assert`` inspiriert worden sein.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Benutzeravatar
pillmuncher
User
Beiträge: 1530
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

RIN67630 hat geschrieben: Donnerstag 25. Juli 2024, 15:59 ...und wo steht bei der nun "richtige" Doku in einem Meer von "falschen" Dokus, dass assert nur for immutables ist?
Nicht "immutables", sondern "Invarianten", also Bedingungen, die jederzeit wahr sind. assert besagt: "Ich, der Programmierer, garantiere, dass diese Bedingung immer erfüllt ist." Und weil der Programmierer sich irren kann, ist es ein ausführ- und testbares statement. Wenn Benutzereingaben nicht vom Programmierer kontrolliert werden können (in dem Sinne, dass die Finger des Benutzers automagisch immer nur die Tasten drücken, die der Programmierer sich wünscht), dann ist assert das falsche Mittel und if das richtige.

Im Übrigen: Die offizielle Dokumentation von Python ist hervorragend und unter https://docs.python.org/3/ zu finden.
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
DeaD_EyE
User
Beiträge: 1239
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

https://docs.python.org/3/reference/sim ... -statement
These equivalences assume that __debug__ and AssertionError refer to the built-in variables with those names. In the current implementation, the built-in variable __debug__ is True under normal circumstances, False when optimization is requested (command line option -O). The current code generator emits no code for an assert statement when optimization is requested at compile time. Note that it is unnecessary to include the source code for the expression that failed in the error message; it will be displayed as part of the stack trace.

Assignments to __debug__ are illegal. The value for the built-in variable is determined when the interpreter starts.
Normalerweise gehört das in Unittests und nicht in normalem Programmcode, der einfach wegoptimiert werden kann, worüber der Entwickler keine Kontrolle hat, wenn jemand anderes das Programm ausführt.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Antworten