【问题标题】:Assigning instances in os.walk in python在 python 中的 os.walk 中分配实例
【发布时间】:2011-12-18 02:02:18
【问题描述】:

我正在尝试创建一个遍历目录的 walker。这是我部分工作的输入和输出。我正在使用一个测试目录,但我希望在任何会导致一些问题的目录上执行此操作。

[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

有没有办法在下面的 Anurag 的 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

只需要知道如何将它合并到下面的类中。谢谢。

【问题讨论】:

  • directory_lister 所需的界面和功能究竟是什么?
  • os.walk 已经列出了所有的目录和文件,那么directory_lister 的意义何在?
  • @KarlKnechtel,该功能是为了方便地列出根目录下的目录。所以你只需指定根目录,其余的就很容易查看了。
  • 这还不能回答这个问题。

标签: python instances


【解决方案1】:

我假设您希望子目录像属性一样可访问,您可以通过两种方式实现

  • 遍历文件列表并动态创建变量
  • 挂钩属性访问并根据需要正确返回列表器

我更喜欢第二种方法,因为它更懒,更好,更容易实现

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 调用。因此,如果我们的 dir-lister 没有名为 varname 的属性,我们假设用户正在尝试访问给定根目录下的该目录,因此我们创建另一个根目录为 root+subdirname 的 DirLister

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']

【讨论】:

  • 不错。但是,当目录名称中有句点时(正如我在测试时注意到的那样),使用目录名称作为属性的基本假设就会失败。
  • 谢谢!这做得很好,我是初学者,你介意通过代码告诉我以更好地理解它吗?
  • @GordonBroom 甚至没有点,文件名中允许但不是有效的 python 变量名的任何东西都会出错
  • 感谢您的解释非常有帮助。是否可以通过打印文件的第一行来使其更复杂。所以 testdir/j/n 会返回,打印 testdir.j.n, 'First line of n'?这需要使用第一种方式(非懒惰方式)吗?还有如何使类可迭代?
  • @Jimmy 是的,您应用类似的逻辑来执行您在属性访问中想做的任何事情,例如如果 var name 是一个数字,则使用它来读取文件并返回值
【解决方案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']

【讨论】:

  • 当我运行这个我得到: OSError: [Errno 2] No such file or directory: 'l'
  • 啊改成directory_lister(os.path.join(root, dir))而不是directory_lister(dir)
  • 当我运行它时,它会返回一个空白列表字典
猜你喜欢
  • 1970-01-01
  • 2011-06-17
  • 2013-04-22
  • 1970-01-01
  • 2011-10-30
  • 2010-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多