Os.walk Problem

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
HrSumsemann
User
Beiträge: 28
Registriert: Donnerstag 19. Februar 2015, 17:32

Hallo allerseits,
ich habe kürzlich begonnen mich mit Python zu befassen (Neuling) und bin dran ein kleines Skript zu schreiben.
Ich möchte einkleines Skrip erstellen, welches einen definierten Ordner nach weiteren Unterordnern durchsuchen soll und nach bestimmten Kriterien relevante Daten speichert.
Nun hänge ich beim os.walk, und zwar sollte dieser ab "path_folderplot" starten, startet jedoch ein Verzeichnis zu weit oben, sprich path_main.

Zum Aufbau des Skriptes:
-main.py ist das ausgeführte Programm
-classes.globvars beinhaltet allgemeine Variablen wie Pfade etc.
-classes.fldplot ruft die os.walk funktion auf.

main.py

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

#Importieren der Variablen
from classes.globvars import *

#Auswahlmenu
 while not is_valid:
      try:
         choice = int (raw_input('enter your choice: ') )
         is_valid = 1
      except ValueError, e:
         print ("'%s' is not a valid input." % e.args[0].split(": ")[1])
#

if choice == 1:
         if not os.path.exists(path_folderplot):
            os.makedirs(path_folderplot)
         else:
            print "Ordner exisitiert bereits!"
         import classes.fldplot
         classes.fldplot.folderscan()

classes.globvar

Code: Alles auswählen

def gpaths():

  import os, sys   
  path_main = "//pyscripts//automat"
  path_folderplot = path_main+os.sep+"_datafiles-folderplot"      

classes.fldplot.folderscan()

Code: Alles auswählen

def folderscan():
        import os
        from classes.globvars import *
        os.chdir(path_folderplot)
        pathscan = os.getcwd()
        for root, dirs, files in os.walk(pathscan):
               
                for file in files:
                        print files
                        if len(files) == 1:
                                print "-->", os.path.abspath(file), "is ok!"
                        elif len(files) >1:
                                print "->", os.path.abspath(file), "ignored!"
                                print "<<< Zu viele Dateien im Ordner"



Hat jemand eine Idee.
BlackJack

@HrSumsemann: Bitte Zeige tatsächlichen Code. Der gezeigte kann so nicht funktionieren da er Syntaxfehler enthält, also nicht einmal kompiliert, und die Namen in `classes.globvar` lokal innerhalb einer Funktion definiert sind, also gar nicht ausserhalb verwendet werden können.

Ansonsten bitte einen Blick in den Style Guide for Python Code werfen. Insbesondere: Einrücken konsistent mit vier Leerzeichen pro Ebene, Importe am Anfang des Moduls, und keine Sternchenimporte. Da kann doch sonst niemand mehr den überblick behalten. BTW ist ein Sternchenimport innerhalb einer Funktion oder Methode sogar ein Syntaxfehler, das geht überhaupt nicht.

`os.chdir()` sollte man nicht verwenden. Das ändert einen globalen Zustand des Prozesses. Andere Stellen des Codes gehen dann vielleicht von einem anderen Arbeitsverzeichnis aus und greifen auf falsche Pfade zu. Da kann man ganz schnell durcheinander kommen.

Ein Package oder Modul `classes` zu nennen ist ungewöhnlich. Der Name sagt so gut wie nichts aus. Man teilt Code nicht nach allgemeinen Datentypen auf sondern nach semantischen Gesichtspunkten. Also nicht alle Klassen in ein Package/Modul und alle Funktionen in ein anderes sondern Klassen und Funktionen die sinvoll zusammengehören in ein Package/Modul. Das ist als wenn man Bücher in einer Bibliothek nach Farbe des Einbands und grösse der Bücher sortieren würde statt nach Fachgebieten und alphabetisch. Ersteres sieht zwar aufgeräumt aus, ist aber unpraktisch wenn man etwas sucht.
HrSumsemann
User
Beiträge: 28
Registriert: Donnerstag 19. Februar 2015, 17:32

So hier nochmal die gesamten Skripte, sorry ;)

Es liegt außerdem eine __init__.py in classes, diese ist aber leer.

main.py

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-



import os, fnmatch, subprocess, sys 
from classes.globvars import *
path_main, path_classes, path_folderplot = gpaths()


#M-A-I-N

for pathname, directories, files in os.walk(path_classes):
   for file in files:
      if fnmatch.fnmatch(file, '*pyc'):
         print file
         os.remove(path_classes+os.sep+file)
      else:
         continue
       

def mainmenu():
   is_valid = 0

   while not is_valid:
      try:
         choice = int (raw_input('enter your choice: ') )
         is_valid = 1
      except ValueError, e:
         print ("'%s' is not a valid input." % e.args[0].split(": ")[1])
###E-X-I-T

      if choice == 0:
         print "exit program"
         exit()
 
###F-O-L-D-E-R--P-L-O-T

      if choice == 1:

         import classes.fldplot
         if not os.path.exists(path_folderplot):
            os.makedirs(path_folderplot)
            print"--->created ", path_folderplot
         else:
            print path_folderplot, "already exists, continue..."

         print 'press any key to continue...'
         raw_input()


         classes.fldplot.folderscan()


mainmenu()
globvars.py in /classes

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

def gpaths():
	
  import os, sys   
  path_main = "//home//markus//Schreibtisch//pyscripts//automat"
  path_classes = path_main+os.sep+"classes"
  path_folderplot = path_main+os.sep+"_datafiles-folderplot"      
  return  path_classes,path_folderplot, path_main


fldplot.py in classes

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-





def folderscan():
        import os
        
        
        from classes.globvars import *
        path_main, path_classes, path_folderplot = gpaths()
       
        #print path_folderplot
        #<---- SCAN FOLDERS ---->
        print "--> os.walking now..."
        os.chdir(path_folderplot)
        pathscan = os.getcwd()
        for root, dirs, files in os.walk(pathscan):
               
                for file in files:
                        print files
                        #<-- ORDNERUEBERPRUEFUNG -->
                        if len(files) == 1:
                                print "-->", os.path.abspath(file), "is ok!"
                        elif len(files) >1:
                                print "->", os.path.abspath(file), "ignored!"
                                print "<<< Zu viele Dateien im Ordner"

        print "press any key to continue..."                        
        raw_input()
    


Einrückungen sind immer mit Tabstopps gemacht, bzw. automatisch, von emacs.
Was ist die alternative zu chdir? Hatte das zunächst nicht drinnen stehen, da ich von aus ging, dass os.walk automatisch in den Ordner geht, da das aber nicht passiert ist, hatte ich das eingefügt (naja hat auch nicht geholfen :| )



Danke für die Hilfe :)
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@HrSumsemann: Deine Tabs sind also mal 2 und mal 8 Leerzeichen breit? Nimm 4 Leerzeichen, dann hast Du später weniger Probleme. *-importe sind schlecht, weil man nicht kontrollieren kann, was da in den eigenen Namensraum importiert wird. globvars ist ein sehr seltsames Modul. Global sollten Variablen nicht sein, da wird auch nur eine Funktion definiert, die drei Pfade zurückgibt, was das "g" in "gpaths" heißen soll, weißt Du in einer Woche selbst nicht mehr. Namen sollten aussagekräftig sein.
Zeile 17: Pfade setzt man nicht mit + sondern mit os.path.join zusammen.
Zeile 19: Was hat das continue für einen Effekt?
Die Leerzeilen in mainmenu machen das Lesen sehr umständlich.
Zeile 41: imports sollten alle am Anfang der Datei stehen.

Welches Betriebssystem benutzt Du, wo Pfade mit doppelten / getrennt werden?
In folderscan solltest Du überlegen, was die Parameter sind, die in der Funktion gebraucht werden. Die Funktion kann bisher nur mit einem festen Pfad verwendet werden, ist also so gut wie nutzlos, was wiederverwendbarkeit betrifft. Was glaubst Du, welchen Wert pathscan in Zeile 18 hat? chdir verändert einen globalen Zustand des Programms und sollte nicht benutzt werden.
Was soll die for-Schleife in Zeile 22, wenn Du innerhalb auf files prüfst? Was soll überhaupt die ganze Funktion machen? Ihr fehlt ein Rückgabewert.
HrSumsemann
User
Beiträge: 28
Registriert: Donnerstag 19. Februar 2015, 17:32

Hi,
-Tabs werde ich anpassen, ist alles Grundeinstellung
- Da mir Pfade bissel Probleme machen, habe ich mir gedacht, wäre es sinnvoll, diese einmal fest zu definieren, dass ich keine Probleme bekomme später. Das g war auf global bezogen, aber ja das macht durchaus sinn, länger auszuschreiben
- Ich hatte Probleme mit dem .pyc Daten in den Classen, daher dachte ich mir, eine Abfrage am Anfang wäre nicht verkehrt, die die Daten löscht, sofern sie bestehen. Mit dem continue wollte ich eigentlich , dass er einfach fortfährt, aber das macht er ja auch so ^^
- Ich benutze Ubuntu, hatte mal Problem mit nur einem /, nachdem ich zwei eingesetzt hatte, hat es komischer weise funktioniert.


Ich wollte zunächst das das Programm vom Pfad aus, wo main.py liegt, den Ordner pathplot anlegt, sofern er nicht vorhanden ist, ich meine Daten ablege, und dann die Routine durchläuft. Einfachheitshalber hatte ich zunächst einen Pfad vorgegen für main_path. Die Abfrage mit lenfliles habe ich drinnen, da ich später eine Liste anlegen möchte, in der in der ersten Spalte, der jeweilige Ordner steht (wollte ich mir aus abspath über den split dann rausholen) und in der zweiten Spalte der Absolutpfad der darin liegenden Datei. Und mehrere Dateien in einem Ordner da nicht praktikabel wären ;)
Also folderscan soll path_folderplot durchsuchen, wenn es einen Ordner findet, indem sich eine Datei befindet, soll er den Ordnernamen und den zugehörigen Dateipfad in eine Liste schreiben.


Meinst du pathscan Zeile 19? Wenn ja denke ich, bin ich von augegangen, dass es den Pfad von path_folderplot besitzt.

Wie gesagt, ich bin erst seit kurzen an python dran , daher verzeiht bitte die vermutlich vielen leichtsinns Fehler ;)
BlackJack

@HrSumsemann: Warum stecken die Pfade dann in einer Funktion statt sie einfach als Konstanten auf Modulebene zu definieren? Aber auch dann sollte man die nicht überall in den Funktionen direkt verwenden sondern als Argument übergeben. Damit man die Funktionen leichter testen und wiederverwenden kann.

Sowohl das löschen der `pyc`-Dateien als auch der doppelte '/' in Pfaden sind Voodoo. Was immer Du auch denkst was Du damit an Problemen löst: Die existieren nicht.

Für Wahrheitswerte hat Python `True` und `False`, da sollte man keine Zahlen für verwenden. Wobei man sich das `is_valid` auch sparen kann wenn man eine ”Endlosschleife” schreibt (``while True:``) die im Erfolgsfall mit ``break`` verlassen wird. Oder mit ``return`` wenn man das in eine Funktion heraus zieht.

Ich weiss nicht ob ich mich auf die Werte im `args`-Attribut einer Ausnahme auf diese Weise verlassen würde. Robuster wäre es sich einfach die Eingabe zu merken statt sie indirekt aus der Fehlermeldung wieder heraus zu fischen.

``print`` ist in Python 2 keine Funktion (solange man nicht `print_function` aus `__future__` importiert), darum sollte man das auch nicht so schreiben als wäre es eine. Spätestens wenn man mehr als einen Wert ”übergibt” verhält sich das nicht mehr so wie man das erwartet, weil man dann keine sinnlosen Klammern mehr hat, sondern ein Tupel erzeugt.
HrSumsemann
User
Beiträge: 28
Registriert: Donnerstag 19. Februar 2015, 17:32

Alles klar, werde versuchen die Fehler auszumerzen.
Eine Frage habe ich noch. Die globalen Variablen (Pfade) habe ich gesetzt, um aus dem Modul fldplot.py den Pfad path_folderplot abgreifen zu können. Gibt es einen einfacheren Weg den Pfad im main.py festzulegen und dann in fldplot.py abrufen zu können?
BlackJack

@HrSumsemann: Übergib den Pfad als Argument an die Funktionen die ihn brauchen.
HrSumsemann
User
Beiträge: 28
Registriert: Donnerstag 19. Februar 2015, 17:32

@BlackJack
Also im main.py eine entsprechende Funktion definieren, welche den Pfad returnt?

so in etwa?

Code: Alles auswählen

path_main = os.getcwd()
def pfaduebergabe():
    path_folderplot = os.path.join(path_main, r"_datafile-folderplot")
    return path_folderplot
Danke für die Hilfe :)
BlackJack

@HrSumsemann: Nein, einfach eine Konstante auf Modulebene definieren und den Wert dann der Funktion die etwas damit machen soll als Argument übergeben. Konstantennamen schreibt man per Konvention komplett in Grossbuchstaben. Und vergiss erst mal das es `os.chdir()` und `os.getcwd()` gibt. Du stellst damit anscheinend nur Unsinn an.
HrSumsemann
User
Beiträge: 28
Registriert: Donnerstag 19. Februar 2015, 17:32

Alles klar werde ich mal versuchen, das getcwd() habe ich mir gedacht, um die Flexibilität bei anderen Pfaden zu ermöglichen.
BlackJack

@HrSumsemann: Das aktuelle Arbeitsverzeichnis ist ja sowieso der Startpunkt für relative Pfade. Es macht also wenig Sinn das zu ermitteln und vor einen relativen oder absoluten Pfad zu hängen weil der dadurch entstehende Pfad effektiv der gleiche ist als wenn man das einfach bleiben lassen würde.
HrSumsemann
User
Beiträge: 28
Registriert: Donnerstag 19. Februar 2015, 17:32

Wenn ich eine Klasse aus den Ordner classes lade, wie es im Skript auch passiert, wird in diesem Moment auch in das Verzeichnis classes gewechselt, oder bin ich weiterhin im Hauptverzeichnis?
Zuletzt geändert von HrSumsemann am Freitag 20. Februar 2015, 20:54, insgesamt 1-mal geändert.
BlackJack

@HrSumsemann: Falls die Frage ist ob ``import`` das aktuelle Arbeitsverzeichnis ändert: Natürlich nicht. Das wäre dann ja genau so ein Fall das man sich überhaupt nicht mehr drauf verlassen kann was das aktuelle Arbeitsverzeichnis ist wenn das jeder ``import`` und damit ja auch jeder Funktionsaufruf nach belieben verändern würde.
HrSumsemann
User
Beiträge: 28
Registriert: Donnerstag 19. Februar 2015, 17:32

Sorry hätte ich dazu schreiben sollen, das meinte ich: classes.fldplot.folderscan()
BlackJack

@HrSumsemann: Das klärt eigentlich nichts auf sondern verwirrt noch mehr. Du schreibst etwas von einer Klasse importieren, sagst jetzt aber Du meinst `classes.fldplot.folderscan()` wo weit und breit keine Klasse zu sehen ist. Was übrigens den Packagenamen `classes` um so fragwürdiger erscheinen lässt. Und meinst Du jetzt das importieren dieser Funktion (oder des Moduls in dem die steckt) oder den *Aufruf* der Funktion? Der enthält ja einen `os.chdir()`-Aufruf, also ändert der Aufruf wahrscheinlich schon das aktuelle Arbeitsverzeichnis des Prozesses. Und wie gesagt, das sollte man nicht machen weil das fehleranfällig ist und nicht skaliert und die Fehlersuche ”lustig” wird wenn andere Teile des Programms von einem anderen Arbeitsverzeichnis ausgehen als das welches nach dem Funktionsaufruf aktuell ist.
HrSumsemann
User
Beiträge: 28
Registriert: Donnerstag 19. Februar 2015, 17:32

Ich meinte den Aufruf von folderscan () aus fldplot. Unabhängig vom Inhalt dieser Funktion. Sprich wird automatisch durch classes.fldplot.folderscan() in den Ordner classes gewechselt?

Werde die Namen nochmal grundlegend überarbeiten. ;)
BlackJack

@HrSumsemann: Nein natürlich nicht. Wie gesagt, dann könnte man sich doch überhaupt nicht mehr auf das aktuelle Arbeitsverzeichnis verlassen wenn jede beliebige Funktion das alleine durch Import oder Aufruf ändern würde. Funktionen können selbst ja wieder andere Funktionen aufrufen oder importieren und man weiss von aussen bei den meisten ja nicht was die intern so anstellen solange man sie nicht selbst geschrieben hat oder im Quelltext von Bibliotheken herumgestöbert hat.
Antworten