Liste und List Comprehension unzuverlässig?

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.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Code: Alles auswählen

string_list = ["Andreas", "Andre", "Andrew", "Anderson", "Anton"]

search_term = "An"

for element in string_list:
    if search_term in element:
        print "List of the elements", element
Ausgabe:
List of the elements Andreas
List of the elements Andre
List of the elements Andrew
List of the elements Anderson
List of the elements Anton

Code: Alles auswählen

string_list = ["Andreas", "Andre", "Andrew", "Anderson"]

search_term = "An"
if [element for element in string_list if search_term in element]:
    print "Search found: ", element
else:
    print "Nothing there"
Ausgabe:
Search found: Anderson
Eine Frage vorab: Wieso springt das Suchergebnis hier auf Anderson und nicht anstatt auf Andreas? Hat meine Suchfunktion - im wahrsten Sinne sdes Wortes, einen Sprung in der Schüssel?


Eines haben die beiden doch gemeinsam, und zwar, sind die "unzuverlässig". Ich hatte folgende Vorstellung. In einer Liste werden bestimmte Variablen geladen, die dann überprüft werden soll, also ob ein bestimmtes Element in der Liste vorhanden ist, wenn nicht, dann soll das Programm etwas anderes tun, wenn ja, dann auch wieder was anderes. Aber wir sehen in meinen beiden Beispielen, dass wir hier mehrere Namen haben, die alle mit "An" beginnen. Bei der Suche wird "fälschlicherweise" behauptet, dass es das Element "An" gibt. Dies hat eher das Verhalten einer Like-Operation von MySQL. Gibt es eine Möglichkeit, dass man sagen kann, dass er genau und exakt nach dem Wort "An" in der Liste suchen soll und nicht nach Ähnlichkeiten?
BlackJack

@Sophus: `element` ist im ersten Fall an 'Anderson' gebunden weil das der letzte Wert ist der an den Namen `element` in der „list comprehension” (LC) gebunden wird. In Python 3 wäre das übrigens ein `NameError` weil `element` dort nicht mehr ausserhalb der LC zur Verfügung steht. Du ”nutzt” hier also Verhalten was die Python-Entwickler als Fehler in der Sprache angesehen haben und in Python 2.x nur nicht behoben haben weil ja jemand auf diesen Fehler aufbauen könnte.

Und zum zweiten: Da ist überhaupt nichts unzuverlässig, das macht genau das was Du programmiert, aber so anscheinend nicht gewollt hast. Das hat auch mit Listen und LCs überhaupt gar nichts zu tun. Ein Test ``a in b`` prüft halt ob `a` in `b` *enthalten* ist, und nicht ob `a` und `b` gleich sind. Dafür gibt es den ``==``-Operator.
karolus
User
Beiträge: 141
Registriert: Samstag 22. August 2009, 22:34

Hallo

das untere prüft ob die gerade generierte Liste `wahr` ist, das ist sie im Laufe der List-comprehension, nachher (surprise) hängt "Anderson" das letzte Element der Liste am Namen `element`....
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

@BlackJack: Besten dank. Ich dachte, ich könnte auf == Operator verzichten, da dies bei der Suche sowohl in der Liste als auch in der LC den gleichen Effekt hätte - falsch gedacht. Aber jetzt weiß ich es natürlich besser. Da ich im Vorfeld nicht weiß, ob die Variablen auch Umlaute oder dergleichen haben könnte, die da in die Liste geladen werden, wäre es bestimmt sinnvoll, wenn ich die Liste in unicode umwandle oder?
Ich dachte dabei an sowas:

Code: Alles auswählen

string_list = unicode(["Überraschung", "Andreas", "Andre", "Andrew", "Anderson"])

search_term = u"Überraschung"

for element in string_list:
    if search_term == element:
        print "List of the elements", element
Aber das mit dem Unicode will nicht so ganz klappen.
BlackJack

@Sophus: `unicode()` hat als Ergebnis eine Unicode-Zeichenkette mit einer Darstellung von dem was als Argument übergeben wurde. Also in diesem Fall eine Zeichenkettendarstellung der Liste. Du willst da ja aber eine Liste in der jedes einzelne Element in eine Unicode-Zeichenkette umgewandelt wird. Das musst Du dann halt auch so sagen. Könnte man mit einer LC machen. :-) Wobei wenn das Bytestrings sind, ich ja eher die `decode()`-Methode statt `unicode()` verwenden würde. Denn die Kodierung in der die Byteketten vorliegen musst Du auch angeben, sonst gibt's eine Ausnahme sobald etwas ausserhalb von ASCII in den Zeichenketten steht.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

@BlackJack: Ich bin ein wenig verwirrt. Wo gebe ich es an, dass die einzelnen Elementen in Unicode umgewandelt werden? Das in meinem Beispiel die Strings im Quelltext bekannt sind, ist ja nur ein Beispiel. Im späteren Verlauf sollen bestimmte Informationen aus einer Datei in eine Liste geladen werden, und da kann ich die Strings nicht direkt mit einem 'u' vor dem String arbeiten. Oder meinst du etwa, dass ich im Schleifenkörper die Elemente einzeln in Unicode umwandeln soll?
BlackJack

@Sophus: Genau, wenn man die einzelnen Elemente umwandeln will, muss man das in einer Schleife (oder etwas vergleichbarem) machen. Also ``for``-Schleife, „list comprehension”, Generatorausdruck, oder wenn man eine Funktion hat die ein einzelnes Element umwandelt vielleicht auch `map()` oder `itertools.imap()`. Je nach dem ob man eine Liste braucht oder auch ein iterierbares Objekt ausreicht welches ”lazy” ausgewertet und ”verbraucht” wird.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Code: Alles auswählen

string_list = ["Überraschung", "Andreas", "Andre", "Andrew", "Anderson"]
 
search_term = u"Überraschung"
 
for element in string_list:
    unicode(element) # convert to unicode-string
    if search_term == element:
        print "List of the elements", element

Ich könnte hierbei also auf die Kodierung (# -*- coding: utf-8 -*-) verzichten, ja? Gut, in meinem Beispiel müsste ich diese Kodierung verwenden, weil die Strings ja im Quelltext stehen, und Python damit ein Problem hätte. Aber es kann ja sein, dass jemand chinesische, russische, arabische oder sonstige Informations-Zeichenketten in eine txt-Datei schreibt und diese Informationen dann in meine Liste laden will.
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@Sophus: Wenn Du irgendwelche Zeichen aus einer Datei lesen willst, mußt Du natürlich deren Encoding kennen. Genauso wie Du das Encoding Deiner Python-Datei kennen mußt, um die Bytestrings richtig decodieren zu können. Der Aufruf von "unicode" hilft da nichts, und wird nur eine Fehlermeldung bringen. Aber das hättest Du selbst sehen können, wenn Du Dein Programm nur einmal ausführst. Was glaubst Du macht Zeile 6 in Deinem letzten Posting? (Überraschung!)
Der Fall, daß man irgendwo zwischen drin etwas decodieren muß, sollte aber nie auftreten. Der normale Vorgang ist, Bytes laden -> in Zeichen umwandeln -> nur noch mit Unicode arbeiten.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@Sophus:
Den Benutzer mit dem Editor seiner Wahl Dateien nach Gutdünken editieren lassen, ist eine schlechte Idee. Gerade unter Windows kommst Du damit in Teufels Küche, da im schlechtesten Falle die Dateien am Ende nur noch Bytesalat für Dein Programm sind. Abhilfe schafft da:
- externes Editieren "verbieten"
- über eigene Editorkomponente + Encoding alles vorgeben
- das Encoding fest vorgeben ("stelle in Deinem Editor Encoding XY ein" - Achtung: können nicht alle Editoren)
- Encoding beim Einlesen in Dein Programm wählen lassen (nur für fortgeschrittene Benutzer zu gebrauchen; die wenigsten wissen, was ein Encoding ist)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

jerch hat geschrieben:@Sophus:
- (... die wenigsten wissen, was ein Encoding ist)
Das trifft leider auch immer noch auf viel zu viele Entwickler zu :-(

Ich verweise an dieser Stelle wieder einmal auf meine Signatur :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

@Sirius3: Ich finde es irgendwie befremdlich, wenn man mich eine Sache zwei Mal fragt. Im Quelltext habe ich bereit in Zeile 6 kommentiert, was ich glaube, was die Zeile tut, aber ich zitiere nochmal 'convert to unicode'. Ich habe gehofft, dass ich im Schleifenkörper die einzelnen Elemente in Unicodes umwandeln kann. Und nein, bei mir wurden keine Fehlermeldungen geworden.

@jerch: Wie kann ich jemanden "verbieten", dass er oder sie mit einer Datei arbeiten darf? Die Datei etwa während der Laufzeit meines Programms geöffnet lassen? Wäre ja fatal, wenn das Programm mal abstürzt, dann wäre die Datei weiterhin "geöffnet".
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Sophus hat geschrieben:@jerch: Wie kann ich jemanden "verbieten", dass er oder sie mit einer Datei arbeiten darf? Die Datei etwa während der Laufzeit meines Programms geöffnet lassen? Wäre ja fatal, wenn das Programm mal abstürzt, dann wäre die Datei weiterhin "geöffnet".
Gar nicht bzw. nicht ohne absurde Verrenkungen (deshalb die Anführungszeichen). Ich würd die Benutzer darauf hinweisen es nicht zu tun, wenn sie es trotzdem machen dann auf eigene Gefahr.
BlackJack

@Sophus: Das Dein Programm bei der Zeile keine Ausnahme ausgelöst hat ist nicht möglich. In `string_list` steckt eine Byte-Zeichenkette mit Werten ausserhalb von ASCII, da *muss* `unicode()` eine Ausnahme auslösen wenn keine Kodierung beim Aufruf angegeben wurde:

Code: Alles auswählen

[15]: string_list = ["Überraschung", "Andreas", "Andre", "Andrew", "Anderson"]

In [16]: unicode(string_list[0])
---------------------------------------------------------------------------
UnicodeDecodeError                        Traceback (most recent call last)
<ipython-input-16-6560869cb5de> in <module>()
----> 1 unicode(string_list[0])

UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)
Bei Dir unterscheidet sich vielleicht der Bytewert in der Fehlermeldung weil der von der Kodierung abhängt in der Dein Quelltext verfasst wurde, und genau deswegen muss man ja die Kodierung angeben, weil die nicht klar ist wenn man einfach nur einen Haufen Bytes vor sich hat.

Edit: Oh, und der Aufruf in Zeile 6 verändert `element` natürlich nicht, man müsste den Rückgabewert vielleicht an einen Namen binden und den dann im weiteren Verlauf verwenden.
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@Sophus: scheinbar habe ich noch nicht oft genug gefragt. Solche Fragen haben ja den Sinn, dass sich der gefragte über die Zeile nochmal Gedanken macht, sie mal im interaktiven Modus ausprobiert und einfach gesagt, versteht, was da passiert, ohne dass ich jetzt alles haarklein vorkauen muss. Und wenn Du keine Fehlermeldung bekommst, dann machst Du etwas anderes, als das, was Du hier zeigst.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Ich bin gerade mit meinem Smartphone online, daher werde ich mich etwas kürzer fassen. Das man in den Modulen bestimmte Kodierungen anwendet, wenn etwas außerhalb des ASCII-Wertes ist , weiss ich ja ;-) Aber weiten wir mal mein Beispiel etwas weiter aus. Wenn ich mit der GUI arbeite und der Anwender in der lineEdit bestimmte Informationen eingibt, Enter drückt bzw. eine Schaltfläche betätigt, sollen die Informationen zunächst in eine Liste hinzugefügt werden. Über der Konsole hätte ich wohl keine Probleme wenn ich mit raw_input() arbeite. Aber im Falle der GUI kann ich das Modul schlecht kodieren, wenn ein Russe dran sitzt und Informationen eingibt .
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@Sophus: GUI-Rahmenwerke liefern ja im Normalfall schon Zeichen und keine Bytes. Du hast also das Problem gar nicht.
BlackJack

@Sophus: Oder anders ausgedrückt beim `raw_input()` *hättest* Du gerade das Problem das das Bytestrings liefert die Du dekodieren musst und dazu wissen müsstest in welcher Kodierung der Russe seine Texte übergibt.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Hallo BlackJack und Sirius3,

wenn ich euch also richtig verstehe, kann ich die Daten, die über das GUI-Rahmenwerk eingegeben wurde, ohne "Umwege" verarbeiten? Zum Beispiel, kann ich dann die Daten aus dem Rahmenwerk ohne De bzw. Umkodierung in eine Datenbank übernehmen? Was mir aber in diesem Zuge noch einfällt. Wenn ich bestimmte Informationen aus dem GUI-Rahmenwerk in einen SHA- und/oder MD5-Wert umwandeln will, brauche ich auch hier keine Umkodierung vornehmen? Nehmen wir an, der Russe gibt sein Passwort ein, dieses will ich dann in einen entsprechenden Wert (md5, SHA etc...) umwandeln, muss ich da nicht erst in Unicode umschwenken?
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@Sophus: hash-Funktionen arbeiten normalerweise auf Byte-Ebene. Deshalb muß ein Passwort encodiert werden. Am besten mit utf8.
Antworten