How evil is this use of sys.getrefcount?

B

Brian Cole

I'm trying to cache the construction and destruction of an expensive
object coming out of a generator function. I can do the following to
force a new object to be used if the object is being used somewhere
else (based upon it's reference count). Here is the pseudo-code of
what I am trying to accomplish.

def GetExpensiveObjects():
obj = ExpensiveObject()
baserefs = sys.getrefcount(obj)
while UpdateExpensiveObject(obj):
yield obj
if sys.getrefcount(obj) > baseline + 1:
obj = ExpensiveObject()

Some users may use this generator by reading all objects into a list,
"objs = list(GetExpensiveObjects())". Others may use the generator and
just operate on each object totally independent of each other:
for obj in GetExpensiveObjects():
DoSomething(obj)

I would like to support both use cases. Unfortunately, the simple
approach of changing the following:
obj = ExpensiveObject()
while UpdateExpensiveObject(obj):
yield obj

To the following:
obj = ExpensiveObject()
while UpdateExpensiveObject(obj):
yield obj
obj = ExpensiveObject()

Is %30 - %50 more expensive. So is the getrefcount approach an
acceptable? I would prefer avoiding the proper object cache based on
weakref as it would be a lot more complexity.

Thanks
Brian
 
M

Miles

I'm trying to cache the construction and destruction of an expensive
object coming out of a generator function. I can do the following to
force a new object to be used if the object is being used somewhere
else (based upon it's reference count). Here is the pseudo-code of
what I am trying to accomplish.

def GetExpensiveObjects():
   obj = ExpensiveObject()
   baserefs = sys.getrefcount(obj)
   while UpdateExpensiveObject(obj):
       yield obj
       if sys.getrefcount(obj) > baseline + 1:
           obj = ExpensiveObject()

Seems pretty evil to me! My approach would probably either be to have
two generators and allow the user to decide if they want the object to
be valid after a subsequent call to the iterator, or to use a wrapper
object like the following:

class ExpensiveProxy(object):
_cache = []

def __init__(self):
if self.cache:
self._object = self._cache.pop()
else:
self._object = ExpensiveObject()
UpdateExpensiveObject(self._object)

def __del__(self):
self._cache.append(self._object)

# Define your own methods to wrap those of the object,
# or maybe define __getattr__

-Miles
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,170
Latest member
Andrew1609
Top