I have a simple custom object that represent custom tag, that user can attach to another object.
- I want to store tags in a set, because I want to avoid duplicates and because order doesn't matter.
- Each tag contain values "name" and "description". Later on, I might add another variables, but the key identifier for tag is "name".
- I want to check whether tag is equal to other either by
tag.name == other.name
or against stringtag == 'whatever'
. - I want users to be able to edit tags including renaming them.
I have defined the object like this and everything worked as expected:
class Tag:
def __init__(self, name, description=""):
self.name = name
self.description = description
def __str__(self):
return self.name
def __repr__(self):
return self.name
def __eq__(self, other):
if isinstance(other, Tag):
return self.name == other.name
else:
return self.name == other
def __hash__(self):
return hash(self.name)
The problem appeared, when I tried to change the tag name:
blue_tag = Tag("blue")
tags = {blue_tag}
blue_tag in tags # returns True as expected
"blue" in tags # returns True as expected
blue_tag.name = "navy"
"navy" in tags # returns False. Why?
I don't understand why. The tag is correctly renamed, when I do print(tags)
. The id of bluetag object is also the same, hash of the name is also the same.
Everywhere, including Python official documentation, I found just basic info that in
checks whether item is present in container and to define custom container, I need to define custom methods like __contains__
But I don't want to create custom set method.
The closest thing I found I found was a question here on SO:
Custom class object and "in" set operator
But it still didn't solve the problem.