I could use some help … I can not figure out why some code doesn’t seem to work.
I have created a global cache decorator. And it’s working as far as caching the values of the functions I wrap in it… but I need to be able to also clear an item from the cache (so I can update/replace it’s cached values.)
What is not working, the the deletion of the ‘key item’ from the cache dictionary, I have tried several ways of tring to remove the key and they all seem to fail. I am not sure what I am doing wrong.
here is the code for the cache:
############################################################################
### cache
## -------------------------------------------------------------------------
global CacheDepot
CacheDepot = {}
# --function----------------------------------------------------------------
def cacheItem(function):
global CacheDepot
def wrapper(*args):
if args in CacheDepot:
return CacheDepot[args]
else:
rv = function(*args)
CacheDepot[args] = rv
return rv
return wrapper
and here is a wip function to remove an item from the cache based on it’s itemKey (using filePath for example):
# --function----------------------------------------------------------------
def cacheDelItem(itemKey):
global CacheDepot
try:
CacheDepot.has_key(itemKey)
print 'The item was in the cache.'
pass
except:
print 'The itemKey is not in the cache'
pass
try:
r = dict(CacheDepot)
# r.__delitem__(itemKey)
try:
del r[itemKey]
except KeyError:
pass
#keyPop = r.pop(itemKey, None)
CacheDepot = r
return True
except:
print 'Could not delete that itemKey'
pass
return None
So I am watching things in the debugger, I know the key is there … and it passes this check:
CacheDepot.has_key(itemKey)
but none of my attempts to try and remove it pass.
dict.has_key will never error, why is that in a try/except statement?
If you want to test dictionary membership, just use
if key in CacheDepot:
# key exists
else:
# key doesn't exist
I’m not sure why you have so many try/except statements. Also I would recommend always avoiding general try/excepts (where you aren’t specifying an exception type to catch), unless you want to do something with the traceback data or you really don’t care why it failed. General try/excepts like that are dangerous because they hide issues with your code–you should be as specific as possible with the exceptions you allow.
Your delete function can just be:
def cacheDelItem(itemKey):
global CacheDepot
if itemKey in CacheDepot:
del CacheDepot[itemKey]
return True
Agree with TheMaxx. The exceptions raised might help you work out what’s going wrong so don’t catch them all and throw them away.
Just a guess but I’d expect something like this to work:
def cacheDelItem(itemKey):
global CacheDepot
if itemKey in CacheDepot:
del CacheDepot[itemKey]
Personally, I’d also consider grouping your cache dict and cache functionality into a class rather than using a global. You don’t know what else might overwrite the global so that could end up giving you weird bugs (if not now then later).
Edit: Beaten by capper once again :P. I’ll leave it for agreement’s sake
[QUOTE=Warheart;22350]Agree with TheMaxx. The exceptions raised might help you work out what’s going wrong so don’t catch them all and throw them away.
Just a guess but I’d expect something like this to work:
def cacheDelItem(itemKey):
global CacheDepot
if itemKey in CacheDepot:
del CacheDepot[itemKey]
Personally, I’d also consider grouping your cache dict and cache functionality into a class rather than using a global. You don’t know what else might overwrite the global so that could end up giving you weird bugs (if not now then later).
Edit: Beaten by capper once again :P. I’ll leave it for agreement’s sake :)[/QUOTE]
I was trying to figure out a method of a shared cache across some modules (which all act on some paths).
so I put my code in a cache.py file, then I created a cache:
global CacheDepot
CacheDepot = {}
Then I could import that same CacheDepot into any other place I wanted to share it.
I know it’s probably not the best way to do it, and I was planning on upgrading it to something more robust … but in the short term I was just playing with code and trying something new I have never done before.
I don’t have a lot of experience with global caching, but my first instinct is that your current method isn’t restrictive enough. What if you have two functions that take the same argument, say a filename, but one returns a p4 fstat and the other returns the root directory of the character or environment the file is in? What about using a local cache for each function? Or at least storing the cached keys with a little more granularity, like under the calling function’s object, or in categories like ‘fstat’.
I feel like the implementation will depend a lot on how you anticipate using it–like whether it’s just for caching perforce results, or intended as something a bit more general that persists between different modules (which it sounds to be). Most caching implementations I’ve seen/used (like a lazy-loading descriptor) as restricted to classes/specific data types.
yes, all things to consider … this experiment, I was pretty specific in what I wanted to do… cache perforce fstats. And I realized in messing around that I even had to make sure that the item I was caching was hashable. etc. early on, I ended up with a dict that ended up looking like it have many multiple/duplicate keys (I know that doesn’t make sense). Anyway, I decided that I was just going to deal with this one specific case (path, fstats) and see if I could get a dirt simple solution implemented/working (not a final solution.) I still have zero clue why I couldn’t get keys to delete properly in that version, even though I could verify if that value was a key in the dict.
Anyway, I have a much better solution working now - per function cache decorator, with a max size queue, clear, delete, etc.
And so via imports, I can use a cached function across multiple modules and have it be shared in an app. It’s much nicer and actually easier to debug then a generic global cache.
I appreciate the input and help.
My delete function now looks like this:
def delItemKey(*args, **kwargs):
itemkey = args
if kwargs:
itemkey += (kwarg_mark,) + tuple(sorted(kwargs.items()))
if itemkey in CacheDepot:
del CacheDepot[itemkey]
return True
and I am using the same implementation to build the original key, and this works great.