Search code examples
pythonpyramid

@reify executes database queries every time called?


Based on this comment about reify,

It acts like @property, except that the function is only ever called once; after that, the value is cached as a regular attribute. This gives you lazy attribute creation on objects that are meant to be immutable.

I have this custom reify class:

class reify(object):
    def __init__(self, wrapped):
        self.wrapped = wrapped

    def __get__(self, inst):
        if inst is None:
            return self
        val = self.wrapped(inst)
        setattr(inst, self.wrapped.__name__, val)
        return val

And it's used like:

@reify
def user_details(self, user_id):
    try:
        # function that executes db query, returns dict
        return user_details_from_id(self._dbconn, user_id)
    except Exception as e:
        pass

Clearly, we can use it just doing name = self.user_details.get("name").

This works as expected, but not sure if this is caching the result or executing the query every time called, how can I confirm? I mean is this implementation correct? (don't have DB console)


Solution

  • A signature like def user_details(self, user_id) has too many args to be supported by @reify or even @property. It should be def user_details(self). The reify decorator will then modify the attribute self.user_details to return the same value for the duration of the instance. Note that it's not global, it's per-instance, because it uses self. To confirm it's caching, you can just put print statements in the user_details function to confirm it's only being invoked one time per instance.