我知道以前有人问过这个问题,我已经看到了答案,但仍然无法弄清楚到底发生了什么。
我试图根据特定的文件元数据(日期和位置)和一组条件,有条件地构建文件夹结构。例如,为了进行测试,我使用了以下方法:
COND = ["Y", "m", "C"]这意味着,在文件夹结构中,文件需要先按年份拆分文件,然后按日历月份拆分文件,然后再按原籍国拆分文件。
这是我为测试而创建的示例数据:
data = [
["111", dt.datetime(2019, 1, 1), "Aus", "Bri"],
["112", dt.datetime(2019, 1, 5), "Aus", "Bri"],
["113", dt.datetime(2019, 2, 10), "Aus", "Mel"],
["114", dt.datetime(2020, 1, 1), "Aus", "Per"],
["115", dt.datetime(2020, 1, 10), "Aus", "Per"],
["116", dt.datetime(2020, 1, 25), "Aus", "Per"],
["117", dt.datetime(2020, 10, 5), "My", "KL"],
["118", dt.datetime(2020, 11, 6), "Ru", "Led"],
["119", dt.datetime(2020, 12, 1), "Ru", "Mos"],
["120", dt.datetime(2021, 3, 5), "Aus", "Syd"],
["121", dt.datetime(2021, 5, 1), "Aus", "Mel"],
["122", dt.datetime(2021, 6, 1), "Aus", "Per"],
["123", dt.datetime(2021, 11, 1), "Chi", "Bei"],
["124", dt.datetime(2021, 11, 15), "Jp", "Tok"],
["125", dt.datetime(2022, 1, 1), "Aus", "Per"],
["126", dt.datetime(2022, 3, 1), "Aus", "Bri"],
["127", dt.datetime(2022, 3, 5), "Aus", "Per"],
["128", dt.datetime(2022, 3, 11), "My", "KL"],
["129", dt.datetime(2022, 5, 1), "Aus", "Syd"],
["130", dt.datetime(2022, 8, 8), "Aus", "Bri"],
]这些简单的函数执行过滤:
def filter_year(data: list[list[str | dt.datetime]]) -> list[int]:
return {i[1].year for i in data}
def filter_month(data: list[list[str | dt.datetime]]) -> list[int]:
return {i[1].month for i in data}
def filter_day(data: list[list[str | dt.datetime]]) -> list[int]:
return {i[1].day for i in data}
def filter_country(data: list[list[str | dt.datetime]]) -> list[str]:
return {i[2] for i in data}
def filter_city(data: list[list[str | dt.datetime]]) -> list[str]:
return {i[3] for i in data}
condition_dict = {
"Y": {'fun': filter_year, 'id': 1 },
"m": {'fun': filter_month,'id': 1 },
"d": {'fun': filter_day,'id': 1},
"C": {'fun': filter_country, 'id': 2},
"c": {'fun': filter_city, 'id': 3 }我试图使用任意顺序树自动构建结构。节点上的数据分割工作正常:
from typing import Any
from pathlib import Path
from dataclasses import dataclass, field
@dataclass
class Node:
folder: Path
metadata: list[list[Any]] = field(default_factory=list)
conditions: list[str] = field(default_factory=list)
@property
def children(self) -> list['Node']:
if len(self.conditions) == 0:
return []
current_condition = self.conditions[0]
fun = condition_dict[current_condition]['fun']
fnames: list[int | str] = fun(self.metadata)
children_data = {str(n): {} for n in fnames}
for f in fnames:
children_data[str(f)]['folder'] = self.folder / str(f)
children_data[str(f)]['conditions'] = self.conditions[1:]
if current_condition == 'Y':
children_data[str(f)]['metadata'] = [i for i in self.metadata if i[1].year == f]
elif current_condition == 'm':
children_data[str(f)]['metadata'] = [i for i in self.metadata if i[1].month == f]
elif current_condition == 'd':
children_data[str(f)]['metadata'] = [i for i in self.metadata if i[1].day == f]
elif current_condition == 'C':
children_data[str(f)]['metadata'] = [i for i in self.metadata if i[2] == f]
elif current_condition == 'c':
children_data[str(f)]['metadata'] = [i for i in self.metadata if i[3] == f]
return [Node(**i) for i in children_data.values()]现在,我正在尝试遍历我在这里使用了一个修改版本的树(Traverse Non-Binary Tree)
@dataclass
class Tree:
def traverse(self, root: Node):
r = root.children
if not r or len(root.conditions) == 0:
print('The end of subtree:', root.folder)
else:
for child in r:
print('\n'.join(str(i.folder) for i in r))
if isinstance(child, Node):
for x in self.traverse(child):
print(str(x.folder))
else:
print(child) 但是,当我在几个正确的输出之后尝试处理我的数据时,我总是会遇到错误NoneType is not iterable
n = Node(folder=Path('/home'), metadata=data, conditions=COND)
tree = Tree()
tree.traverse(n)输出:
/home/2019
/home/2020
/home/2021
/home/2022
/home/2019/1
/home/2019/2
/home/2019/1/Aus
The end of subtree: /home/2019/1/Aus
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/home/pavel/python/photo_manager/temp/tree_test.ipynb Cell 4 in <cell line: 4>()
1 n = Node(folder=Path('/home'), metadata=data, conditions=COND)
3 tree = Tree()
----> 4 tree.traverse(n)
/home/pavel/python/photo_manager/temp/tree_test.ipynb Cell 4 in Tree.traverse(self, root)
45 print('\n'.join(str(i.folder) for i in r))
46 if isinstance(child, Node):
---> 47 for x in self.traverse(child):
48 print(str(x.folder))
49 else:
/home/pavel/python/photo_manager/temp/tree_test.ipynb Cell 4 in Tree.traverse(self, root)
45 print('\n'.join(str(i.folder) for i in r))
46 if isinstance(child, Node):
---> 47 for x in self.traverse(child):
48 print(str(x.folder))
49 else:
/home/pavel/python/photo_manager/temp/tree_test.ipynb Cell 4 in Tree.traverse(self, root)
45 print('\n'.join(str(i.folder) for i in r))
46 if isinstance(child, Node):
---> 47 for x in self.traverse(child):
48 print(str(x.folder))
49 else:
TypeError: 'NoneType' object is not iterable我不明白为什么会发生这样的事情,因为我相信我是在防范NoneType。由于某种原因,我只会到达一个子树的末尾,而不是遍历其他子树。我在这里做错什么了?
发布于 2022-07-20 11:37:54
我并没有真正了解整个故事,但你在这条线上可能会犯这样的错误:
for x in self.traverse(child):问题是self.traverse没有return语句,因此这个递归调用返回None,而for x in None没有任何意义。
我认为您实际上不想从递归调用中获得一些x值,因为递归调用处理自己的事务。不需要再次打印该递归调用已经打印的内容。
这里还有第二个问题:
for child in r:
print('\n'.join(str(i.folder) for i in r))在这里,对于r中的每个子节点,您可以在print调用中再次迭代r 。只会打印副本。您只需从r中打印当前子程序即可。这将使下面的else块过时:当您刚刚打印child.folder时,似乎没有必要再次打印child。
因此,纠正这两个问题,以下操作至少不会出错:
@dataclass
class Tree:
def traverse(self, root: Node):
r = root.children
if not r or len(root.conditions) == 0:
print('The end of subtree:', root.folder)
else:
for child in r:
print(str(child.folder))
if isinstance(child, Node):
self.traverse(child)https://stackoverflow.com/questions/73047407
复制相似问题