我有包含此表的 SQLlite 数据库: 在此表中,我们可以看到描述特定任务的行。任务的嵌套是使用 root_task_id 单元实现的。例如: id:1 的任务是 id:19 的任务的根任务,id:19 的任务是 id:20 的任务的根任务。这意味着: 的任务id:20是id:19的任务的子任务,id:19的任务是id:1的任务的子任务。 当我从数据库获取这些数据到 Python 程序时,我想通过使用 Task 类的对象来创建此任务的层次结构:
class Task:
def __init__(self, task_id, root_task_id, task_name, task_text, task_is_executed, subtasks = []):
self.id = task_id
self.root_task_id = root_task_id
self.name = task_name
self.text = task_text
if task_is_executed == 0:
self.is_executed = "No executed"
else:
self.is_executed = "EXECUTED"
self.subtasks = subtasks
此任务的层次结构必须使用 Task 类对象的 subtasks 属性来实现。简而言之,我需要根据 SQL 表的 root_task_id 单元实现的层次结构将任务打包为子任务。
我写了这段代码,但是有一些错误,我无法检测到:
def wrap_up_task_recursive(task: Task, tasks: list[Task], depth = 0):
for root_task in tasks:
print(f"root_task with id: {root_task.id}, is root? for task with id: {task.id}, that has root task with id: {task.root_task_id}?")
print(depth)
if task.root_task_id == root_task.id:
print("Yes")
root_task.subtasks.append(task)
break
else:
if len(root_task.subtasks) != 0:
wrap_up_task_recursive(task=task, tasks=root_task.subtasks, depth=depth + 1)
def convertTasksToUserFrandlyFormat2(all_tasks: list[Task]) -> list[Task]:
root_tasks: list[Task] = []
root_tasks_indexes: list[int] = []
for index, task in enumerate(all_tasks):
if task.root_task_id == None:
root_tasks.append(task)
root_tasks_indexes.append(index)
root_tasks_indexes.sort(reverse=True)
print(f"Root tasks indexes: {root_tasks_indexes}")
for index in root_tasks_indexes:
all_tasks.pop(index)
print(f"**********root_tasks**********")
for rt in root_tasks:
print(f"id: {rt.id}")
print(f"root_id: {rt.root_task_id}")
print(f"sub: {len(rt.subtasks)}")
print(f"**********Subtasks**********")
for t in all_tasks:
print(f"id: {t.id}")
print(f"root_id: {t.root_task_id}")
print(f"sub: {len(rt.subtasks)}")
for task in all_tasks:
wrap_up_task_recursive(task=task, tasks=root_tasks)
return root_tasks
def indentation(depth: int) -> str:
resultStr = ""
for _ in range(depth):
resultStr += " "
return resultStr
def recursiveReading(task: Task, depth = 0):
print(f"{indentation(depth)} id = {task.id}")
print(task.subtasks)
print(len(task.subtasks))
def readTasksToUserFrandlyFormat(all_tasks: list[Task]):
for task in all_tasks:
recursiveReading(task)
task1 = Task(task_id=1, root_task_id=None, task_name="New task", task_text="This is new task", task_is_executed=0)
task2 = Task(task_id=14, root_task_id=None, task_name="New task", task_text="This is new task", task_is_executed=0)
task3 = Task(task_id=15, root_task_id=None, task_name="New task", task_text="This is new task", task_is_executed=0)
task4 = Task(task_id=16, root_task_id=None, task_name="New task", task_text="This is new task", task_is_executed=0)
task5 = Task(task_id=17, root_task_id=None, task_name="New task", task_text="This is new task", task_is_executed=0)
task6 = Task(task_id=18, root_task_id=None, task_name="New task", task_text="This is new task", task_is_executed=0)
task7 = Task(task_id=19, root_task_id=1, task_name="New task", task_text="This is new task", task_is_executed=0)
task8 = Task(task_id=20, root_task_id=19, task_name="New task", task_text="This is new task", task_is_executed=0)
all_tasks = [task1, task2, task3, task4, task5, task6, task7, task8]
h_all_tasks = convertTasksToUserFrandlyFormat2(all_tasks)
readTasksToUserFrandlyFormat(h_all_tasks)
控制台输出:
Root tasks indexes: [5, 4, 3, 2, 1, 0]
**********root_tasks**********
id: 1
root_id: None
sub: 0
id: 14
root_id: None
sub: 0
id: 15
root_id: None
sub: 0
id: 16
root_id: None
sub: 0
id: 17
root_id: None
sub: 0
id: 18
root_id: None
sub: 0
**********Subtasks**********
id: 19
root_id: 1
sub: 0
id: 20
root_id: 19
sub: 0
root_task with id: 1, is root? for task with id: 19, that has root task with id: 1?
0
Yes
root_task with id: 1, is root? for task with id: 20, that has root task with id: 19?
0
root_task with id: 19, is root? for task with id: 20, that has root task with id: 19?
1
Yes
root_task with id: 14, is root? for task with id: 20, that has root task with id: 19?
0
root_task with id: 19, is root? for task with id: 20, that has root task with id: 19?
1
Yes
root_task with id: 15, is root? for task with id: 20, that has root task with id: 19?
0
root_task with id: 19, is root? for task with id: 20, that has root task with id: 19?
1
Yes
root_task with id: 16, is root? for task with id: 20, that has root task with id: 19?
0
root_task with id: 19, is root? for task with id: 20, that has root task with id: 19?
1
Yes
root_task with id: 17, is root? for task with id: 20, that has root task with id: 19?
0
root_task with id: 19, is root? for task with id: 20, that has root task with id: 19?
1
Yes
root_task with id: 18, is root? for task with id: 20, that has root task with id: 19?
0
root_task with id: 19, is root? for task with id: 20, that has root task with id: 19?
1
Yes
id = 1
[<myTaskManager.Task object at 0x000001BCA396E750>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>]
7
id = 14
[<myTaskManager.Task object at 0x000001BCA396E750>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>]
7
id = 15
[<myTaskManager.Task object at 0x000001BCA396E750>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>]
7
id = 16
[<myTaskManager.Task object at 0x000001BCA396E750>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>]
7
id = 17
[<myTaskManager.Task object at 0x000001BCA396E750>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>]
7
id = 18
[<myTaskManager.Task object at 0x000001BCA396E750>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>, <myTaskManager.Task object at 0x000001BCA396E780>]
7
令人惊讶的是,我的所有代码都工作正常,除了以下行:
def __init__(self, task_id, root_task_id, task_name, task_text, task_is_executed, subtasks = []):
在这行代码中,我有一个带有默认参数的构造函数:subtasks = [],这导致了Task类的所有对象都具有相同的子任务列表(引用相同的内存单元)的问题。当您使用“可变”对象作为默认值时,是什么导致了混乱;原因很简单:构造函数在每次调用中都使用相同的“默认参数”对象。任何想要更详细地了解它的人,我强烈建议阅读这篇post,@Michael Butscher 在评论中建议了我。 我需要做什么才能让我的代码按预期工作?为此,您只需更改两行代码:将构造函数中的 subtasks = [] 默认参数替换为
subtasks = None,然后将 self.subtasks = subtasks 替换为 self.subtasks = [] init函数。事情应该是这样的:
class Task:
def __init__(self, task_id, root_task_id, task_name, task_text, task_is_executed, subtasks = None):
self.id = task_id
self.root_task_id = root_task_id
self.name = task_name
self.text = task_text
if task_is_executed == 0:
self.is_executed = "No executed"
else:
self.is_executed = "EXECUTED"
if subtasks == None:
self.subtasks = []
else:
self.subtasks = subtasks
我还根据 SQL 表的
单元实现的层次结构附加了包tasks
作为 subtasks 的完整代码:
class Task:
def __init__(self, task_id, root_task_id, task_name, task_text, task_is_executed, subtasks = None):
self.id = task_id
self.root_task_id = root_task_id
self.name = task_name
self.text = task_text
if task_is_executed == 0:
self.is_executed = "No executed"
else:
self.is_executed = "EXECUTED"
if subtasks == None:
self.subtasks = []
else:
self.subtasks = subtasks
def wrap_up_task_recursive(task: Task, tasks: list[Task], depth = 0):
for root_task in tasks:
print(f"root_task with id: {root_task.id}, is root? for task with id: {task.id}, that has root task with id: {task.root_task_id}?")
print(depth)
if task.root_task_id == root_task.id:
print("Yes")
root_task.subtasks.append(task)
break
else:
if len(root_task.subtasks) != 0:
wrap_up_task_recursive(task=task, tasks=root_task.subtasks, depth=depth + 1)
def convertTasksToUserFrandlyFormat2(all_tasks: list[Task]) -> list[Task]:
root_tasks: list[Task] = []
root_tasks_indexes: list[int] = []
for index, task in enumerate(all_tasks):
if task.root_task_id == None:
root_tasks.append(task)
root_tasks_indexes.append(index)
root_tasks_indexes.sort(reverse=True)
print(f"Root tasks indexes: {root_tasks_indexes}")
for index in root_tasks_indexes:
all_tasks.pop(index)
print(f"**********root_tasks**********")
for rt in root_tasks:
print(f"id: {rt.id}")
print(f"root_id: {rt.root_task_id}")
print(f"sub: {len(rt.subtasks)}")
print(f"**********Subtasks**********")
for t in all_tasks:
print(f"id: {t.id}")
print(f"root_id: {t.root_task_id}")
print(f"sub: {len(rt.subtasks)}")
for task in all_tasks:
wrap_up_task_recursive(task=task, tasks=root_tasks)
return root_tasks
def indentation(depth: int) -> str:
resultStr = ""
for _ in range(depth):
resultStr += "|__"
return resultStr
def recursiveReading(task: Task, depth = 0):
print(f"{indentation(depth)} id = {task.id}")
if len(task.subtasks) != 0:
for subtask in task.subtasks:
recursiveReading(subtask, depth + 1)
def readTasksToUserFrandlyFormat(all_tasks: list[Task]):
print("********Task hierarchy********")
for task in all_tasks:
recursiveReading(task)
task1 = Task(task_id=1, root_task_id=None, task_name="New Task", task_text="This is new task", task_is_executed=0)
task2 = Task(task_id=2, root_task_id=1, task_name="New Task", task_text="This is new task", task_is_executed=0)
task3 = Task(task_id=3, root_task_id=None, task_name="New Task", task_text="This is new task", task_is_executed=0)
task4 = Task(task_id=4, root_task_id=2, task_name="New Task", task_text="This is new task", task_is_executed=0)
task5 = Task(task_id=5, root_task_id=4, task_name="New Task", task_text="This is new task", task_is_executed=0)
listOfTasks = [task1, task2, task3, task4, task5]
listOfTasksWithHierarchy = convertTasksToUserFrandlyFormat2(listOfTasks) # Here list of packed tasks as subtasks according to hierarchy implemented by root_task_id cells of SQL table.
readTasksToUserFrandlyFormat(listOfTasksWithHierarchy)
控制台输出:
Root tasks indexes: [2, 0]
**********root_tasks**********
id: 1
root_id: None
sub: 0
id: 3
root_id: None
sub: 0
**********Subtasks**********
id: 2
root_id: 1
sub: 0
id: 4
root_id: 2
sub: 0
id: 5
root_id: 4
sub: 0
root_task with id: 1, is root? for task with id: 2, that has root task with id: 1?
0
Yes
root_task with id: 1, is root? for task with id: 4, that has root task with id: 2?
0
root_task with id: 2, is root? for task with id: 4, that has root task with id: 2?
1
Yes
root_task with id: 3, is root? for task with id: 4, that has root task with id: 2?
0
root_task with id: 1, is root? for task with id: 5, that has root task with id: 4?
0
root_task with id: 2, is root? for task with id: 5, that has root task with id: 4?
1
root_task with id: 4, is root? for task with id: 5, that has root task with id: 4?
2
Yes
root_task with id: 3, is root? for task with id: 5, that has root task with id: 4?
0
********Task hierarchy********
id = 1
|__ id = 2
|__|__ id = 4
|__|__|__ id = 5
id = 3