Elemente aus Liste löschen

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
Sanji
User
Beiträge: 12
Registriert: Donnerstag 17. August 2006, 15:32
Kontaktdaten:

Hallo,

ich komme ursprünglich aus der PHP-welt und will mich nach 4 Jahren mal ein wenig in anderen Sprachen austoben. Dazu habe ich in Python mal ein kleines Backup-Script geschrieben. Da habe ich eine kleine Verständnisfrage:

Ich habe, um aus der Liste der Dateien/Verzeichnisse alle Dateien zu löschen, folgenden Code erstellt (und schäme mich richtig dafür):

Code: Alles auswählen

import dircache
import operator
import os
import time

backupTarget = "backup"               # das Zielverzeichnis für die Backups
directories  = dircache.listdir(".")  # das zu durchsuchende Verzeichnis (. = Verzeichnis, in dem die backup.py liegt)
winrar       = "D:\\WinRAR\\rar"      # Pfad zur Kommandozeilen-Version von WinRAR
options      = "a -r -m5 -inul"       # Optionen für WinRAR (a = hinzufügen, r = rekusriv, m5 = höchste Kompression, inul = keine Ausgabe)

# Verzeichnisse kennzeichnen
dircache.annotate('.',directories)

# Unnoetiges Verzeichnis entfernen
directories.remove(backupTarget+"/");

#
# Alle anderen Dateien entfernen
# (Sicher schrecklich gelöst, aber ich bin Phyton-Anfänger...)
#

deleted = 1

while deleted:
	for i in range(len(directories)):
		string = directories[i]
		if string[-1] != "/":
			del directories[i]
			deleted = 1
			break
	else:
		deleted = 0
Wie gesagt, ich bin von allen anderen Sprachen dieser Welt die "andere" FOR-Schleife gewöhnt und habe keinen einfacheren Weg gefunden, aus der Liste die Dateien zu entfernen. Ich habe beim Durchiterieren immer einen "Index out of bounds" (sinngemäß) erhalten. Das ist ja auch verständlich, wenn ich die Liste (oder war's ein Tupel?) beim Durchlaufen verkürze.
Aber das muss doch auch wesentlich eleganter gehen mit dem Löschen von Elementen. (Die Funktion isdir() habe ich erst nach der Variante mit dem / am Ende entdeckt (ich hab (PHP) nach is_dir() gesucht ^^).

Helft mir mal auf die Sprünge, so will ich den Code nicht lassen, das ist ja beschämend.

Sanji
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Einfach:

Code: Alles auswählen

directories = [dir for dir in os.listdir(".") if os.path.isdir(dir)]
Wenn man mit Verzeichnishierarchien arbeitet, lohnt es sich auch die Funktion os.walk anzuschauen.
Sanji
User
Beiträge: 12
Registriert: Donnerstag 17. August 2006, 15:32
Kontaktdaten:

Ausgezeichnet ... diese "List Comprehensions" scheinen ja wirklich extrem nützlich zu sein ...
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

Hallo,

das könnte man auch direkt über einen Systemaufruf lösen. Ich weiß nicht, ob das ok ist, wenn man von einem popen-Objekt direkt liest, aber man kann das ja noch strecken. Unter Windows würde das so aussehen:

Code: Alles auswählen

from os import popen
l = popen("dir /a:d /b").read().strip().split("\n")
Die Zeile führt einen Systembefehl (Suche nach Verzeichnissen, kurze Ausgabe) aus, liest das Ergebnis aus der Pipe, entfernt führende und nachstehende Whitespaces und trennt die Zeilen nach Linefeed - in der Reihenfolge. :-)

Grüße,
der Michel
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Sanji
User
Beiträge: 12
Registriert: Donnerstag 17. August 2006, 15:32
Kontaktdaten:

Ich hab jetzt auch nochmal richtig nachgelesen: Im Tutorial steht ja eindeutig: Wenn man eine Liste in einer FOR-Schleife veändern will, soll man über eine Kopie der Liste iterieren.
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

Hi Sanji,

ich bin mir jetzt nicht ganz sicher aber ich denke es ist auch möglich, wenn Du von hinten her über die Liste iterierst:

Code: Alles auswählen

for i in range(len(directories), 0, -1):
    i -= 1      # notwendig weil Index bei null beginnt
    if os.path.isdir(directories[i]) : del directories[i]
Oder besser noch Du zählst vorwärts und indizierst nur vom Ende (mit negativen Indizes). Das sieht eleganter aus. :-)

Code: Alles auswählen

iLen = len(directories)
for i in range(iLen):
    if directories[i-iLen] > 4: del directories[i-iLen]
Grüße,
der Michel
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Oder man nimmt einfach eine andere Schleife:

Code: Alles auswählen

i = 0
while i < len(directories):
    if os.path.isdir(directories[i]):
        del directories[i]
    else:
        i += 1
jAN
User
Beiträge: 170
Registriert: Samstag 4. Juni 2005, 18:51
Wohnort: Großmehlra (in Thüringen)
Kontaktdaten:

ich hab nen Einzeiler:

Code: Alles auswählen

[directories.remove(directories[i]) for i in range(len(directories)+1) if directories[i]>4]
#adios.py
import os,sys
while 1: os.startfile(sys.argv[0])
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

Ah! Meine Augen! @jAN: Nur weil es geht, muss man es noch lange nicht machen ;)

Code: Alles auswählen

[sys.stdout.write("Das ist böse!\n") for x in xrange(1000)]
Außerdem wird dann unnötigerweise eine Liste angelegt und gleich wieder gelöscht.
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Es ist auch falsch:

Code: Alles auswählen

>>> directories= [1,2,3,4,5,6]
>>> [directories.remove(directories[i]) for i in range(len(directories)+1) if directories[i]>4]
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
IndexError: list index out of range
Python 47
User
Beiträge: 574
Registriert: Samstag 17. September 2005, 21:04

Es muss so sein:

Code: Alles auswählen

[directories.remove(directories[i]) for i in range(len(directories)-1) if directories[i]>4]
mfg

Thomas :-)
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

Sag mir bitte, das das ein Scherz ist! :shock:
Das ist noch fälscher als das Ursprüngliche!
1. range(x) liefert immer nur bis x-1
2. Wenn directories=[6,5,4,3,2,1] ist, geht es auch nicht
Das liegt einfach daran, dass du über eine kopie der Liste iterieren musst.
Und das das ganze Konstrukt sowieso schlecht, unnötig kompliziert und gefährlich ist, sagte ich ja schon.
jAN
User
Beiträge: 170
Registriert: Samstag 4. Juni 2005, 18:51
Wohnort: Großmehlra (in Thüringen)
Kontaktdaten:

sry es war spät und ich hab kein python zur hand... ;)
#adios.py
import os,sys
while 1: os.startfile(sys.argv[0])
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

Hi!
Joghurt hat geschrieben: Das liegt einfach daran, dass du über eine kopie der Liste iterieren musst.
... oder rückwärts oder von hinten indizieren, siehe oben. ;-)

Grüße,
Michael
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Antworten