Is there any method I can override that will allow me to use print statements / pdb / etc. to keep track of every time an instance of my class is allocated? While unpickling some objects I am seeming to get some that never have either __setstate__ or __init__ called on them. I tried overriding __new__ and printing out the id of every object I make in __new__, but I am still encountering objects with ids that were never printed.
Edit: here is my code I use for altering (instrumenting) __new__ of my class and all of its super-classes except for object itself:
class Allocator:
def __init__(self, my_class):
self.my_class = my_class
self.old_new = my_class.__new__
def new(self, * args, ** kargs):
rval = self.old_new(*args, ** kargs)
#rval = super(self.my_class,cls).__new__(cls)
print 'Made '+str(self.my_class)+' with id '+str(id(rval))
return rval
def replace_allocator(cls):
if cls == object:
return
setattr(cls,'__new__',Allocator(cls).new)
print cls.__base__
try:
for parent in cls.__base__:
replace_allocator(parent)
except:
replace_allocator(cls.__base__)
I call replace_allocator on my classes' parent class as soon as it is imported in the main script. My class has a custom __new__ to begin with, which also prints out the id.
3 Answers 3
(This is more of a comment than an answer.)
Quoting Guido's Unifying types and classes in Python 2.2:
There are situations where a new instance is created without calling
__init__(for example when the instance is loaded from a pickle). There is no way to create a new instance without calling__new__(although in some cases you can get away with calling a base class's__new__).
If you are using new-style classes (descendants of object), __new__() should always be called. I don't think the obscure cases "you can get away with calling a base class's __new__" in will happen accidently, though I don't know what these cases actually are.
And just to add an example:
In [1]: class A(object):
...: def __new__(cls):
...: print "A"
...: return object.__new__(cls)
...:
In [2]: A()
A
Out[2]: <__main__.A object at 0xa3a95cc>
In [4]: object.__new__(A)
Out[4]: <__main__.A object at 0xa3a974c>
1 Comment
__new__ for classes other than object itself.Are you using new-style classes? For Pickle to call __setstate__, the __getstate__ method should also be defined on the class returning a non-False value.
1 Comment
__getstate__ implemented. Also, __setstate__ is getting called on most but not all instances of the class.Not sure if this can help you, but Python's garbage collector has introspective capabilities that might be worth taking a look at.
id(instance)matches?Allocator(cls)as a type cast? If so, it is wrong, because in Python it is a constructor call for anAllocatorobject, and the.newpart will get a new bound-method instance.Allocator(cls)as a constructor call for anAllocatorobject. The point of anAllocatorconstructed withclsis to call the original__new__method ofclsand report theidof the resulting object instance.for parent in cls.__bases__. You don't need the fall-back tocls.__base__. And don't use catch-allexcept:clauses. They always bite you.