Reputation: 1219
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?
Upvotes: 1
Views: 110
Reputation: 1123400
list.remove()
removes the first object that tests equal. From the documentation:
s.remove(x)
remove the first item from s wheres[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
.
Upvotes: 2