[Baypiggies] Class decorator to capture the creation and deletion of objects

Alex Martelli aleax at google.com
Mon Feb 24 21:24:52 EST 2014


Off the cuff, I'd make saveme into a function, not a class;
the saveme function would alter the class passed in as its only argument
(saving __init__ and/or __del__ methods it may have and replacing them with
other -- nested -- functions that call them and do the rest of the job) and
return the same class object it received.

No time to actually write the code but this seems a much sounder
architecture.


Alex



On Mon, Feb 24, 2014 at 4:49 PM, Sangeeth Saravanaraj <
sangeeth.saravanaraj at gmail.com> wrote:

> This question was initially asked in tutor at python.org; Now I am widening
> the audience to gain attention.
>
> 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.
>
> 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 [which initialises its base classes
> using super() method]!
>
> Now the following is what I have tried:
>
> class saveme(object):
>     def __init__(self, klass):
>         print "saveme::__init__()"
>         self._klass = klass
>
>     def __call__(self, *args, **kwargs):
>         print "saveme::__call__()"
>         obj = self._klass(*args, **kwargs)
>         # creation of DB record will happen here!
>         # i.e. something like add_to_db(kwargs.get("id"))
>         return obj
>
>     def __del__(self):
>         # deletion of DB record will happen here!
>         # i.e. something like remove_from_db(id)
>         # TODO: how to retrieve the "id" here?!
>         print "saveme::__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__()
>
>
> @saveme
> class A(Parent1, Parent2):
>     def __init__(self, id):
>         print "A::__init__()"
>         self.id = id
>         #super(A, self).__init__()
>
>
> #@saveme
> #class B(object):
> #    def __init__(self, id):
> #        print "B::__init__()"
> #        self.id = id
>
>
> def main():
>     a1 = A(id="A1")
> #    b1 = B(id="B1")
>
> if __name__ == "__main__":
>     main()
>
>
> When executed the above, I ran in to the following:
>
> saveme::__init__()
> saveme::__call__()
> A::__init__()
> Traceback (most recent call last):
>   File "1.py", line 54, in <module>
>     main()
>   File "1.py", line 50, in main
>     a1 = A(id="A1")
>   File "1.py", line 10, in __call__
>     obj = self._klass(*args, **kwargs)
>   File "1.py", line 39, in __init__
>     super(A, self).__init__()
> TypeError: must be type, not saveme
> saveme::__del__()
>
>
> When I commented "super(A, self).__init__()" in the class A :: __init__()
> method, it returned an object of type A and I was able to see the prints in
> the __call__ and __del__ methods but the __init__() methods of the base
> classes (Parent1 & Parent2) were not called!
>
> From the error message, what I could understand is - the object returned
> by saveme::__call__() is not of type A but of type saveme. But when I put a
> print in the saveme::__call__() I could see it returns an object of type A
> and not saveme.
>
> 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()?
>
> Or, is there any other better way to capture the __call__ and __del__
>  events for an object of a certain class - if so, how?!
>
> Thank you,
>
> Sangeeth
>
>
> PS:
> http://stackoverflow.com/questions/21826854/typeerror-when-using-super-method-with-class-decorator-for-a-derived-class
>
>
> _______________________________________________
> Baypiggies mailing list
> Baypiggies at python.org
> To change your subscription options or unsubscribe:
> https://mail.python.org/mailman/listinfo/baypiggies
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20140224/d3d37c76/attachment.html>


More information about the Python-list mailing list