2011-07-10 8 views
20

Я чувствую, что назначение файлов и папок и выполнение части + = [item] немного хаки. Какие-либо предложения? Я использую Python 3.2Что такое способ Python для работы с деревом каталогов?

from os import * 
from os.path import * 

def dir_contents(path): 
    contents = listdir(path) 
    files = [] 
    folders = [] 
    for i, item in enumerate(contents): 
     if isfile(contents[i]): 
      files += [item] 
     elif isdir(contents[i]): 
      folders += [item] 
    return files, folders 
+18

Избегайте 'от x import *'. * Это * один совет для питонического стиля. –

ответ

32

Посмотрите на функцию os.walk, которая возвращает путь вместе с каталогами и файлами, которые он содержит. Это должно значительно сократить ваше решение.

+0

Ничего себе, это прекрасно, не верьте, что я его пропустил. Спасибо вам. – Mike

+1

, но 'os.walk' не ограничивается одним уровнем каталогов, как код OP. –

0

Попробуйте использовать метод append.

+0

+1: это также намного лучше, чем 'list + = [item]'. Аккумуляторы * не включены *, и знакомство с основными языковыми функциями не позволяет вам повторно изобретать батарею: http://docs.python.org/tutorial/stdlib.html#batteries-included – msw

3
def dir_contents(path): 
    files,folders = [],[] 
    for p in listdir(path): 
     if isfile(p): files.append(p) 
     else: folders.append(p) 
    return files, folders 
4

Действительно, используя

items += [item] 

плох по многим причинам ...

  1. Метод append был сделан точно для этого (добавление одного элемента к концу a)

  2. Вы создают временный список одного элемента, чтобы просто выбросить его. В то время как сырая скорость не должна быть вашей первой проблемой при использовании Python (иначе вы используете неправильный язык), все еще теряя скорость без всякой причины, не кажется правильным.

  3. Вы используете небольшую асимметрию языка Python ... для списка объектов, пишущих a += b не то же самое, как написание a = a + b, потому что прежний изменяет объект на месте, а второй вместо выделяет новый список, и это может имеют другую семантику, если объект a также доступен другим образом. В вашем конкретном коде это не похоже на случай, но это может стать проблемой позже, когда кому-то другому (или самому себе через несколько лет, то же самое) придется модифицировать код. Python даже имеет метод extend с менее тонким синтаксисом, который специально предназначен для обработки случая, в котором вы хотите изменить объект списка, добавив в конце элементы другого списка.

Также как и другие отметили, кажется, что ваш код пытается сделать то, что уже делает os.walk ...

2

Вместо встроенного os.walk и os.path.walk, я использую что-то производный от этого куска кода, который я нашел в другом месте предлагается:

http://code.google.com/p/mylibs/source/browse/lib/Python/MyPyLib/DirectoryStatWalker.py

Я не repaste его здесь, но он ходит каталоги рекурсивно и является достаточно эффективным и легким для чтения.

+0

+1 @mikebabcock thanks - это работает для меня из-под коробки в Python 2.x (хотя OP использует 3.x) мне понадобилось 2.x решение. – therobyouknow

+0

К сожалению, проект больше не доступен, 404. Может ли кто-то его отнести? – LarsH

+1

Я еще не проверял, еще ли он идентичен, но cf http://pymoex.googlecode.com/svn/trunk/os_path/directoryStatWalker.py @LarsH – mikebabcock

0

В то время как поиск по той же информации, я нашел этот вопрос.

Я размещаю здесь самый маленький, самый ясный код, который я нашел в http://www.pythoncentral.io/how-to-traverse-a-directory-tree-in-python-guide-to-os-walk/ (вместо того, чтобы просто публиковать URL-адрес, в случае ссылки гнить).

На странице есть полезная информация, а также указаны некоторые другие релевантные страницы.

# Import the os module, for the os.walk function 
import os 

# Set the directory you want to start from 
rootDir = '.' 
for dirName, subdirList, fileList in os.walk(rootDir): 
    print('Found directory: %s' % dirName) 
    for fname in fileList: 
     print('\t%s' % fname) 
0

Я не проверял это еще широко, но я считаю, это расширит os.walk генератора, присоединиться dirnames всего пути к файлам, и придавить результирующий список; Чтобы получить прямое список конкретных файлов в вашем пути поиска.

import itertools 
import os 

def find(input_path): 
    return itertools.chain(
     *list(
      list(os.path.join(dirname, fname) for fname in files) 
      for dirname, _, files in os.walk(input_path) 
     ) 
    ) 
1

Если вы хотите рекурсивно перебрать все файлы, включая все файлы в подпапки, я считаю, что это лучший способ.

import os 

def get_files(input): 
    for fd, subfds, fns in os.walk(input): 
     for fn in fns: 
      yield os.path.join(fd, fn) 

## now this will print all full paths 

for fn in get_files(fd): 
    print(fn) 
+1

Мне очень нравится этот подход, потому что он отделяет итерационный код файловой системы от код для обработки каждого файла! Тем не менее, строка «выход из» должна быть опущена - 'os.walk' уже входит в подкаталоги, поэтому, если вы это сделаете, вы увидите файлы подкаталогов 2^n раз. –

+0

Вы правы! К сожалению .. – Gijs

1

С Python 3.4 появился новый модуль pathlib. Таким образом, чтобы получить все файлы и файлы, вы можете:

from pathlib import Path 

dirs = [str(item) for item in Path(path).iterdir() if item.is_dir()] 
files = [str(item) for item in Path(path).iterdir() if item.is_file()]