Logische Operatoren für datetime? (python 3.7)

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
Marco82
User
Beiträge: 19
Registriert: Samstag 4. April 2020, 21:07

Hallo zusammen,

ich habe Probleme mit einem von mir verwendeten Paket. Bei der Suche nach der Ursache bin ich auf folgendes Konstrukt gestoßen:

Code: Alles auswählen

        if first_time and time and last_time and not first_time <= time <= last_time:
            log.debug(f'Not in track (search for:{time}, start:{first_time}, end:{last_time})')
            return None
first_time, time, last_time sind alle vom type datetime.

Leider konnte ich zur logischen Verknüpfung von datetime Typen keine weiteren Informationen finden. Darum meine Fragen:
  • Kann man datetime überhaupt mit logischen Operatoren Verknüpfen?
  • Falls ja, kann mit dann vielleicht jemand mit einem Link zur Erläuterung der Funktionsweise zukommen lassen?

Vielen Dank im Voraus!
Sirius3
User
Beiträge: 18272
Registriert: Sonntag 21. Oktober 2012, 17:20

Hier werden keine Datetime-Instanzen logsich vernküpft, sondern deren Wahrheitswert.
So ist das vielleicht deutlicher:

Code: Alles auswählen

bool(first_time) and bool(time) and bool(last_time) and not (first_time <= time <= last_time)
Ich vermute mal, first_time, time and last_time können auch None sein.
Marco82
User
Beiträge: 19
Registriert: Samstag 4. April 2020, 21:07

In der Python Doku sind die unterstützen Operatoren ausdrücklich aufgeführt. And ist nicht dabei.
https://docs.python.org/3.7/library/dat ... t=datetime
Ich vermute mal, first_time, time and last_time können auch None sein.
Aber wann genau ist ein DateTime True, und wann ist er False? Und warum findest man dazu nichts bei Google, etc.?
Wenn ich Dich richtig verstehe, dann sind first_time, time und last_time immer true, wenn Sie nicht None sind?
Das kann aber irgendwie auch nicht stimmen, weil:

Code: Alles auswählen

type(datetime and datetime) == datetime
Also das Ergebnis einer "Verundung" zweier datetime Variablen ist wieder eine datetime Variable...
Sirius3
User
Beiträge: 18272
Registriert: Sonntag 21. Oktober 2012, 17:20

Was `and` für eine Operation ist, steht in der Dokumentation unter boolean-operations beschrieben.
Marco82
User
Beiträge: 19
Registriert: Samstag 4. April 2020, 21:07

Sirius3 hat geschrieben: Montag 7. September 2020, 14:47 Was `and` für eine Operation ist, steht in der Dokumentation unter boolean-operations beschrieben.
Kann es sein, dass Du den original Beitrag nicht gelesen hast?
Die Frage lautet nicht wie ein AND generell Funktioniert. Das steht ja in der Doku. Ich interessiere mich dafür, wie eine AND auf zwei DateTime oder ein DateTime und einen boolschen Wert reagiert. Dazu konnte ich weder in der Doku noch in diversen Foren eine Antwort finden.

Bekommt man hier im Forum eigentlich einen besseren Status, wenn man viele Antworten schreibt?
Jankie
User
Beiträge: 592
Registriert: Mittwoch 26. September 2018, 14:06

Was hast du denn vor, dass du auf die Idee kommst sowas zu machen?

Zur Not probiert man halt selber aus:

Code: Alles auswählen

from datetime import datetime

start = datetime(2021, 9, 8)
ende = datetime(2020, 9, 8)

print(start and ende)
print(start or ende)
print(True or ende)
print(False or ende)
print(True and ende)
print(False and ende)
Marco82
User
Beiträge: 19
Registriert: Samstag 4. April 2020, 21:07

Da ich über die Doku und diverse Foren nicht weiter gekommen bin, habe ich einen anderen Ansatz verfolgt.

Ich habe den Quelltext für DateTime gesucht (und hoffentlich an folgender Stelle gefunden):
https://github.com/python/cpython/blob/ ... atetime.py

Code: Alles auswählen

    
# ~ Zeile 744
def __bool__(self):
    return (self._days != 0 or
                 self._seconds != 0 or
                 self._microseconds != 0)
Ich habe das jetzt so verstanden, dass bei Python ein DateTime beim logischen Verknüpfungen implizit in den Datentyp Boolean konvertiert wird. Datei ist die Konvertierungsregel im Datentyp DateTime beschrieben. (Siehe oben)

Bitte widersprechen, falls meine Annahme nicht korrekt ist. Andernfalls hilft diese abschließende Antwort vielleicht einem anderen Anfänger.


Besten Dank an alle Beteiligten!
Sirius3
User
Beiträge: 18272
Registriert: Sonntag 21. Oktober 2012, 17:20

Das AND funktioniert genau so wie in der Dokumentation beschrieben, da ist es egal, welchen Typ die Operanden haben:

Code: Alles auswählen

date1 and date2
bedeutet dass als Ergebnis date1 genommen wird, wenn date1 sich im boolschen Kontext zu unwahr evaluiert, sonst date2.
Der Unwahr kann bei datetime-Instanzen nie auftreten.
Deshalb vermute ich, dass es in Deinem Beispiel auch möglich sein muß, dass date1 den Wert None annehmen kann, sonst wäre der Ausdruck unsinnig.

Solche Fragen lassen sich am besten im Interaktiven Modus des Python-Interpreters ausprobieren.
Benutzeravatar
__blackjack__
User
Beiträge: 14052
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Marco82: Du hast da die `__bool__()`-Methode von einem `timedelta`-Objekt gefunden. Das ist ”unwahr” wenn es den Wert 0 hat und sonst wahr. So einen Nullwert gibt es für `datetime`-Objekte nicht. Die übernehmen letztlich die `__bool__()`-Implementierung von `object` und die liefert bedingungslos `True`.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Benutzeravatar
DeaD_EyE
User
Beiträge: 1240
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Marco82 hat geschrieben: Montag 7. September 2020, 13:21 Bei der Suche nach der Ursache bin ich auf folgendes Konstrukt gestoßen:

Code: Alles auswählen

        if first_time and time and last_time and not first_time <= time <= last_time:
            log.debug(f'Not in track (search for:{time}, start:{first_time}, end:{last_time})')
            return None
Ich habe mir jetzt nicht alle Posts genau durchgelesen, also ist es möglich, dass es schon erwähnt worden ist.
Jedenfalls kann man bei dem Code annehmen, dass `fist_time` und `last_time` auch `None` sein können.
In diesem Fall muss man vorher den Check machen. Wenn z.B. first_time ein `None` ist, evaluiert es nach `False` und folgende AND Verknüpfungen werden erst gar nicht evaluiert.
Würde man diesen Check nicht machen, käme es zu einem Typeerror, wenn man versucht `None` zu vergleichen.

Code: Alles auswählen

message = None

if message and message.isupper():
    print("message besteht aus Großbuchtsben")
Da passiert gar nichts, weil bool(message) ein False evaluiert und folgende AND-Verknüpfungen nicht ausgeführt werden.
Würde man den ersten Test weglassen und message wäre immer noch None und kein str, dann käme es zum TypeError, da das None-Objekt nicht die Methode `isupper` hat.

Eigentlich will man das alles gar nicht. Besser ist es immer nur einen Datentyp zurückzuliefern und nicht mal so und dann wieder anders.
Wenn man aber bereits fertigen Code nutzt, hat man keinen Einfluss darauf.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Sirius3
User
Beiträge: 18272
Registriert: Sonntag 21. Oktober 2012, 17:20

@DeaD_EyE: ja, es wurde schon erwähnt. None steht für "keine Wert" und das ist eigentlich kein anderer Datentyp sondern ein Nicht-Datentyp. Das macht oft Sinn. Ob das hier so ist, kann man an zwei Zeilen Code nicht sagen.
Benutzeravatar
DeaD_EyE
User
Beiträge: 1240
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Sirius3 hat geschrieben: Donnerstag 10. September 2020, 13:00 Ob das hier so ist, kann man an zwei Zeilen Code nicht sagen.
Wenn man annimmt, dass derjenige der den Code geschrieben hat auch weiß was er da macht, dann schon.
Ich kenne dieses Muster, da ich selbst oft nach None abfrage, um einen TypeError zu verhindern.
Für mich zeigt da schon förmlich ein Pfeil drauf, auf dem "hässlich" steht. Ich mag diese Abfrage nicht.

Meine Aussage, dass None ein Typ ist, kann man hier nachlesen: https://docs.python.org/3/reference/dat ... -and-types
This type has a single value. There is a single object with this value. This object is accessed through the built-in name None. It is used to signify the absence of a value in many situations, e.g., it is returned from functions that don’t explicitly return anything. Its truth value is false.
Funktionen, die mal ein None oder einen anderen Datentyp zurückliefern, führen sehr oft zu einem TypeError.
Google: TypeError None
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Benutzeravatar
__blackjack__
User
Beiträge: 14052
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@DeaD_EyE: Also erst einmal ist `None` *kein* Datentyp sondern ein Wert. Der Datentyp ist `NoneType`.

Der Punkt ist, dass `None` ”kompatibel” mit jedem anderen Datentyp ist, weil der Wert immer mit mindestens einem anderen Datentyp verwendet wird, also stattdessen verwendet wird um auszudrücken das man ”Nichts” statt eines Wertes an der Stelle hat/haben will. So gesehen ist das kein eigenständiger Datentyp den man für sich alleine verwendet. Wenn man Typannotationen verwendet, wird man nicht `NoneType` als Typ sehen, sondern immer ``Optional[SomeOtherType]`` oder das wofür das steht: ``Union[SomeOtherType, NoneType]``. Und man kann auch ``def do_something(number: SomeOtherType = None) -> None:`` schreiben ohne das sich die Typprüfung beschwert und ohne das `SomeOtherType` von `NoneType` abgeleitet werden müsste.

Das Funktionen die einen optionalen Rückgabewert haben leichter zu Fehlern bei der Verwendung führen können stimmt zwar, aber das ist halt an einigen Stellen die sinnvollste Variante, wenn dieser Wert weder eine Ausnahmesituation darstellt noch durch das „null object pattern“ ersetzt werden kann.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Antworten