1

I am wondering about how Python handles the user-defined objects. So here is the scenario:

I have created my own class called MyClass:

class MyClass():
  def __init__(self):
    # some code here

class MyClassContainer():
  def __init__(self):
    self.container = [] # will store MyClass object instances.
  def Add(self, object):
    self.container.append(object)
  def Remove(self, object):
    self.container.remove(object)

example = MyClassContainer()

myclass1 = MyClass()
example.Add(myclass1)

myclass2 = MyClass()
example.Add(myclass2)

example.Remove(myclass1)

So the question, is python's remove function able to distinguish different object instances of the same class? Is there any corner case that will not uniquely identify the object instance I wanted to delete?

A possible scenario is this one:

myclass1 = MyClass(5)
example.Add(myclass1)

myclass1 = MyClass(3)
example.Add(myclass1)

example.Remove(myclass1)

Which object instance will be removed? I guess the one with 3 passed, but is there a rule that says, python uniquely identify object instances of the same class?

1
  • you have to define how they are compared using __eq__. Basically locates the myclass1 == example.container element and removes that. Commented Nov 9, 2015 at 22:12

1 Answer 1

2

list.remove() removes the first object that tests equal. From the documentation:

s.remove(x)
remove the first item from s where s[i] == x

Instances of a custom class by default only test equal if they are the exact same object; if s[i] is x returns true then s[i] == x also returns true.

It is not the variable name that defines the instance; in your second example, it'll be the MyClass(3) instance that is removed from the list, because it is a unique object, distinct from the MyClass(5) instance you created and added before. You can check this with the id() function, which on CPython basically returns the current memory address:

>>> myclass1 = MyClass(5)
>>> id(myclass1)
4349144816
>>> example.Add(myclass1)
>>> myclass1 = MyClass(3)
>>> id(myclass1)
4349145040
>>> example.Add(myclass1)
>>> example.container
[<__main__.MyClass object at 0x1033aaef0>, <__main__.MyClass object at 0x1033aafd0>]
>>> hex(id(myclass1))
'0x1033aafd0'
>>> myclass1 is example.container[1]
True
>>> example.Remove(myclass1)
>>> example.container
[<__main__.MyClass object at 0x1033aaef0>]

Note that the default representation of your custom classes include the id() value in hexadecimal!

You can alter this behaviour by overriding the object.__eq__() method; have it return True or False based on your own criteria, or return the NotImplemented singleton if the other object is not a type your class supports being compared with (so Python can delegate to the other object).

For example, if your instances should be considered equal when their number attribute is equal, you'd implement it like this:

class MyClass():
    def __init__(self, number):
        self.number = number

    def __eq__(self, other):
        if not isinstance(other, MyClass):
            return NotImplemented
        return self.number == other.number

With that change, you can do this:

example.Add(MyClass(42))
example.Add(MyClass(81))
example.Remove(MyClass(42))

and that would remove the instance with number set to 42.

Sign up to request clarification or add additional context in comments.

1 Comment

And if you were on Python 2, while you're defining __eq__, you'd want to either set __hash__ = None or define a reasonable __hash__ method, so dicts and sets don't go crazy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.