Пустой список в конструкторе класса Python вызывает ошибку
Я создаю простое дерево, в котором каждый узел имеет любое количество дочерних элементов в Python, и я создал класс узла, чтобы помочь мне. Каждый узел содержит ссылку на свой родительский узел (int) и любые дочерние узлы (список).
Однако явное добавление пустого списка в аргумент конструктора узла дало мне странные результаты, и мне хотелось бы получить объяснение, почему это поведение изменяется, когда список явный или явно не помещен в аргументы конструктора:
Реализация №1:
class Node:
def __init__(self, value, parent, children=[]):
self.parent = parent
self.value = value
self.children = children
Реализация №2:
class Node:
def __init__(self, value, parent):
self.parent = parent
self.value = value
self.children = []
Чтобы заполнить массив узлов:
parents = [4,-1,4,1,1]
nodes = [None] * n
for i in range(n):
nodes[i] = Node(i, parents[i])
Чтобы сохранить родительский атрибут каждого узла:
tree = Tree()
for i, node in enumerate(nodes):
parent_id = node.parent
if parent_id == -1:
tree.root = nodes[i]
else:
nodes[parent_id].children.append(node.value)
print([(node.value, node.children) for node in nodes])
С Реализацией №1 я получаю:
[(0, [0, 2, 3, 4]), (1, [0, 2, 3, 4]), (2, [0, 2, 3, 4]), (3, [0, 2, 3, 4]), (4, [0, 2, 3, 4])]
но с Реализацией № 2 я (правильно) получаю:
[(0, []), (1, [3, 4]), (2, []), (3, []), (4, [0, 2])]
В чем разница? Я не понимаю, почему список полностью заполнен для каждого узла даже с
if
а также
else
заявления. Любая помощь приветствуется, в том числе если вы думаете, что есть лучшие способы сделать это.
1 ответ
Аргументы по умолчанию связываются один раз при определении функции, поэтому каждый объект
Node
получает тот же объект списка в вашей первой реализации.
Локальные переменные оцениваются при запуске функции, поэтому
self.children=[]
назначает новый список каждому объекту.
Лучшим подходом, если вы хотите разрешить необязательный аргумент, было бы
class Node:
def __init__(self, value, parent, children=None):
self.parent = parent
self.value = value
self.children = children or []
Это использует
None
как значение по умолчанию. В
or
оператор позволяет нам выбрать
children
если аргумент истинный, и пустой список, если он ложный.
Из документации.