Probleme beim umschreiben von python 2 auf python 3

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
kangool
User
Beiträge: 12
Registriert: Mittwoch 24. März 2021, 21:30

hallo ich hoffe hier im Richtigen untergorum zu sein....

Zuerstmal ein Hallo an alle hier.

ich hab hier ein kodi addon das ich gerne mit kodi 19 benutzen würde und vieles habe ich schon selbst geschafft,
obwohl ich eigentlich ein totaler Anfänger bin was Python betrifft..
Aber mit viel lesesn und versuchen klappt es nicht so schlecht aber es gibt einen teil wo ich hänge
den häng ich hier mal an

Code: Alles auswählen

if episode_num is not None:
                        episode_num = str.encode(str(episode_num), 'ascii','ignore')
                        if str.find(episode_num, ".") != -1:
                            splitted = str.split(episode_num, ".")
                            if splitted[0] != "":
                                #TODO fix dk format
                                try:
                                    season = int(splitted[0]) + 1
                                    is_movie = None # fix for misclassification
                                    if str.find(splitted[1], "/") != -1:
                                        episode = int(splitted[1].split("/")[0]) + 1
                                    elif splitted[1] != "":
                                        episode = int(splitted[1]) + 1
                                except:
                                    episode = ""
                                    season = ""
die fehlermeldung dazu lautet wie folgt

TypeError: descriptor 'find' for 'str' objects doesn't apply to a 'bytes' object

und hier noch die komplette py
https://www.dropbox.com/s/viszyzlpbl92y ... ce.py?dl=1

vielleicht erbarmt sich mir ja einer und kann mir nen tipp geben
und auch erklären was es damit auf sich hat damit auch ich verstehe wieso weshalb warum
Herzlichen Danke
narpfel
User
Beiträge: 691
Registriert: Freitag 20. Oktober 2017, 16:10

Moin,

du versuchst die `find`-Methode für Strings mit einem `bytes`-Objekt aufzurufen. Das geht natürlich nicht.

Methoden ruft man normalerweise nicht in der Form `Class.method(instance, ...)` auf, sondern man benutzt `instance.method(...)`.

Ansonsten ist das alles reichlich kompliziert geschrieben, und 3466 Zeilen sind auch ein bisschen viel, das mal eben so auf Python 3 zu portieren. Bei dem gezeigten Code würde ich mir aber gar nicht erst die Mühe machen, sondern das komplett neu schreiben. 10 Verschachtelungsebenen in einer Funktion sind eindeutig zu viel.

Da wirst du dich selber durchkämpfen müssen. Vielleicht hilft dir etwas wie `modernize`. Und natürlich das offizielle Tutorial. Die Unterschiede zwischen Python 2 und Python 3 wirst du auch lernen müssen. Dafür gibt es zum Beispiel diesen Guide.
Sirius3
User
Beiträge: 18274
Registriert: Sonntag 21. Oktober 2012, 17:20

episode_num scheint ja schon ein String zu sein. Warum dann nochmal per str umwandeln? Warum machst Du dann aus dem String ein Bytes-Objekt? Normalerweise versucht man alles mit Strings zu machen und nur an den Rändern (Ein-/Ausgabe) kommt man, wenn überhaupt, mit Bytes in Berührung.
Um zu prüfen, ob ein Zeichen in einem String vorkommt, benutzt man nicht find, sondern den in-Operator.
Dann scheint da ja noch ein spezielles Muster erwartet zu werden. Nämlich dass exakt nur ein Punkt vorkommen darf und/oder auch noch ein "/".
Da würde man dann wahrscheinlich besser mit einem Regulären Ausdruck arbeiten.
Nackte excepts darf man nciht benutzen. Fange immer nur exakt die Exception ab, die Du auch erwartest. Hier wohl ValueError.
Seltsam ist, dass in manchen if-Zweigen Variablen gesetzt werden, in anderen nicht. Dann ist season und Episode entweder None, ein leerer String oder eine Zahl? So etwas darf niemals passieren, das ist eindeutig ein Programmierfehler.
Ebenso, dass eine Variable die is_movie heißt, entweder den String "Movie" oder None als Wert hat.

Der ganze Abschnitt sähe dann so aus:

Code: Alles auswählen

if episode_num is not None:
    match = re.fullmatch(r"(\d+)\.(\d*)(/.*)?")
    if match:
        season = int(match.group(1)) + 1
        if match.group(2):
            episode = int(match.group(2)) + 1
        else:
            episode = None
    else:
        match = re.search(r"Season\s*(\d+).*?Episode\s*(\d+)", re.I)
        if not match:
            match = re.search(r"S([0-9]+)E([0-9]+)", re.I)
        if match:
            season = int(match.group(1))
            episode = int(match.group(2))
        else:
            season = episode = None
Warum wird im ersten Fall +1 auf season und episode draufaddiert?
Machen die regulären Ausdrücke wirklich so Sinn?
Benutzeravatar
__blackjack__
User
Beiträge: 14055
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@kangool: narpfel schrob ja schon das der Code zu tief verschachtelt ist. Man möchte bei so etwas eigentlich auch gerne eine einfache Funktion die nur die Staffel und Episode aus so einer `episode_num`-Zeichenkette heraus holt und dann Unit Tests die das mal mit allen möglichen Varianten durchgeht, ob die auch tatsächlich alle funktionieren.

So etwas ist dann auch bei Portierungen/Aktualisierungen wertvoll um sicher(er) zu sein, dass der neue Code auch das macht was der alte Code schon konnte.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Benutzeravatar
__blackjack__
User
Beiträge: 14055
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@kangool: Noch mal ganz konkret zu der Ausnahme: Zwischen Python 2 und 3 hat sich der `str`-Datentyp geändert. In Python 2 gab es `str` für ”Zeichenketten” die aus Bytes bestehen und `unicode` für Zeichenketten die aus Zeichen bestehen. Und man könnte die oft einfach mischen weil die beiden Typen automagisch umgewandelt wurden, was immer dann ging wenn nur ASCII-Zeichen enthalten waren.

In Python 3 ist `str` das was in Python `unicode` war, und für eine Folge von Bytes gibt es den `bytes`-Datentyp. Und es findet keine automagische Umwandlung mehr statt. Und genau darüber stolpert Dein Code jetzt.

Du wandelst `episode_num` von `str` in `bytes` um, und versuchst dann mit `find()` in diesen Bytes eine Zeichenkette zu finden:

Code: Alles auswählen

In [54]: episode_num = "4.2"                                                    

In [55]: type(episode_num)                                                      
Out[55]: str

In [56]: episode_num = str.encode(str(episode_num), "ascii", "ignore")          

In [57]: type(episode_num)                                                      
Out[57]: bytes

In [58]: episode_num                                                            
Out[58]: b'4.2'

In [59]: str.find(episode_num, ".")                                            
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-59-7c8df1b5b7d6> in <module>
----> 1 str.find(episode_num, ".")

TypeError: descriptor 'find' requires a 'str' object but received a 'bytes'
Die Umwandlung hätte so unter Python 2 aber auch nicht wirklich funktioniert, denn die funktioniert dort nur wenn das ursprüngliche `episode_num` nur ASCII-Zeichen enthält. Nur dann macht das kodieren als ASCII mit "ignore" wenig Sinn, dessen Zweck offenbar das ausfiltern von Nicht-ASCII-Zeichen war. Bis zu dem Schritt kommt man in Python 2 aber nur wenn da keine Nicht-ASCII-Zeichen drin vorkommen. Mit Nicht-ASCII-Zeichen hätte das erste `str()` eine Ausnahme ausgelöst:

Code: Alles auswählen

>>> str(u"test")
'test'
>>> str(u"täschd")  # "Test" auf Schwäbisch. :-)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe4' in position 1: ordinal not in range(128)
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Antworten