string OR string IN 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.
Antworten
getafix
User
Beiträge: 2
Registriert: Dienstag 30. Juli 2024, 15:55

Moin,

ich bin ziemlicher Anfänger und weiß deshalb auch noch nicht mit welchen Begriffen ich ein Problem sinnvoll beschreibe.
Das schonmal im Vorraus, falls die Frage schon öfter beantwortet wurde.

Ich habe folgendes Problem:
Ich möchte testen ob stringA (".txt") oder stringB (".docx") in einem Teststring drin sind. Mit nur einem string funktioniert alles super, aber sobald ich "or" oder "and" hinzufüge, werden alle Teststrings zu type = 1.

Code:

Code: Alles auswählen

def datatype(name):
    type = 0
    if ".txt" or ".docx" in name:
        type = 1
    elif ".xlsx" in name:
        type = 2
    print(type)

#Teststrings:
datatype("blablabla.txt")
datatype("blablabla.xlsx")
datatype("blablabla")
Output:
1
1
1

Mir würden auch alternative Lösungen einfallen, wie zb. eine eigene elif-Abfrage für ".docx", aber ich würde gerne verstehen, warum das "or" nicht so funktioniert, wie ich es mir vostelle.

Danke schonmal!
Sirius3
User
Beiträge: 18251
Registriert: Sonntag 21. Oktober 2012, 17:20

`or` verknüpft zwei Ausdrücke miteinander `a or b` bedeutet, falls a zu "wahr" ausgewertet wird ist das Ergebnis a sonst b.
".txt" ist immer wahr, also ist das Ergebnis Deiner if-Abfrage immer wahr und damit immer type = 1.

Der in-Operator ist hier auch zu generisch, weil Du möchtest ja, dass der Dateiname mit der entsprechenden Endung endet.

Solche Probleme löst man mit passenden Datenstrukturen. Um mit Dateinnamen zu arbeiten gibt es pathlib.Path:

Code: Alles auswählen

from pathlib import Path

SUFFIX_TO_TYPE = {
    ".txt": 1,
    ".docx": 1,
    ".xlsx": 2,
}

def get_datatype(name):
    return SUFFIX_TO_TYPE.get(Path(name).suffix, 0)

#Teststrings:
print(get_datatype("blablabla.txt"))
print(get_datatype("blablabla.xlsx"))
print(get_datatype("blablabla"))
Benutzeravatar
__blackjack__
User
Beiträge: 14000
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@getafix: Anmerkung zur Namensgebung: Funktionsnamen (und Methodennamen) beschreiben üblicherweise Tätigkeiten um sie leichter von eher passiven Werten unterscheiden zu können. `datatype` wäre ein guter Name um einen Wert zu bezeichnen der einen Datentyp repräsentiert. Also für das *Ergebnis* einer Funktion die den Datentyp ermittelt.

`type()` ist der Name einer eingebauten Funktion, den sollte man möglichst nicht an etwas anderes binden.

Wenn das nicht für eine andere API notwendig ist, würde man eher nicht ”magische” Zahlen erzeugen/verwenden die irgendwas bedeuten was man zusätzlich wissen muss. 0, 1, und 2 können ja für alles mögliche stehen. Für Aufzählungstypen gibt es das `enum`-Modul in der Standardbibliothek.

Code: Alles auswählen

#!/usr/bin/env python3
from enum import Enum, auto
from pathlib import Path


class DocumentType(Enum):
    UNKNOWN = auto()
    TEXT = auto()
    SPREADSHEET = auto()


SUFFIX_TO_DOCUMENT_TYPE = {
    ".docx": DocumentType.TEXT,
    ".txt": DocumentType.TEXT,
    ".xlsx": DocumentType.SPREADSHEET,
}


def get_document_type(path):
    """
    >>> get_document_type("spam.docx")
    <DocumentType.TEXT: 2>
    >>> get_document_type("ham.xlsx")
    <DocumentType.SPREADSHEET: 3>
    >>> get_document_type("parrot.gif") is DocumentType.UNKNOWN
    True
    """
    return SUFFIX_TO_DOCUMENT_TYPE.get(Path(path).suffix, DocumentType.UNKNOWN)
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
getafix
User
Beiträge: 2
Registriert: Dienstag 30. Juli 2024, 15:55

Vielen Dank!! Ich schaue mir nochmal in Ruhe alles an!
B-second
User
Beiträge: 1
Registriert: Sonntag 4. August 2024, 10:50

Hallo,

Wie bereits beschrieben, gibt es zur Auswertung von Dateiendungen sicherere Verfahren.
Aber vllt. will man als Einsteiger erstmal grundlegende Dinge verstehen. :idea:

In diesem Code werden die übergebenen Strings nie geprüft, da der Ausdruck

Code: Alles auswählen

if ".txt" ...  
immer nach "True" ausgewertet wird. Somit ist die or-Bedingung ab diesem Punkt immer erfüllt und endet mit

Code: Alles auswählen

 type = 1
Grundsätzlich kann dein Code schon funktionieren. Du musst nur die Auswertung ändern in:

Code: Alles auswählen

 if ".txt" in name or ".docx" in name: 
dann geht es.


MfG
B-second
Benutzeravatar
sparrow
User
Beiträge: 4526
Registriert: Freitag 17. April 2009, 10:28

@B-second: Wie das robust geht, hat __blackjack__ bereits gezeigt. Deine Lösung prüft nicht auf die Dateiendung (wie eigentlich gewünscht), sondern ob das der String in dem anderen enthalten ist. Das sind unterschiedliche Dinge.
Es gibt Szenarien, bei denen ein Dateiname erweitert wird. Und deine Bedingung würde auch auf "document.txt.gz" zutreffen - obwohl das gar keine reine Textdatei ist. Und die berühmten "liesmich.txt.exe" übrigens auc.
Antworten