Python Object Cache

I tried some code, but it seems to cause problems:

class Page: cache = [] """ Return cached object """ def __getCache(self, title): for o in Page.cache: if o.__searchTerm == title or o.title == title: return o return None """ Initilize the class and start processing """ def __init__(self, title, api=None): o = self.__getCache(title) if o: self = o return Page.cache.append(self) # Other init code self.__searchTerm = title self.title = self.someFunction(title) 

Then I try:

 a = Page('test') b = Page('test') print a.title # works print b.title # AttributeError: Page instance has no attribute 'title' 

What is wrong with this code? Why is this not working? Is there any way to make it work? If not, how is it easy and transparent to switch to end-user cache objects?

+3
source share
3 answers

if you want to manipulate the creation, you need to change __new__ .

 >>> class Page(object): ... cache = [] ... """ Return cached object """ ... @classmethod ... def __getCache(cls, title): ... for o in Page.cache: ... if o.__searchTerm == title or o.title == title: ... return o ... return None ... """ Initilize the class and start processing """ ... def __new__(cls, title, api=None): ... o = cls.__getCache(title) ... if o: ... return o ... page = super(Page, cls).__new__(cls) ... cls.cache.append(page) ... page.title = title ... page.api = api ... page.__searchTerm = title ... # ...etc ... return page ... >>> a = Page('test') >>> b = Page('test') >>> >>> print a.title # works test >>> print b.title test >>> >>> assert a is b >>> 

EDIT: using __init__ :

 >>> class Page(object): ... cache = [] ... @classmethod ... def __getCache(cls, title): ... """ Return cached object """ ... for o in Page.cache: ... if o.__searchTerm == title or o.title == title: ... return o ... return None ... def __new__(cls, title, *args, **kwargs): ... """ Initilize the class and start processing """ ... existing = cls.__getCache(title) ... if existing: ... return existing ... page = super(Page, cls).__new__(cls) ... return page ... def __init__(self, title, api=None): ... if self in self.cache: ... return ... self.cache.append(self) ... self.title = title ... self.api = api ... self.__searchTerm = title ... # ...etc ... >>> >>> a = Page('test') >>> b = Page('test') >>> >>> print a.title # works test >>> print b.title test >>> assert a is b >>> assert a.cache is Page.cache >>> 
+5
source

You cannot change an instance of an created object after it is created. When setting self to something else, all you do is change the link the variable points to, so the actual object is not affected.

This also explains why the title attribute is missing. You return as soon as you change the local variable self , not allowing the current instance to initialize the title attribute (not to mention the fact that self at this point does not point to the correct instance).

Thus, you cannot change the object during its initialization (in __init__ ), since at that moment it was already created and assigned to a variable. A constructor call of type a = Page('test') is actually the same as:

 a = Page.__new__('test') a.__init__('test') 

So, as you can see, the __new__ class constructor call is first made, and this is actually responsible for instantiating. This way you can overwrite the __new__ class method to manipulate the creation of the object.

Usually the preferred way is to create a simple factory method, for example:

 @classmethod def create (cls, title, api = None): o = cls.__getCache(title) if o: return o return cls(title, api) 
+2
source

self is an ordinary local variable, so setting self = .. just changes what points to the self variable in this function. It does not modify the actual object.

See: Is it possible to replace the self object with another object of the same type in the method?

To do what you want, you can use a static function as a factory :

 class Page: cache = [] """ Return cached object """ @staticmethod def create(title): for o in Page.cache: if o.__searchTerm == title or o.title == title: return o return Page(title) """ Initilize the class and start processing """ def __init__(self, title, api=None): Page.cache.append(self) # Other init code self.__searchTerm = title self.title = title a = Page.create('test') b = Page.create('test') print a.title print b.title 
0
source

Source: https://habr.com/ru/post/1441933/


All Articles