【问题标题】:How to represent file structure as python objects如何将文件结构表示为python对象
【发布时间】:2019-06-11 03:21:31
【问题描述】:

我正在尝试找到一种将文件结构表示为 python 对象的方法,这样我就可以轻松获得特定路径,而无需输入所有字符串。这适用于我的情况,因为我有一个静态文件结构(未更改)。

我认为我可以将目录表示为类,将目录中的文件表示为类/静态变量。

我希望能够浏览 python 对象,以便它返回我想要的路径,即:

print(FileStructure.details.file1) # root\details\file1.txt
print(FileStructure.details) # root\details

我从下面的代码中得到的是:

print("{0}".format(FileStructure())) # root
print("{0}".format(FileStructure)) # <class '__main__.FileStructure'>
print("{0}".format(FileStructure.details)) # <class '__main__.FileStructure.details'>
print("{0}".format(FileStructure.details.file1)) # details\file1.txt

我目前的代码是……

import os 

class FileStructure(object): # Root directory
    root = "root"

    class details(object): # details directory
        root = "details"
        file1 = os.path.join(root, "file1.txt") # File in details directory
        file2 = os.path.join(root, "file2.txt") # File in details directory

        def __str__(self):
            return f"{self.root}"

    def __str__(self):
        return f"{self.root}"

我不想实例化这个类来完成这项工作。我的问题是:

  1. 如何调用类对象并让它返回一个字符串 文本的
  2. 如何让嵌套类使用它们的父类?

【问题讨论】:

  • 为什么不实例化这个类呢?如果类是静默实例化的,所以你永远看不到实例,是否可以接受?
  • @ShadowRanger 我不希望用户每次都像usethisclass = TheClass() 那样明确地实例化它。静默实例化它是什么意思?
  • 旁注:There is no way for the nested class to use its parent class implicitly,所以你的设计已经不能真正发挥作用了。
  • 如果你把@object.__new__放在class FileStructure...之前的那一行,它会默默地创建一个FileStructure的实例并将它分配给名称FileStructure(所以类本身将不再具有全局名称,只有具有该名称的实例才会存在)。
  • @ShadowRanger 所以看来我的方法有误。至少我从对象装饰器中学到了一些新东西。谢谢!

标签: python python-3.x object


【解决方案1】:

让我们开始吧:你可能实际上并不想要这个。 Python3 的pathlib API 似乎比这更好,并且已经得到广泛支持。

root = pathlib.Path('root')
file1 = root / 'details' / 'file1'  # a Path object at that address

if file1.is_file():
    file1.unlink()
else:
    try:
        file1.rmdir()
    except OSError as e:
        # directory isn't empty

但是,如果您出于某种原因对此死心塌地,则需要覆盖 __getattr__ 以创建新的 FileStructure 对象并跟踪父母和孩子。

class FileStructure(object):
    def __init__(self, name, parent):
        self.__name = name
        self.__children = []
        self.__parent = parent

    @property
    def parent(self):
        return self.__parent

    @property
    def children(self):
        return self.__children

    @property
    def name(self):
        return self.__name

    def __getattr__(self, attr):
        # retrieve the existing child if it exists
        fs = next((fs for fs in self.__children if fs.name == attr), None)
        if fs is not None:
            return fs

        # otherwise create a new one, append it to children, and return it.
        new_name = attr
        new_parent = self
        fs = self.__class__(new_name, new_parent)
        self.__children.append(fs)
        return fs

然后使用它:

root = FileStructure("root", None)
file1 = root.details.file1

您可以添加__str____repr__ 来帮助您进行陈述。您甚至可以包含 path 属性

# inside FileStructure
@property
def path(self):
    names = [self.name]
    cur = self
    while cur.parent is not None:
        cur = cur.parent
        names.append(cur.name)
    return '/' + '/'.join(names[::-1])

def __str__(self):
    return self.path

【讨论】:

  • fun lil tidbit: __getattr__ 只有在没有以通常方式找到请求的属性时才会调用,所以if attr in ['parent', ...] 不是必需的。参考:stackoverflow.com/questions/3278077/…
  • @DeeBee 哦,有趣!谢谢你——我曾计划测试它,但在我不得不提交答案或重新开始工作之前已经没有时间了。我很惊喜地发现,我的代码后来放到解释器中时竟然还能运行 :)
【解决方案2】:

预先说明:这是一个糟糕的解决方案,但它只需极少的更改即可满足您的要求。基本上,您需要 __str__ 的实例才能工作,因此这会欺骗使用装饰器语法将您的类声明更改为已声明类的单例实例化。因为它是impossible to reference outer classes from nested classes implicitly,所以引用是显式执行的。为了重用__str__file1file2 被制成@propertys,这样他们就可以使用details 实例的str 形式来构建自己。

@object.__new__
class FileStructure(object): # Root directory
    root = "root"

    @object.__new__
    class details(object): # details directory
        root = "details"
        @property
        def file1(self):
            return os.path.join(str(self), 'file1')
        @property
        def file2(self):
            return os.path.join(str(self), 'file2')

        def __str__(self):
            return f"{os.path.join(FileStructure.root, self.root)}"

    def __str__(self):
        return f"{self.root}"

再次重申:虽然这确实会产生您想要的行为,但这仍然是一个糟糕的解决方案。我强烈怀疑你在这里有an XY problem,但这回答了问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-29
    • 1970-01-01
    • 2020-06-16
    • 2014-06-29
    • 1970-01-01
    相关资源
    最近更新 更多