在Python中使用os.walk分配实例
我正在尝试创建一个可以遍历文件夹的程序。这里有一些输入和输出,我已经部分完成了。我正在使用一个测试文件夹,但我希望这个程序能够在任何文件夹上工作,这导致了一些问题。
[IN]: print testdir #name of the directory
[OUT]: ['j','k','l'] #directories under testdir
[IN]: print testdir.j
[OUT]: ['m','n'] # Files under testdir.j
这是到目前为止的代码:
class directory_lister:
"""Lists directories under root"""
def __init__(self,path):
self.path = path
self.ex = []
for item in os.listdir(path):
self.ex.append(item)
def __repr__(self):
return repr(self.ex)
这个代码可以返回文件夹和文件,但我必须手动指定文件夹的名称。
testdir = directory_lister(path/to/testdir)
j = directory_lister(path/to/j)
etc
有没有办法让这个过程自动化,比如:
for root,dirs,files in os.walk(/path/to/testdir/):
for x in dirs:
x = directory_lister(root) #I want j = directory_lister(path/to/j), k = directory_lister(path/to/k) and l = directory_lister(path/to/l) here.
可以有一个:
class directory_lister:
def __init__(self,path):
self.path = path
self.j = directory_lister(path + os.sep + j) # how to automate this attribute of the class when assigned to an instance??
上面的代码有问题,因为对象x只是一个实例,而j、k、l必须手动定义。我需要使用另一个类,还是用字典配合getattr,但我总是遇到同样的问题。如果需要额外的信息,请问我,我希望我说得够清楚。
更新 2
有没有办法在下面的DirLister中添加其他复杂的功能?比如当它到达一个文件,比如testdir/j/p时,打印出文件p的第一行。
[IN] print testdir.j.p
[OUT] First Line of p
我已经创建了一个类来打印文件的第一行:
class File:
def __init__(self, path):
"""Read the first line in desired path"""
self.path = path
f = open(path, 'r')
self.first_line = f.readline()
f.close()
def __repr__(self):
"""Display the first line"""
return self.first_line
只需要知道如何把它整合到下面的类中。谢谢。
2 个回答
我不太明白你在问什么,不过这样做可以吗?
for root,dirs,files in os.walk(/path/to/testdir/):
listers = dict((dir, directory_lister(dir)) for dir in dirs)
#now you can use:
listers['j']
listers['k']
listers['l']
我猜你想让子目录像属性一样可以访问,这可以通过两种方式实现:
- 遍历文件列表,动态创建变量
- 在属性访问时进行处理,正确返回需要的列表
我更喜欢第二种方法,因为它比较懒惰,效果更好,也更容易实现。
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__
来处理,当使用obj.varname
时会调用这个方法。所以如果我们的目录列出器没有名为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
这个方法会列出目录,如果还没有被列出,并且应该在我们最终需要它时调用,比如在打印列表时。
编辑:根据提问者的要求,这里是递归列出整个树的替代方法,不过我强烈不推荐这样做。
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']