Fiskabollen
Fiskabollen

Reputation: 81

Automatic redis lookup for python objects

I'm trying to implement classes for which redis actually holds the attributes, but the user of the class is not aware of this (ie. object persistence across multiple clients). I know there are a few libs that wrap redis for python but none do exactly this in this simple way (but please correct me if I'm wrong on this!)

I've successfully implemented automatic redis storage of attributes but I can't seem to get retrieval to work using __getattribute__ without infinite recursion blowing it up. I think I am being careful about using object.__getattribute__ etc. but obviously I must be missing something:

class redisStored(object):
    global redis

    # A class method to implement object retrieval from redis
    # Call <Classname>.load(<id>) to create a new instance which exists in redis
    @classmethod
    def load(cls,id):
        # Create the object
        obj = cls.__new__(cls)
        # Set id without calling obj's __setattr__
        object.__setattr__(obj,'id',int(id))
        # Return the object we created
        return obj

    def __str__(self):
        # Return "<ClassName>:<id>" to differentiate ids in redis
        # You can use this to say redis.hgetall(g) where g is the instance

        return "%s:%s" % (self.__class__.__name__, str(object.__getattribute__(self,'id')))
        #                                     self.id here ^ would cause infinite recursion

    # This works fine
    def __setattr__(self,name,value):
        redis.hset(self,name,value)
        return object.__setattr__(self,name,value)

    # This blows up with infinite recursion, WHY??
    def __getattribute__(self,name):
        _val = redis.hget(self,name)
        if not _val:
            return object.__getattribute__(self,name)
        else:
            return _val

If I trace this it blows up inside _val = redis.hget(self,name) but I can't figure out why. Thanks for any help!

Upvotes: 3

Views: 440

Answers (1)

fvisconte
fvisconte

Reputation: 186

You should be very carefull with __getattribute__ overloading.

A side effect is that accessing self.__class__ calls __getattribute__ and creates a dummy redis query.

As you are using new-style classes you may want to use __getattr__ instead and avoid infinite recursion problem, although if you use __getattr__ you will return object attribute prior to redis value if this attribute already exists in your instance.

Anyway your object is kind-of immutable as long as you overloaded __setattribute__ method so this is not a big issue.

Please refer to this SO response for a more detailed difference between __getattr__ and __getattribute__ : Difference between __getattr__ vs __getattribute__

Upvotes: 2

Related Questions