0

Assume that I have a class (Base) & a list (obj)

class Base:
    def __init__(self, x, y):
        self.x = x 
        self.y = y 

    def __repr__(self):
        return f"Base({self.x}, {self.y})"

    def area(self):
        return self.x*self.y

obj = [Base(10, 12), Base(2, 5), Base(7, 8)]

How to remove Base(2, 5) from the obj list? The obj.remove(Base(2,5)) does not work. Any Suggestions?

DaCard
  • 511
  • 4
  • 15
  • 2
    `obj.remove(Base(2,5))` won't work because you haven't told `Base` how to tell if two instances are equal. You could use `del obj[1]`. – khelwood May 07 '21 at 20:29
  • See your answer here: https://stackoverflow.com/questions/9140857/oop-python-removing-class-instance-from-a-list#9140906, you need to iterate through the list. – Itay Dumay May 07 '21 at 20:30
  • 2
    @khelwood The asker did not ask how to remove/delete an element by its' index, the question above was about how to remove a specific object instance from the list. – Itay Dumay May 07 '21 at 20:34
  • https://stackoverflow.com/questions/1227121/compare-object-instances-for-equality-by-their-attributes does this answer your question? – QWERTYL May 07 '21 at 20:34
  • 1
    @ItayDumay My suggestion does literally what they asked for, even if it turned out not to be what they wanted. Suggestions that are rejected lead the OP to clarify their requirements. That's why it was posted as a comment and not an answer. – khelwood May 07 '21 at 20:39
  • There are no class objects in your list. There are *instanes* of the `Base` clas... – juanpa.arrivillaga May 07 '21 at 21:14

2 Answers2

6

list.remove needs to be able to tell when the element to be removed is the same as one of the elements in the list.

so you could implement an __eq__ method along those lines:

class Base:    
    def __eq__(self, other):
        if not isinstance(other, Base):
            return NotImplemented
        return self.x, self.y == other.x, other.y

and obj.remove(Base(2,5)) will work.

hiro protagonist
  • 44,693
  • 14
  • 86
  • 111
2

Your immediate problem is that you do not have an element called Base(2, 5) in that list: you have three object descriptors. Your call to remove does not refer to any of those three elements: it refers to a fourth element. Yes, that element happens to have the same attributes as one list element, but you have not implemented the equality operator for Base to recognize that coincidence.

The brute-force way is to iterate through the list and find the corresponding element:

for elem in obj:
    if (elem.x, elem.y) == (2, 5):
        obj.remove(elem)
        break
Prune
  • 76,765
  • 14
  • 60
  • 81
  • 1
    You're welcome ... but please note that the previous answer and my comment (implement `__eq__` for your class) is the *proper* way to handle this situation. In general, you'll want to use the built-in capabilities for any optimizations in the underlying implementation. In this case, Hiro's answer is much cleaner and easier to maintain; mine *might* be a tiny amount faster ... and not worth the maintenance costs. – Prune May 07 '21 at 20:43