【问题标题】:How can I create nested folders with attributes in python?如何在 python 中创建具有属性的嵌套文件夹?
【发布时间】:2021-01-06 04:37:21
【问题描述】:

我是一名初级程序员,刚开始学习嵌套列表和字典。我的任务是创建一个文件系统,包含目录类及其属性。

class Directory:
    def __init__(self, name: str, parent: Optional['Directory'], children: List[Optional['Directory']]):
        self.name = name
        self.parent = parent
        self.children = children

我应该构建一个函数来递归地创建这个文件系统,给定根目录及其字典中的目录。 Parent 是一个目录,其中包含当前目录作为他的孩子之一。任何没有子目录的目录都应该是一个空目录。

    "root": ["dirA", "dirB"],          
    "dirA": ["dirC"],
    "dirC": ["dirH", "dirG"],
    "dirB": ["dirE"]
    "dirG": ["dirX", "dirY"]}

我一直在尝试这样做,我想我知道如何递归地创建目录,但是我不知道在没有任何额外导入的情况下将什么放在 dir.parent 位置。使用root,没有问题,因为它是 None 但在进一步的过程中,我不知道如何将孩子的父母(应该是目录)作为他的属性之一,因为我将从那里递归。你知道怎么做吗?这是我到目前为止的代码:

def create_system(system: Dict[str, List[str]], parent_children: List[str]) -> Optional[List[Optional['Directory']]]:
    children: List[Optional['Directory']] = []
    for child in parent_children:
        if child in system.keys():
            children.append(Directory(child, parent, create_system(system, list(system.get(child)))))
        else:
            children.append(Directory(child, parent, []))
    return children

def root(system: Dict[str, List[str]]) -> Optional['Directory']:
    return Directory("root", None, create_system(system, list(system.get("root"))))

感谢您的回复!

【问题讨论】:

  • Python 对空格非常敏感。请修正你的缩进。
  • 我假设您使用os.mkdir 来实际创建目录?你也可以os.mkdirs吗?
  • @谢谢。这看起来像一个抽象的数据操作。 “目录”在此上下文中并不表示实际的文件系统目录。
  • 也许我误解了这个问题。 @MadPhysicist 你可能是对的,但我会留下我的答案,以防它对其他人有用。

标签: python recursion nested


【解决方案1】:

你的目标是转换字典

system = {
    "root": ["dirA", "dirB"],          
    "dirA": ["dirC"],
    "dirC": ["dirH", "dirG"],
    "dirB": ["dirE"]
    "dirG": ["dirX", "dirY"]
}

进入以下树:

            root
           /    \
        dirA    dirB
        /         \
      dirC        dirE
     /   \
   dirH  dirG
         /   \
       dirX  dirY

希望,很明显,进程的返回值可以只是根。为确保仅在创建父文件夹后才访问每个文件夹,您可以使用基于堆栈的 BFS 方法或递归 DFS 方法。

让我们看一个简单的 BFS 方法:

def create_system_bfs(system):
    root = Directory('root', None, [])
    stack = [root]  # in practice, use collections.deque([root])

    while stack:
        current = stack.pop(0)
        for child in system.get(current.name, []):
            d = Directory(child, current, [])
            current.children.append(d)
            stack.append(d)

    return root

DFS 版本可能类似于:

def create_system_dfs(system):
    def create_node(name, parent):
        d = Directory(name, parent, [])
        d.children = [create_node(child, d) for child in system.get(name, [])]
        return d
    return create_node('root', None)

请记住,还有其他可能的方法。在这两种情况下,create_root 方法是完全没有必要的。 BFS 方法仅受可用堆内存的限制。 DFS 方法也可能受到堆栈大小的限制。

【讨论】:

    【解决方案2】:

    在纠结于类之前,我们可以从一个普通函数的角度来思考 -

    def paths(t, init="root"):
      def loop(q, path):
        if isinstance(q, dict):
          for (dir, v) in q.items():
            yield from loop(v, [*path, dir])
        elif isinstance(q, list):
          for dir in q:
            yield from loop \
              ( t[dir] if dir in t else None
              , [*path, dir]
              )
        else:
          yield "/".join(path)
      yield from loop(t[init], ["."])
    

    使用paths 很简单,只需在您的input 树上调用它-

    input = {
      "root": ["dirA", "dirB"],          
      "dirA": ["dirC"],
      "dirC": ["dirH", "dirG"],
      "dirB": ["dirE"],
      "dirG": ["dirX", "dirY"]
    }
    
    for path in paths(input):
      print(path)
    
    ./dirA/dirC/dirH
    ./dirA/dirC/dirG/dirX
    ./dirA/dirC/dirG/dirY
    ./dirB/dirE
    

    使用paths 可以让我们轻松创建我们需要的目录-

    import os
    
    for path in paths(input):
      os.makedirs(path)
    

    【讨论】:

      【解决方案3】:

      这是一个了解可重用模块和相互递归的机会。此答案中的此解决方案解决了您的特定问题,而无需对another answer 中编写的模块进行任何修改。这种方法的明显优势是tree 对节点形状的了解为零,并允许您定义任何输出形状。

      下面我们使用带有nameparentchildren 属性的普通dict 创建一个树。 tree 不会为您做出这个选择。如果需要,可以使用不同的结构或自定义类 -

      from tree import tree
      
      input = {
        None: ["dirA", "dirB"],          
        "dirA": ["dirC"],
        "dirC": ["dirH", "dirG"],
        "dirB": ["dirE"],
        "dirG": ["dirX", "dirY"]
      }
      
      result = tree \
        ( flatten(input)
        , parent
        , lambda node, children:
            dict \
              ( name=name(node)
              , parent=parent(node)
              , children=children(name(node))
              )
        )
      
      print(result)
      
      [
        {
          "name": "dirA",
          "parent": None,
          "children": [
            {
              "name": "dirC",
              "parent": "dirA",
              "children": [
                {
                  "name": "dirH",
                  "parent": "dirC",
                  "children": []
                },
                {
                  "name": "dirG",
                  "parent": "dirC",
                  "children": [
                    {
                      "name": "dirX",
                      "parent": "dirG",
                      "children": []
                    },
                    {
                      "name": "dirY",
                      "parent": "dirG",
                      "children": []
                    }
                  ]
                }
              ]
            }
          ]
        },
        {
          "name": "dirB",
          "parent": None,
          "children": [
            {
              "name": "dirE",
              "parent": "dirB",
              "children": []
            }
          ]
        }
      ]
      

      为了使用tree,我们定义了一个flatten输入节点的方法-

      def flatten(t):
        seq = chain.from_iterable \
          ( map(lambda _: (_, k), v)
              for (k,v) in input.items()
          )
        return list(seq)
      
      print(flatten(input))
      
      [ ('dirA', None)
      , ('dirB', None)
      , ('dirC', 'dirA')
      , ('dirH', 'dirC')
      , ('dirG', 'dirC')
      , ('dirE', 'dirB')
      , ('dirX', 'dirG')
      , ('dirY', 'dirG')
      ]
      

      而且我们还定义了主键和外键。这里我们使用nameparent,但是你可以选择任何你喜欢的名字-

      def name(t):
        return t[0]
      
      def parent(t):
        return t[1]
      

      要详细了解tree 模块及其部分优势,请参阅original Q&A

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-24
        • 2022-01-21
        • 1970-01-01
        • 2018-03-15
        • 2018-11-14
        • 2017-11-29
        相关资源
        最近更新 更多