繁体   English   中英

如何在 python 中创建具有属性的嵌套文件夹?

[英]How can I create nested folders with attributes in python?

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

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

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

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

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

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"))))

感谢您的任何回复!

您的目标是转换字典

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 方法仅受可用堆 memory 的限制。 DFS 方法也可能受到堆栈大小的限制。

在上课之前,我们可以考虑一个普通的 function -

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)

输出

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

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

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模块及其一些好处的更多信息,请参阅原始问答

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM