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

Elemente aus Liste löschen

Beitragvon Sanji » Donnerstag 17. August 2006, 15:39

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

Beitragvon birkenfeld » Donnerstag 17. August 2006, 15:51

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:

Beitragvon Sanji » Donnerstag 17. August 2006, 18:23

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

Beitragvon Michael Schneider » Donnerstag 17. August 2006, 20:54

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:

Beitragvon Sanji » Donnerstag 17. August 2006, 21:06

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: 566
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Bremen
Kontaktdaten:

Beitragvon Michael Schneider » Donnerstag 17. August 2006, 21:27

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

Beitragvon birkenfeld » Freitag 18. August 2006, 13:02

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:

Beitragvon jAN » Freitag 18. August 2006, 22:47

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])
Benutzeravatar
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

Beitragvon Joghurt » Freitag 18. August 2006, 23:54

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

Beitragvon birkenfeld » Samstag 19. August 2006, 06:27

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

Beitragvon Python 47 » Samstag 19. August 2006, 12:08

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 :-)
Benutzeravatar
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

Beitragvon Joghurt » Samstag 19. August 2006, 12:19

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:

Beitragvon jAN » Samstag 19. August 2006, 15:04

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: 566
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Bremen
Kontaktdaten:

Beitragvon Michael Schneider » Montag 21. August 2006, 18:36

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 ...

Wer ist online?

Mitglieder in diesem Forum: Google [Bot]