17

我认为这应该可行,但它给了我一个错误。我有一个包含 class 对象的列表node。我有两个不同的列表

  1. 开放列表
  2. node_list.(它们在纵向上不一样,排序方式)

当我在 中找到特定节点时,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 项不要害怕)打印出:(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>]

谢谢

后续问

所以我想检查我要删除的节点是否存在于 node_list 中。当我在http://docs.python.org/tutorial/datastructures.html上查找一些简单的列表函数时

list.index(x)remove.index(x)如果元素不在列表中,两者都会出错。这导致我的程序停止运行。为了绕过这个,我可以在以下语句之前使用这个语句.remove()node in node_list我认为in检查一个元素是否是列表的一部分并返回一个布尔值。只是仔细检查谢谢,

4

3 回答 3

16

发生这种情况是因为您理解为识别Node类的两个实例的特征,而不是 python 理解它的方式。

问题就在这里。假设你问 python 5==5,python 会返回True。这是因为 python 知道ints。但是,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:回应帝斯曼的评论

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

这将起作用。但仔细观察后,很明显 a[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

第二种方法尝试从中删除xmy_list如果导致错误,则忽略该错误

于 2012-07-12T16:57:13.327 回答
4

作为对您的跟进的回应,yesin将检查列表中的成员资格,因此:

if removed in node_list: node_list.remove(removed)

不会给你错误。或者,您可以捕获错误:

try:
    node_list.remove(removed)
except ValueError:
    pass
于 2012-07-12T18:36:45.837 回答
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_listnode_list定义的位置,但我怀疑列表本身引用了相同的列表对象。如果是这种情况,弹出 fromopen_node_list也会弹出 from node_list,因此当您调用remove. 这是一个示例,其中node_listopen_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[:]
于 2012-07-12T17:15:46.400 回答