Fehlermeldung beim Umwandel von Strings in Liste

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
Smasch
User
Beiträge: 9
Registriert: Dienstag 24. Januar 2017, 17:41

Hallo Leute,

Code: Alles auswählen

    liste[i]=int(liste[i])
ValueError: invalid literal for int() with base 10: ''
Ich bekomme die oben genannte Fehlermeldung wenn ich eine Liste durchlaufe und die Zahlen Stringwerte in Zahlen umwandle. Das liegt daran das manche Indexe des Liste leer sind. Gibt es eine Möglichkeit die Fehlermeldung zu ignorieren und an den Index einen anderen Wert zu schreiben (zb. "X" oder 1)?

Wenn ich die If Anweisung vor die Datentyp Umwandlung stelle erkennt er nicht zuverlässig alle leeren Stellen.

Code: Alles auswählen

i = 0
while i<=285:
   liste[i]=int(liste[i])
   if(liste[i]==''):
      liste[i]="x"
i=i+1
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@Smasch: die Frage ist, warum sind da leere Strings in der Liste, woher kommt die Liste, wieso willst Du 'x' in einer Liste mit Zahlen, was machst Du mit der Liste weiter?
BlackJack

@Smasch: Überleg mal was da genau passiert wenn das Listenelement eine leere Zeichenkette ist.  Das ist ziemlich offensichtlich dass das so nicht funktionieren kann.

Allerdings ist das auch nicht wirklich ”pythonisch” was Du da machst. Anstelle von Indexzugriffen würde man in Python eher eine neue Liste erstellen und nicht vorhandene Listenelemente eines Typs durch die eines anderen ersetzen. Leere Zeichenketten durch 'X' zu ersetzen ist ebenfalls keine gute Idee weil man dann eine Liste hat in der Zahlen und Zeichenketten gemischt vorkommen. Das schreit geradezu nach Problemen im nächsten Verarbeitungsschritt, denn dann muss man ja irgendwie auseinanderhalten was was ist. Listen sollten immer nur Elemente vom selben Typ, oder zumindest „duck type“, haben. Als Ausnahme könnte man `None`, den Wert für ”nichts” sehen.

Selbst wenn man das mit einem Index machen würde: die ``while``-Schleife sollte dann eine ``for``-Schleife über die Indexwerte sein.
Benutzeravatar
pixewakb
User
Beiträge: 1411
Registriert: Sonntag 24. April 2011, 19:43

Wenn es nicht komplizierter wird, könnte man es auch mit einer list comprehension lösen:

Code: Alles auswählen

liste = ["1", "2", "", "4"]

neueliste = [int(i) if i != "" else None for i in liste]

print(neueliste)
Ergibt:

Code: Alles auswählen

[1, 2, None, 4]
In freier Wildbahn kann das m. E. vorkommen. Ich bekomme Daten mit Gleitkommazahlen als Strings, wo immer mal wieder ein "-" für NaN auftaucht, was auch nicht schön ist. Ich muss das nachher ausgeben und leite das dann direkt so durch, weil ein None bei mir in der Verarbeitung Probleme machte. Ist sicherlich eine unschöne Lösung, läuft aber. Soll heißen: Möglicherweise verarbeitet der Thread-Starter Daten, die er von außen bekommt.
BlackJack

@pixewakb: Aber wenn man Zeichenketten in Gleitkommazahlen wandelt wo auch ein '-' für NaN vorkommen kann, dann wird man doch eher das '-' eben durch NaN ersetzen, was ja ein gültiger Gleitkommawert ist. Andererseits kann ich mir schwer vorstellen das in einer Liste von Gleitkommazahlen ein `None` Probleme bereitet die eine Zeichenkette mit einem '-' darin nicht bereitet. Wie sieht das denn aus?
Benutzeravatar
pixewakb
User
Beiträge: 1411
Registriert: Sonntag 24. April 2011, 19:43

Ich habe hier gefunden, was Du meinst: http://stackoverflow.com/questions/9447 ... -in-python

Ich dachte, dass es nan nur bei numpy gebe, da habe ich etwas dazugelernt. Muss ich mir mal ansehen, möglicherweise kann ich das für zukünftige Software berücksichtigen.

In der Hauptsache parse ich Webseiten, rufe dortige Mess- und Datenwerte ab, verarbeite die und bereite sie für eine Anzeige wieder auf. Die Anzeige erfolgt im HTML-Bericht, wofür es ein eigenes Modul gibt, dass den HTML-Bericht generiert. Ich kann dort Python-Listen weitergeben und daraus werden dann automatisch Übersichten generiert, allerdings gibt es Probleme mit dem None-Wert, weil aktuell dann einfach HTML-Zellen fehlen, was die Anzeigen unbrauchbar macht. Das ist das erste Problem. Das zweite Problem ist, dass ich die Werte, die nicht vorliegen, in der Tabelle kennzeichen muss und NaN macht da m. E. wenig Sinn, während "-" durchaus angemessen erscheint. Ich leite das aktuell beim letzten Projekt einfach weiter. Da gibt es zu einem bestimmten Zeitpunkt halt keinen Mess- oder Datenwert, was daran liegen kann, dass er momentan nicht bereitgestellt wird oder aber zum angegebenen Zeitpunkt nicht erhoben wurde. In einem bestimmten Szenario kommt das so vor.
BlackJack

@pixewakb: Wenn bei `None` Zellen fehlen, ist das doch aber ein Problem mit dem Code der das HTML erstellt und entscheidet bei `None` keine Zelle zu erstellen, statt eine Zelle, entweder ohne Inhalt, oder mit einem Inhalt der signalisiert, dass es dort keinen Wert gibt. Also Beispielsweise den Text '-', oder 'N/A', oder was auch immer man für nicht vorhandene Werte in dem Bericht haben möchte.
Benutzeravatar
pixewakb
User
Beiträge: 1411
Registriert: Sonntag 24. April 2011, 19:43

Stimmt auch wieder, ich schaue mir mal an, was das Modul genau macht.
Smasch
User
Beiträge: 9
Registriert: Dienstag 24. Januar 2017, 17:41

Hi, die Werte aus der Liste kommen aus der SeriellenSchnittstelle.
Ich bekomme immer 100 Werte allerdings nur die die sich zur vorherigen Messung geändert haben. Also zb. 5,10,7,13,,1,9,,,6, (und so weiter). Ändert sich eine Zahl nicht bekomm ich nur das ",".

Code: Alles auswählen

daten.decode('ascii').split(",")
Teil ich den Stream in die Liste auf.
Wenn ich mir die Liste nach dem Auftrennen ausgebe habe ich an manchen Indexen leere Stellen. diese möchte ich jetzt mit den alten Werten der Vorherigen Messung füllen.
BlackJack

@Smasch: Das würde man am einfachsten mit `zip()` und den beiden Listen, und einer „list comprehension“ machen, wo der Wert eines einzelnen Elements so zustandekommt, dass man prüft ob der neue Wert eine leere Zeichen ist — dann nimmt man den alten Wert, oder ob es keine leere Zeichenkette ist — dann nimmt man die in eine Zahl umgewandelte Zeichenkette.

Bei 100 Werten verstehe ich die 285 in der Bedingung der ``while``-Schleife nicht‽
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@Smasch: Jetzt wird das Bild klarer. Du mußt Dir einfach beim Umwandeln in Zahlen den leeren Eintrag als Sonderfall behandeln:

Code: Alles auswählen

values = []
value = None
for item in daten.split(b","):
    if item:
        value = int(item)
    values.append(value)
Smasch
User
Beiträge: 9
Registriert: Dienstag 24. Januar 2017, 17:41

Danke für eure Antworten genau da liegt mein Problem ich weiß nicht wie ich die leeren Stellen ausfindig mache.
mit meiner If Anweisung hat er sie nicht alle zuverlässig gefunden.

@Sirius3 ich hab dein Code eingearbeitet leider hängt es jetzt am Zeilenende:

Code: Alles auswählen

value = int(item)
ValueError: invalid literal for int() with base 10: b'\r\n'

Edit:

ich hab es mit einer zweiten eleganten if Anweisung gelöst:

Code: Alles auswählen

for item in daten.split(b","):
   if i < 286:
      if item:
         value = int(item)
    i += 1
    values.append(value)
print(values)
ich bekomme mehr als 100 Werte


Aber ich muss gestehen ich hab die for schleife noch nicht so ganz verstanden was die genau macht

was macht das "b" in der split Funktion?
und schreibt die for schleife an jede leere stelle ein None?
BlackJack

@Smasch: Wenn Du mehr als 100 Werte bekommst dann sorge zuerst dafür das Du nur die 100 Werte hast, die Dich interessieren und schleif da nicht so einen Index mit.

``for``-Schleifen und Iteratoren sind Grundlagen, die muss man beherrschen.

Deine ``if``-Abfrage würde alle Leerstellen finden, wenn sie denn überhaupt eine Chance hätte ausgeführt zu werden. Das Codezeilen der Reihe nach ausgeführt werden ist ebenfalls eine sehr fundamentale Sache. Du kannst nicht erst umwandeln und danach testen wollen ob das eventuell eine Leerstelle ist.
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@Smasch: ein fester Zahlenwert ist nicht elegant, weil sobald sich daran etwas ändert, muß man sich daran erinnern, an dieser Stelle etwas anzupassen. Elegant wäre, die Zeileendezeichen gleich nach dem Empfangen wegzuschneiden (bytes.strip) oder auf Elemente mit nur Leerzeichen, statt auf leere Elemente zu prüfen (item.isspace()).
Benutzeravatar
snafu
User
Beiträge: 6736
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Smasch hat geschrieben:

Code: Alles auswählen

for item in daten.split(b","):
   if i < 286:
      if item:
         value = int(item)
    i += 1
    values.append(value)
print(values)
Deutlich kompakter:

Code: Alles auswählen

values = [
    int(item) if item else None
    for item in data.split(',')[:286]
]
Beim Verarbeiten von Text würde ich übrigens viel früher dafür sorgen, dass ich Strings erhalte und keine Bytes, um Dinge wie data.split(b',') zu vermeiden. Das kann man in Python schon beim Öffnen einer Datei mit den entsprechenden Flags erledigen.
Antworten