Update object_cache.py

clean code
This commit is contained in:
Hellow 2023-02-13 16:45:12 +01:00
parent 47bc91ff20
commit 353cf22dfb

View File

@ -1,4 +1,6 @@
from typing import Dict, List
from collections import defaultdict
from typing import Dict, List, Optional
import weakref
from .objects import MusicObject
@ -9,52 +11,96 @@ This is necessary, to not have duplicate objects with the same id.
Using a cache that maps the ojects to their id has multiple benefits:
- if you modify the object at any point, all objects with the same id get modified *(copy by reference)*
- less ram usage
- to further decrease ram usage I only store weak refs and not a strong reference, for the gc to still work
"""
class ObjectCache:
"""
:attr object_to_id: maps any object from the Database like Song or Artist to its id.
"""
ObjectCache is a cache for the objects retrieved from a database.
It maps each object to its id and uses weak references to manage its memory usage.
Using a cache for these objects provides several benefits:
- Modifying an object updates all objects with the same id (due to copy by reference)
- Reduced memory usage
:attr object_to_id: Dictionary that maps MusicObjects to their id.
:attr weakref_map: Dictionary that uses weak references to MusicObjects as keys and their id as values.
:method exists: Check if a MusicObject already exists in the cache.
:method append: Add a MusicObject to the cache if it does not already exist.
:method extent: Add a list of MusicObjects to the cache.
:method remove: Remove a MusicObject from the cache by its id.
:method get: Retrieve a MusicObject from the cache by its id. """
object_to_id: Dict[str, MusicObject]
weakref_map: Dict[weakref.ref, str]
def __init__(self) -> None:
self.object_to_id = dict()
def clear(self) -> None:
"""
deletes all references and lets the gc clean up the rest
this should free up memorie.
If not, check if you have any references to an object in you're code.
It is likely that this object crossreferences to many objects
"""
self.object_to_id = dict()
self.weakref_map = defaultdict()
def exists(self, music_object: MusicObject) -> bool:
"""
:returns exist: if an element with the same id exists it returns true, else false
Check if a MusicObject with the same id already exists in the cache.
:param music_object: The MusicObject to check for.
:return: True if the MusicObject exists, False otherwise.
"""
if music_object.dynamic:
return True
if music_object.id in self.object_to_id:
return True
return False
return music_object.id in self.object_to_id
def on_death(self, weakref_: weakref.ref) -> None:
"""
Callback function that gets triggered when the reference count of a MusicObject drops to 0.
This function removes the MusicObject from the cache.
:param weakref_: The weak reference of the MusicObject that has been garbage collected.
"""
data_id = self.weakref_map.pop(weakref_)
self.object_to_id.pop(data_id)
def append(self, music_object: MusicObject) -> bool:
"""
:returns exist: if an element with the same id exists it returns true, else false
Add a MusicObject to the cache.
:param music_object: The MusicObject to add to the cache.
:return: True if the MusicObject already exists in the cache, False otherwise.
"""
if self.exists(music_object):
return True
self.weakref_map[weakref.ref(music_object, self.on_death)] = music_object.id
self.object_to_id[music_object.id] = music_object
return False
def extent(self, music_object_list: List[MusicObject]):
"""
adjacent to the extend method of list, this appends n Object
adjacent to the extent method of list, this appends n Object
"""
for music_object in music_object_list:
self.append(music_object)
self.append(music_object)
def remove(self, _id: str):
"""
Remove a MusicObject from the cache.
:param _id: The id of the MusicObject to remove from the cache.
"""
data = self.object_to_id.get(_id)
if data:
self.weakref_map.pop(weakref.ref(data))
self.object_to_id.pop(_id)
def __getitem__(self, item) -> Optional[MusicObject]:
"""
this returns the data obj
:param item: the id of the music object
:return:
"""
return self.object_to_id.get(item)
def get(self, _id: str) -> Optional[MusicObject]:
return self.__getitem__(_id)