I took sometime to understand why it is hard to capture the object instantiation and object deletion using __call__
and __del__
methods respectively. The following are some of the useful references
- http://eli.thegreenplace.net/2009/06/12/safely-using-destructors-in-python/
- I don't understand this python __del__ behaviour
- the same topic has also been discussed in the python-list mailer - check out the thread here - https://mail.python.org/pipermail/python-list/2014-February/667592.html
There are excellent hacks available to do this using __del__
method but they are have side effects! For example, the answer given by @user2357112 is a good hack but it does not work when we make a circular reference because the garbage collector cannot determine which __del__
among the circular reference to call first! However this can be avoided by using a weak ref; but its still a hack!
One of the suggestions that was made was to create a context manager which can create and delete the objects of a particular class.
I have the following example which sort of emulates that. Please take a closer look at the Controller
decorator.
class Parent1(object):
def __init__(self):
#print "Parent1::__init__()"
super(Parent1, self).__init__()
class Parent2(object):
def __init__(self):
#print "Parent2::__init__()"
super(Parent2, self).__init__()
def Controller(_cls):
class Wrapper(_cls):
def create(self, name):
ret = _cls.create(self, name)
print "Added to Database! :: ", name
# Database add here!
return ret
def remove(self, name):
ret = _cls.remove(self, name)
print "Deleted from Database! :: ", name
# Database delete here!
return ret
return Wrapper
@Controller
class Manager(object):
def __init__(self):
#print "Manager::__init__()"
self._repo = []
def create(self, name):
a = A(name)
print "Object created :: ", name
self._repo.append(a)
def remove(self, name):
for i, item in enumerate(self._repo):
if item._name == name:
del self._repo[i]
print "Object removed :: ", name
def display(self):
for item in self._repo:
print item
class A(Parent1, Parent2):
def __init__(self, name):
#print "A::__init__()"
self._name = name
super(A, self).__init__()
def __repr__(self):
return self._name
def main():
m1 = Manager()
m1.create("apples")
m1.create("oranges")
m1.create("grapes")
#m1.display()
m1.remove("apples")
#m1.display()
if __name__ == "__main__":
main()
When executed, it produces the following result:
Object created :: apples
Added to Database! :: apples
Object created :: oranges
Added to Database! :: oranges
Object created :: grapes
Added to Database! :: grapes
Object removed :: apples
Deleted from Database! :: apples
This is the safest solution that I could come up for my problem. Suggestions welcome!