How can I memoize a class instantiation in Python?

前端 未结 3 1637
抹茶落季
抹茶落季 2020-12-05 04:47

Ok, here is the real world scenario: I\'m writing an application, and I have a class that represents a certain type of files (in my case this is photographs but that detail

3条回答
  •  攒了一身酷
    2020-12-05 05:41

    The solution that I ended up using is this:

    class memoize(object):
        def __init__(self, cls):
            self.cls = cls
            self.__dict__.update(cls.__dict__)
    
            # This bit allows staticmethods to work as you would expect.
            for attr, val in cls.__dict__.items():
                if type(val) is staticmethod:
                    self.__dict__[attr] = val.__func__
    
        def __call__(self, *args):
            key = '//'.join(map(str, args))
            if key not in self.cls.instances:
                self.cls.instances[key] = self.cls(*args)
            return self.cls.instances[key]
    

    And then you decorate the class with this, not __init__. Although brandizzi provided me with that key piece of information, his example decorator didn't function as desired.

    I found this concept quite subtle, but basically when you're using decorators in Python, you need to understand that the thing that gets decorated (whether it's a method or a class) is actually replaced by the decorator itself. So for example when I'd try to access Photograph.instances or Camera.generate_id() (a staticmethod), I couldn't actually access them because Photograph doesn't actually refer to the original Photograph class, it refers to the memoized function (from brandizzi's example).

    To get around this, I had to create a decorator class that actually took all the attributes and static methods from the decorated class and exposed them as it's own. Almost like a subclass, except that the decorator class doesn't know ahead of time what classes it will be decorating, so it has to copy the attributes over after the fact.

    The end result is that any instance of the memoize class becomes an almost transparent wrapper around the actual class that it has decorated, with the exception that attempting to instantiate it (but really calling it) will provide you with cached copies when they're available.

提交回复
热议问题