Liste wirft falsche Zahlen raus

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
Beginner123
User
Beiträge: 12
Registriert: Donnerstag 18. Oktober 2018, 07:38

Hallo, ich habe im Folgenden Code versucht über eine Liste zu iterrieren und dabei alle Elemente der Liste, die keine Zahlen (float oder int) sind aus der ursprünglichen Liste zu entfernen.
Leider schmeißt er mir die floats immer mit raus, woran kann das liegen?

Hier einmal mein Versuch:

Code: Alles auswählen

items = ["e", 1.23,"k",1.4,-1,"l"]
def test(items):
    items2 = items.copy()
    for i in items2:
        if (type(i) == (int or float)):
            pass
        else:
            items.remove(i)
    return items
test(items)
Bolitho
User
Beiträge: 219
Registriert: Donnerstag 21. Juli 2011, 07:01
Wohnort: Stade / Hamburg
Kontaktdaten:

Warum machst du die Schleife nicht direkt auf der Liste?

Code: Alles auswählen

items = ["e", 1.23,"k",1.4,-1,"l"]

def test(items):
    for i in items:
        if (type(i) == (int or float)):
            pass
        else:
            items.remove(i)
    return items

test(items)
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Die Bedingung ist aber immer noch falsch.

x == a or b

ist nicht was du denkst. Das musst du dir so geklammert vorstellen:

(x == a) or b

Und dann ist klar, dass das IMMER wahr ist, weil float wahr ist.

Stattdessen

x == a or x == b

benutzen, oder gleich

isinstance(x, (a, b))
Sirius3
User
Beiträge: 18267
Registriert: Sonntag 21. Oktober 2012, 17:20

@__deets__: falsche Klammerung, die Klammer ist um (int or float) was immer int ist, weil int schon wahr ist.

@Beginner123: Deine Bedingung lautet daher nur `type(x) == int`. In Wirklichkeit willst Du aber wahrscheinlich nicht nur int und float rauswerfen, sondern alle Arten von Zahlen? Das macht man in Python aber nicht, indem man eine Liste verändert, sondern indem man eine neue Liste generiert, die nur die Elemente enthält, die man behalten will.

Code: Alles auswählen

from numbers import Number
def test(items):
    return [x for x in items if not isinstance(x, Number)]

items = ["e", 1.23,"k",1.4,-1,"l"]
print(test(items))
oder mit filter_false

Code: Alles auswählen

from itertools import filterfalse
def test(items):
    return list(filterfalse(lambda x: isinstance(x, Number), items))
Sonstige Anmerkungen:
Bei einem if-Block mit nur `pass` würde man die Bedingung umdrehen und den else-Block als if-Block nehmen.
Eine Funktion sollte möglichst nicht die Liste ändern, die man ihr übergibt, und wenn, dann das deutlich in der Dokumentation zur Funktion beschreiben und dann None zurückgeben.

@Bolitho: die Schleife direkt über die Liste zu machen führt zu falschen Ergebnissen, wenn man innerhalb der Schleife die Liste ändert.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Sirius3 hat geschrieben: Montag 29. Oktober 2018, 10:05 @__deets__: falsche Klammerung, die Klammer ist um (int or float) was immer int ist, weil int schon wahr ist.
Bist du sicher? AFAIK hat == höhere Präzedenz. Also muss darum geklammert werden.

Edit: “muss geklammert werden” soll natürlich meinen, dass man sich die so denken muss.
Beginner123
User
Beiträge: 12
Registriert: Donnerstag 18. Oktober 2018, 07:38

Okay danke für die Hilfe, ich muss mich im Moment an den Unistoff halten und darf deshalb noch nichts importieren, ich sollte einmal die urprüngliche Liste ändern und einmal die gleiche Aufgabe bloß ohne die ursprüngliche Liste zu verändern.

@_deets_ Mit type(i) == int or type(i) == float funktioniert es jetzt :)

@Sirius für die Praxis sehen deine Beispiele deutlich besser aus, deshalb werde ich mir die Vorgehensweise auf jeden Fall merken!
Sirius3
User
Beiträge: 18267
Registriert: Sonntag 21. Oktober 2012, 17:20

@__deets__: die Klammern sind aber da, AFAIK haben die höchste Priorität: type(i) == (int or float)

@Beginner123: type zu benutzen ist aber trotzdem im Allgemeinen falsch, richiger ist __deets__ letzte Variante: `isinstance(x, (a, b))`
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

@Sirius: ah. ich habe die von ihm selbst gesetzten beim schreiben der Antwort schon wieder vergessen. Und im Kopf nur das falsche Muster "x == a or b" gehabt, das ja so auch oft vorkommt. Klar, seine Klammerung macht das natuerlich noch problematischer.
Beginner123
User
Beiträge: 12
Registriert: Donnerstag 18. Oktober 2018, 07:38

@Sirius Okay merke ich mir, wir haben in der Uni nur type als Option bekommen und den Typ herauszufinden, warum genau darf ich das nicht dafür nutzen? An welcher Stelle wäre type angebracht?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das Problem mit type ist, dass es fragil bei Vererbung ist. Wenn du sowas hier machst, siehst du das Problem:

Code: Alles auswählen

class A:
    pass

class B(A):
    pass

b = B()
print(type(b) == A)
print(isinstance(b, A))
Darum ist es besser, isinstance zu benutzen. Und es hat auch gleich einen angenehmen Mechanismus, mehrere Typen abzupruefen, was du ja tun musst.
Beginner123
User
Beiträge: 12
Registriert: Donnerstag 18. Oktober 2018, 07:38

Okay gut zu wissen, danke euch
Benutzeravatar
snafu
User
Beiträge: 6862
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@Beginner123: Am flexibelsten ist tatsächlich Number aus dem numbers-Modul. Damit fängt man alle Arten von Zahlen ab. Auch sowas wie Decimal. Wenn ihr das noch nicht hattet, dann nimm erstmal type(). Ein guter Dozent weist euch noch auf isinstance() hin. Dies ist nämlich das bevorzugte Vorgehen für Typprüfungen in Python.
Benutzeravatar
__blackjack__
User
Beiträge: 14033
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Wobei man vielleicht noch erwähnen sollte das die wirklich bevorzugte Methode für Typprüfungen in Python, wie in den meisten anderen objektorientierten Programmiersprachen, ist es gar nicht zu tun. Explizite Typprüfungen sind ein „code smell“. Es gibt einige wenige Fälle in denen man sie braucht, aber allgemein sollte man da immer zweimal drüber nachdenken warum man sie braucht oder ob man sie tatsächlich braucht. Bei gegebenen Beispiel könnte man sie beispielsweise die Frage stellen warum da überhaupt Zahlen und Zeichenketten in einer Liste gemischt werden.

Bei Python kommt noch hinzu, dass man mit expliziten Typprüfungen das „duck typing“ aushebelt und potentiell gültige Werte falsch behandelt weil der Typ ”nicht stimmt”. `Number` funktioniert zum Beispiel auch nur wenn die zahlähnlichen Typen die man vorliegen hat, auch tatsächlich davon abgeleitet sind, oder zumindest nachträglich registriert worden sind. Da kann man bei den Typen aus der Standardbibliothek wohl von ausgehen, aber ausserhalb kann das dann schon wieder anders aussehen.

Trotzdem könnte man hier auch noch `functools.singledispatch` aus der Standardbibliothek erwähnen wenn man schon beim Thema Typprüfungen ist. Und beispielsweise `decorator.dispatch_on` wenn man auch externe Module hinzuzieht.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Antworten