1

I'd like to add an attribute to an instance which is in a set. The set of objects of the class Problem is identified by attribue uid (that's why they are hashed and compared):

class Problem:
    allowed_keys = [
        'flag1',
        'a_list_of_objects'
    ]

    def __init__(self, uid, name, **kwargs):
        self.uid = uid
        self.name = name
        self.__dict__.update((k, v) for k, v in kwargs.iteritems() if k in self.allowed_keys)

    def __eq__(self, other):
        return isinstance(other, self.__class__) and getattr(other, 'uid', None) == self.uid

    def __hash__(self):
        return hash(self.uid)

    def __ne__(self, other):
         return not self.__eq__(other)

    def __repr__(self):
         return json.dumps(self.__dict__, sort_keys=True)

All instances of this problem are added to a set.

problem_set = set()

problem1 = Problem(uid="abc123", name="name1", flag1=True)
problem_set.add(problem1)

problem2 = Problem(uid="xyz789", name="name2", flag2=False)
problem_set.add(problem2)

Now if I want to update the object problem1 with another attribute (it will never exist before), it just won't add the a_list_of_objects to the existing problem1

my_list = [{"a": "avalue", "b": "bvalue"}]
problem3 = Problem(uid="abc123", name="name1", a_list_of_objects=my_list

print list(problem_set)
# same list as before

What do I need to do in order to achieve this? Using @property and create getters and setters for each attribute of class Problem?

1 Answer 1

2

You are not modifying the existing problem1 instance. You are creating an entirely different instance problem3 albeit equal to problem1 going by your implementation of __eq__. Instances satisifying equality are not merged or synced in the way I think you expect. Instances of your class with the same uid and thus hash value can exist freely outside a set as independent objects. Trying to add one of both to a set will drop one, not sync them.

To modify problem1 you should instead do:

problem1.a_list_of_objects = my_list

Or you could assign to a copy of my_list to avoid sharing the same list among instances:

import copy

problem1.a_list_of_objects = copy.deepcopy(my_list)

New attributes can be bound to an existing instance of your class.

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

3 Comments

How do I properly merge them then (based on the uid)? I need to merge multiple attributes to the instance if it's already there, or create a new one if not. The list should be shared among instances.
You need to iterate through the set and check if an instance with that uid already exists. If yes, update. If no, create a new one. You can also use in to test if an equal instance already exists, but that won't give you a reference to the instance. A set comprehension can be used with the in check - if the check passes, and a simple set.add if it fails.
Thanks. Your input made me rewrite the code so that the Problem instance creation happens as a last step when all values are decided. Much simpler.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.