"filter" funktioniert nicht in gewünschter Weise

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
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

Hallo,

ich möchte gerne aus einer Liste, die mit Dateinamen gefüllt ist, diejenigen raussuchen, die die Dateiendung (Suffix) "msi" haben.

Dazu habe ich mir folgendes Script gedacht:

Code: Alles auswählen

#! /usr/bin/env python

import os
import glob

AllFileList = ['C:\\tmp\\test\\new\\Putty.log', 'C:\\tmp\\test\\new\\CSES.msi', 'C:\\tmp\\test\\new\\Putty_7_sna.log', 'C:\\tmp\\test\\new\\wrapper.css']

print AllFileList

for single_file in AllFileList:
  if filter(single_file.endswith, "msi"):
    print "Filter is positive! => File: %s" % single_file
Und das kommt raus:

Code: Alles auswählen

C:\tmp>test.py
['C:\\tmp\\test\\new\\Putty.log', 'C:\\tmp\\test\\new\\CSES.msi', 'C:\\tmp\\test\\new\\Putty_7_sna.log', 'C:\\tmp\\test\
\new\\wrapper.css']
Filter is positive! => File: C:\tmp\test\new\CSES.msi
Filter is positive! => File: C:\tmp\test\new\wrapper.css
Erwarten würde ich aber nur die Datei "C:\tmp\test\new\CSES.msi"...

Warum findet der auch die "wrapper.css"-Datei?

CU,
API
webspider
User
Beiträge: 485
Registriert: Sonntag 19. Juni 2011, 13:41

filter filtert mithilfe einer Funktion (lambda bietet sich da insbesondere an) aus einer Liste Elemente aus. Hier eine funktionierende Variante deines Beispiels:

Code: Alles auswählen

file_list = ['C:\\tmp\\test\\new\\Putty.log', 'C:\\tmp\\test\\new\\CSES.msi', 'C:\\tmp\\test\\new\\Putty_7_sna.log', 'C:\\tmp\\test\\new\\wrapper.css']

print file_list
print filter(lambda x: x.endswith("msi"), file_list)
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

So, wie du filter() verwendest, testest du, ob single_file mit einem der Buchstaben "m", "s", oder "i" endet, aber nicht, ob single_file mit "msi" endet. Richtig wäre es so:

Code: Alles auswählen

for single_file in AllFileList:
  if single_file.endswith("msi"):
    print "Filter is positive! => File: %s" % single_file
In specifications, Murphy's Law supersedes Ohm's.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Und solltest du nach über 100 Posts nicht mittlerweile gelernt haben, dass es Codetags für Python gibt? ;-)
Das Leben ist wie ein Tennisball.
deets

Du hast filter nicht verstanden. filter bekommt ein Praedikat, und ein iterierbares Objekt - und liefert die Liste der Objekte, bei denen das Praedikat True liefert.

Du aber iterierst schon ueber deine Liste von Dateinamen, und statt einfach "if name.endwith("msi")" zu machen, hast du einen filter-Ausdruck gebaut, der

- ueber die Buchstaben "m", "s" und "i" iteriert
- schaut, ob der aktuelle Name auf einen davon endet.

Das stimmt natuerlich auch bei "css".

Ich wuerde dir hier auch generell stattdessen zu einer Listcomprehension (oder gen-exp) raten, statt das etwas antiquierte filter zu benutzen (das hat immer noch seinen Sinn, aber anderswo):

Code: Alles auswählen

msis = [name for name in namensliste if name.endswith("msi")]
Dann kann man natuerlich noch statt endwith fnmatch oder os.path.splitext() verwenden - das waere noch besser, denn so findest du ja auch Dateien, die nicht auf ".msi" enden.
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

Danke schonmal für eure Erklärungen.

Ich habe das jetzt mal an dem Beispiel mit dem Suffix "msi" aufgehängt, um das Problem deutlich einzuschränken.

Und ihr habt Recht - "filter" hatte ich nicht wirklich verstanden. Aber ich habe "filter" verwendet, weil ich nicht nur nach "msi"-Dateien suche, sondern evtl auch nach anderen Dateiendungen (zB "log", ...) - und da man "filter" einen Tupel übergeben kann, hielt ich das für ne brauchbare Lösung...

Kann mir dafür noch jemand nen Lösungsansatz nennen? (Alle Dateiendungen, die infrage kommen, stehen in einem Tupel)
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@api:

Code: Alles auswählen

for single_file in AllFileList:
  if any(single_file.endswith(word) for word in ('msi', 'abc', 'def')):
    print "Filter is positive! => File: %s" % single_file
Im Übrigen schließe ich mich deets Meinung an, wenn er schreibt, dass fnmatch oder os.path.splitext() besser wären, als str.endswith().
Zuletzt geändert von pillmuncher am Montag 27. Februar 2012, 16:07, insgesamt 1-mal geändert.
In specifications, Murphy's Law supersedes Ohm's.
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

@eyDu: Das könnte ich wirklich mal in Angriff nehmen... :? :D
Antworten