问题 删除python列表中的对象实例


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

  1. open_list
  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件物品不用担心) 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>]

谢谢

   后续问题  

 

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

list.index(x) 和 remove.index(x) 如果元素不在列表中,则都会给出错误。这导致我的程序停止运行。 绕过这个,我可以在之前使用这个声明 .remove()node in node_list 我觉得 in 检查元素是否是列表的一部分并返回bool。 只是仔细检查 谢谢,


4473
2017-07-12 16:45


起源



答案:


发生这种情况是因为您理解为识别您的两个实例的功能 Node 类,不是python如何理解它。

问题出在这里。假设你问python 5==5,python会回来 True。这是因为python知道 int秒。然而, 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))

这会奏效。但仔细观察后,很明显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

第二种方法试图删除 x 从 my_list 如果这导致错误,则忽略该错误


12
2017-07-12 16:57



所以只有一行像 __eq__(self, node)。嗯..很高兴了解python。谢谢! - user1521385
诺诺......不只是一条线。我发布的只是函数的签名。你需要完全定义它(参见我编辑的帖子) - inspectorG4dget
哦,好吧,是的,我正在阅读python库中的这个功能,然后你的例子有所帮助。谢谢! - user1521385
如果这是原因,我会感到有些惊讶。即使没有定义 __eq__, class Node: pass; a = [Node(), Node()]; b = a[:]; b.remove(a.pop(0)) 应该工作,我想。 - DSM
顺便说一句,我有一个快速跟进q,如果你可以检查出来..谢谢。 - user1521385


答案:


发生这种情况是因为您理解为识别您的两个实例的功能 Node 类,不是python如何理解它。

问题出在这里。假设你问python 5==5,python会回来 True。这是因为python知道 int秒。然而, 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))

这会奏效。但仔细观察后,很明显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

第二种方法试图删除 x 从 my_list 如果这导致错误,则忽略该错误


12
2017-07-12 16:57



所以只有一行像 __eq__(self, node)。嗯..很高兴了解python。谢谢! - user1521385
诺诺......不只是一条线。我发布的只是函数的签名。你需要完全定义它(参见我编辑的帖子) - inspectorG4dget
哦,好吧,是的,我正在阅读python库中的这个功能,然后你的例子有所帮助。谢谢! - user1521385
如果这是原因,我会感到有些惊讶。即使没有定义 __eq__, class Node: pass; a = [Node(), Node()]; b = a[:]; b.remove(a.pop(0)) 应该工作,我想。 - DSM
顺便说一句,我有一个快速跟进q,如果你可以检查出来..谢谢。 - user1521385


如果我正确地阅读了这个问题,那么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因此,当您调用时,节点将不再存在 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[:]

2
2017-07-12 17:15



我不认为我引用了它们。它们是独立的全球清单。在满足某些条件后,我通常只会将node_list中的一些节点附加到打开列表中。它们确实包含对相同对象的引用。 - user1521385
你能展示创建列表的代码吗? - Monkeyer
open_list = [] closed_list = [] node_list = []。通过循环来初始化节点列表。然后做其他的事情,如果我需要,可以附加到open_list。顺便说一下,我有一个快速跟进q,如果你能检查出来..谢谢。 - user1521385


在回复你的后续行动时,是的 in 将检查列表中的成员身份,因此:

if removed in node_list: node_list.remove(removed)

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

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

2
2017-07-12 18:36