Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

removing an instance of an object in python list

I Think this should work but its giving me an error. I have a list that contains objects of class node. I have two different lists

  1. open_list
  2. node_list.( they are not the same lengthwise, ordering wise)

When I find a specific node in the open_list I need to delete it from the node_list. I know that the lists have addresses to the objects stored in them

so when i try to do

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

it gives me an error saying

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

but the list just contains addresses that act like pointers right? it should match up the same addresses. i printed out the address of removed and the whole node_list (only 10 items for now don't fear) print out: (the last item in node_list matches the address of removed:

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>]

Thanks

follow-up Q

so I want to check if the node i want to remove exists in the node_list. when i looked up some simple list functions on http://docs.python.org/tutorial/datastructures.html

list.index(x) and remove.index(x) both give an error if the element is not in the list. this caused my program to stop running. to bypass this, can i use this statement before the .remove(): node in node_list i think the in checks to see if an element is part of a list and returns a bool. just double checking thanks,

like image 879
user1521385 Avatar asked Jul 12 '12 16:07

user1521385


People also ask

How do you remove an object from a list in Python?

In Python, use list methods clear() , pop() , and remove() to remove items (elements) from a list. It is also possible to delete items using del statement by specifying a position or range with an index or slice.

How do I remove an object from a list?

The remove(Object obj) method of List interface in Java is used to remove the first occurrence of the specified element obj from this List if it is present in the List. Parameters: It accepts a single parameter obj of List type which represents the element to be removed from the given List.

How do you delete an object from an instance in Python?

To delete an object in Python, we use the 'del' keyword. A when we try to refer to a deleted object, it raises NameError.

What is remove () in Python?

In this tutorial, we will learn about the Python List remove() method with the help of examples. The remove() method removes the first matching element (which is passed as an argument) from the list.


2 Answers

This is happening because what you understand as identifying features of two instances of your Node class, is not how python understands it.

The problem lies here. Suppose you asked python 5==5, python would return True. This is because python knows about ints. However, Node is a custom class that you defined, so you need to tell python when two Node objects are the same. Since you (probably) haven't, python defaults to comparing their locations in memory. Since two separate instances will be in two different memory locations, python will return False. If you are familiar with Java at all, this is like the difference between == and .equals(...)

In order to do this, go into your Node class and define the __eq__(self, other) method, where other is expected to be another instance of Node.

For example, if your nodes have an attribute called name and two nodes that have the same name are considered to be the same, then your __eq__ could look like this:

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

Of course, the more elegant way of writing that same function is:

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

When this is done, your error should disappear

EDIT 1: In response to DSM's comment

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

This will work. But upon closer inspection, it becomes evident that a[0] and b[0] are in fact the same object. This can be verified by calling id(a[0]) and comparing it with id(b[[0]) to confirm that they are indeed the same

EDIT 2: In response to the OP's follow up question (added to the original question as edit)

Yes, the object not existing in the list will cause an error which would normally stop program flow. This can be solved in either of the following two ways:

if x in my_list:
    my_list.remove(x)

OR

try:
    my_list.remove(x)
except:
    pass

The second method attempts to remove x from my_list and if that results in an error, ignores the error

like image 157
inspectorG4dget Avatar answered Sep 28 '22 07:09

inspectorG4dget


If I read the question right, python's default of comparing the memory locations is the behavior he is looking for, but is not getting. Here's a working example where a custom class is defined Node, it show's that there is no need for the __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)

I can't be sure, because you did not show where your open_node_list and node_list were defined, but I suspect that the lists themselves reference the same list object. If that's the case, the popping from open_node_list also pops from node_list, therefore the node will no longer exist when you call remove. Here is example in which node_list and open_node_list are really the same list and so changes to one affect the other:

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)

One way you can copy a list is:

node_list = open_node_list[:]
like image 25
Monkeyer Avatar answered Sep 28 '22 06:09

Monkeyer