Удаление экземпляра объекта в списке python

Думаю, это должно работать, но это дает мне ошибку. У меня есть список, содержащий объекты класса node. У меня есть два разных списка.

  • open_list
  • node_list (они не одинаковы по длине, упорядочиваются)

Когда я нахожу конкретный node в open_list, мне нужно удалить его из node_list. Я знаю, что списки имеют адреса для объектов, хранящихся в них

поэтому, когда я пытаюсь сделать

removed = open_list.pop(min_index) 
node_list.remove(removed) 

он дает мне ошибку, говоря

node_list.remove(removed)
ValueError: list.remove(x): x not in list

но список просто содержит адреса, которые действуют как указатели вправо? он должен совпадать с теми же адресами. я распечатал адрес removed и весь node_list (только 10 элементов на данный момент не боятся) print out: (последний элемент в node_list соответствует адресу удаленной:

removed: <__main__.node instance at 0x0124A440>
node_list: [<__main__.node instance at 0x01246E90>, <__main__.node instance at 0x01246EE0>, <__main__.node instance at 0x0124A300>, <__main__.node instance at 0x0124A328>, <__main__.node instance at 0x0124A350>, <__main__.node instance at 0x0124A378>, <__main__.node instance at 0x0124A3A0>, <__main__.node instance at 0x0124A3C8>, <__main__.node instance at 0x0124A3F0>, <__main__.node instance at 0x0124A418>, <__main__.node instance at 0x0124A440>]

Спасибо

последующий Q

поэтому я хочу проверить, существует ли node, который я хочу удалить, в списке узлов. когда я просмотрел некоторые простые функции списка на http://docs.python.org/tutorial/datastructures.html

list.index(x) и remove.index(x) обе дают ошибку, если элемент отсутствует в списке. это заставило мою программу перестать работать. чтобы обойти это, могу ли я использовать этот оператор перед .remove(): node in node_list Я думаю, что in проверяет, является ли элемент частью списка и возвращает bool. просто двойная проверка спасибо,

Ответ 1

Это происходит потому, что то, что вы понимаете как идентификационные признаки двух экземпляров вашего класса Node, не так, как это понимает python.

Проблема здесь. Предположим, вы спросили python 5==5, python вернет True. Это связано с тем, что python знает о int s. Тем не менее, Node - это настраиваемый пользовательский класс, поэтому вам нужно указать python, когда два объекта Node совпадают. Поскольку у вас (возможно) нет, python по умолчанию сравнивает свои местоположения в памяти. Поскольку два отдельных экземпляра будут находиться в двух разных ячейках памяти, python вернет False. Если вы вообще знакомы с Java, это похоже на разницу между == и .equals(...)

Чтобы сделать это, перейдите в свой класс Node и определите метод __eq__(self, other), где other ожидается как другой экземпляр Node.

Например, если ваши узлы имеют атрибут с именем name, а два узла с одинаковым именем считаются одинаковыми, то ваш __eq__ может выглядеть так:

def __eq__(self, other):
    myName = self.name
    hisName = other.name
    if myName == hisName:
        return True
    else:
        return False

Конечно, более элегантный способ написания этой же функции:

def __eq__(self, other):
    return self.name == other.name

Когда это будет сделано, ваша ошибка должна исчезнуть

РЕДАКТИРОВАТЬ 1: в ответ на DSM комментарий

class Node: pass
a = [Node(), Node()]
b = a[:]
b.remove(a.pop(0))

Это сработает. Но при ближайшем рассмотрении становится очевидным, что [0] и b [0] фактически являются одним и тем же объектом. Это можно проверить, вызвав id(a[0]) и сравнив его с id(b[[0]), чтобы подтвердить, что они действительно одинаковы

РЕДАКТИРОВАТЬ 2: В ответ на вопрос о продолжении OP (добавлен в исходный вопрос как редактирование)

Да, объект, не существующий в списке, вызовет ошибку, которая обычно останавливает поток программы. Это можно решить одним из двух способов:

if x in my_list:
    my_list.remove(x)

ИЛИ

try:
    my_list.remove(x)
except:
    pass

Второй метод пытается удалить x из my_list, и если это приводит к ошибке, игнорирует ошибку

Ответ 2

Если я правильно прочитал вопрос, стандартное значение python для сравнения мест памяти - это поведение, которое он ищет, но не получает. Здесь рабочий пример, в котором определяется пользовательский класс Node, показывает, что нет необходимости в __eq__(self, other).

class Node(object):
    pass

open_node_list = []
node_list = []

for i in range(10):
    a_node = Node()
    open_node_list.append(a_node)
    node_list.append(a_node)

removed = open_node_list.pop()
node_list.remove(removed)

Я не могу быть уверен, потому что вы не указали, где были определены ваши open_node_list и node_list, но я подозреваю, что сами списки ссылаются на один и тот же объект списка. В этом случае выскакивание из open_node_list также появляется из node_list, поэтому node больше не будет существовать при вызове remove. Вот пример, в котором node_list и open_node_list действительно являются одним и тем же списком, и поэтому изменения одного влияют на другое:

class Node(object):
  pass

open_node_list = []
node_list = open_node_list # <-- This is a reference, not a copy.

open_node_list.append(Node())
print(node_list)

Один из способов копирования списка:

node_list = open_node_list[:]

Ответ 3

В ответ на ваш запрос yes in проверит наличие членства в списке, поэтому:

if removed in node_list: node_list.remove(removed)

не даст вам ошибку. В качестве альтернативы вы можете уловить ошибку:

try:
    node_list.remove(removed)
except ValueError:
    pass