Sangeeth Saravanaraj wrote: > On Mon, Feb 24, 2014 at 10:53 PM, Peter Otten <__pete...@web.de> wrote: > >> Sangeeth Saravanaraj wrote: >> >> > I am trying to capture an object initiation and deletion events using >> > the __call__() and __del__() methods with the following approach. >> >> Note that there is no guarantee that __dell__ will ever be called. >> Usually it is better to introduce a weakref with callback. >> >> > class A(object): >> > def __init__(self, klass): >> > print "A::__init__()" >> > self._klass = klass >> > >> > def __call__(self): >> > print "A::__call__()" >> > return self._klass() >> > >> > def __del__(self): >> > print "A::__del__()" >> > >> > 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__() >> > >> > @A >> > class B(Parent1, Parent2): >> > def __init__(self): >> > print "B::__init__()" >> > super(B, self).__init__() >> > >> > def main(): >> > b = B() >> > >> > if __name__ == "__main__": >> > main() >> > >> > >> > I decorate a class, say class B (whose object initiation and deletion I >> > wanted to capture) with a decorator class A. Please note that the class >> > B is derived from two classes - Parent1 & Parent2 and I want to use >> > super() method to initialise the parent classes. >> > >> > When I executed the above code snippet, I ran into the following issue: >> > >> > >> > A::__init__() >> > A::__call__() >> > B::__init__() >> > Traceback (most recent call last): >> > File "so.py", line 40, in <module> >> > main() >> > File "so.py", line 36, in main >> > b = B() >> > File "so.py", line 10, in __call__ >> > return self._klass() >> > File "so.py", line 32, in __init__ >> > super(B, self).__init__() >> > TypeError: must be type, not A >> > A::__del__() >> > >> > >> > When I commented "super(B, self).__init__()" in the class B :: >> > __init__() method, it returned an object of type B and I was able to >> > see the prints in the __call__ and __del__ methods but the __init__() >> > methods of the >> base >> > classes (Parent1 & Parent2) are not called! >> > >> > From the error message, what I could understand is - the object >> > returned by A::__call__() is not of type B but of type A. But when I >> > put a print >> in >> > the A::__call__() I could see it returns an object of type B and not A. >> > >> > Now the question is - With this approach to capture the initiation and >> > deletion events of an object, how do I initialise the base classes >> > using super()? >> >> You'd have to introduce a naming convention or rewrite your class to be >> aware of the wrapping in some way: >> >> @A >> class B(Parent1, Parent2): >> def __init__(self): >> print "B::__init__()" >> super(B._klass, self).__init__() >> >> Not pretty. >> >> > Or, is there any other better way to capture the __call__ and __del__ >> > events for an object of a certain class - if so, how?! >> >> Most certainly, but you have to give some details about what you are up >> to first. >> > > Sorry, I should have described what I was trying! > > I want to create a decorator which should do the following things: > > - When an object of the decorated class is created, the objects name > (say the value of the incoming "id" argument) should be stored as a > record in a table in a database. > - When an object of the decorated class is deleted, the record with > this deleted objects name (i.e. object.id) should be removed from the > table. > > You can safely assume that all the database operations are working fine! > > Now, for example - consider the following snippet: > > @saveme > class A(object): > def __init__(self, id): > self.id = id > > @saveme > class B(object): > def __init__(self, id): > self.id = id > > "saveme" should do what I have explained earlier. > > a1 = A("A1") > a2 = A("A2") > a3 = A("A3") > b1 = B("B1") > b2 = B("B2") > > At this point if I query and print all the records in a table, I should > get the following: > output: ["A1", "A2", "A3", "B1", "B2"] > > del a1 > del a2 > del a3 > del b1 > del b2 > > At this point, all entries in the table should be deleted; query should > return an empty list! > > And, I want to highlight that the classes that are being decorated with > "saveme" can de derived classes too! > > What is the best way to do this?!
I'm sorry, after a bit of try-and-error I could not come up with a good way to write such a decorator. My best effort so far uses inheritance: import itertools import weakref _registry = weakref.WeakValueDictionary() _next_id = lambda count=itertools.count(): next(count) def show(): print(list(_registry.values())) class Registered(object): def __init__(self, id=None): if id is None: id = _next_id() self.id = id _registry[id] = self def __repr__(self): return "{}(id={!r})".format(self.__class__.__name__, self.id) class A(Registered): pass class B(Registered): pass class C(B): pass a1 = A() b1 = B() c1 = C() show() del a1 show() b2 = B() show() del b1 del c1 del b2 show() _______________________________________________ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor