Я предполагаю, что вы хотите, чтобы sub-dir был доступен как атрибут, вы можете достичь этого двумя способами
- Просмотр списка файлов и динамическое создание переменных
- Подключиться к атрибуту доступа и правильно вернуть списки при необходимости
Я предпочитаю второй подход, так как он ленив, лучше и проще в реализации
import os
class DirLister(object):
def __init__(self, root):
self.root = root
self._list = None
def __getattr__(self, name):
try:
var = super(DirLister).__getattr__(self, name)
return var
except AttributeError:
return DirLister(os.path.join(self.root, name))
def __str__(self):
self._load()
return str(self._list)
def _load(self):
"""
load once when needed
"""
if self._list is not None:
return
self._list = os.listdir(self.root) # list root someway
root = DirLister("/")
print root.etc.apache2
выход:
['mods-enabled', 'sites-80', 'mods-available', 'ports.conf', 'envvars', 'httpd.conf', 'sites-available', 'conf.d', 'magic', 'apache2.conf', 'sites-enabled']
Вы можете улучшить это, чтобы улучшить проверку ошибок и т. Д.
Объяснение кода: это в основном рекурсивный список каталогов, поэтому объекты DirLister
перечисляют файлы под данным корнем, и если к какой-либо переменной обращаются с точечной нотацией, она возвращает DirLister, предполагая, что этот атрибут это папка под рутом. Так что если мы попытаемся создать DirLister
класс шаг за шагом, это будет более понятным
1- Простой DirLister
, который просто перечисляет файлы / папки под ним
class DirLister(object):
def __init__(self, root):
self.root = root
self._list = os.listdir(self.root)
2 - Наш простой список просто перечисляет файлы на один уровень глубиной, если мы хотим получить файлы в подпапках, мы можем подключиться к __getattr__
, который вызывается с помощью varname, когда используется obj.varname
. Поэтому, если у нашего dir-lister нет атрибута с именем varname, мы предполагаем, что пользователь пытается получить доступ к этому каталогу под данным корнем, поэтому мы создаем еще один DirLister с корнем root+subdirname
def __getattr__(self, name):
try:
var = super(DirLister).__getattr__(self, name)
return var
except AttributeError:
return DirLister(os.path.join(self.root, name))
Примечание: сначала мы проверяем базовый класс на предмет этого атрибута, потому что мы не хотим рассматривать доступ ко всем переменным как доступ к подчиненному каталогу, если такого атрибута, следовательно, нет AttributeError
, то мы создаем новый DirLister для подпапки .
3- Чтобы улучшить код, чтобы мы не отображали все папки, даже если пользователь их не запрашивал, мы перечисляем только, когда пользователь требует, следовательно, load
метод
def _load(self):
if self._list is not None:
return
self._list = os.listdir(self.root) # list root someway
поэтому этот метод выводит список dir, если его еще нет в списке, и его следует вызывать, когда он, наконец, нам нужен, например, при печати списка
Редактировать: как спрашивает OP, здесь есть альтернативный метод рекурсивного перечисления всего дерева, хотя я настоятельно рекомендую против него
import os
class RecursiveDirLister(object):
def __init__(self, root):
self._sublist = []
for folder in os.listdir(root):
self._sublist.append(folder)
path = os.path.join(root, folder)
if not os.path.isdir(path):
continue
# add it as attribute, assuming that dir-name is valid python varname
try:
sublister = RecursiveDirLister(path)
except OSError:
continue#ignore permission errors etc
setattr(self, folder, sublister)
def __str__(self):
return str(self._sublist)
etc = RecursiveDirLister("/etc")
print etc.fonts
выход:
['conf.avail', 'conf.d', 'fonts.conf', 'fonts.dtd']