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

David Lawrence david at bitcasa.com
Mon Feb 24 22:46:07 EST 2014


If as according to the docs, there is no guarantee of __del__ being called,
anything that relies on that seems unsafe (depending on how robust one
needs the solutions to be).  Solutions I've seen elsewhere suggest creating
something like a *release()* method on your objects and calling it
explicitly before calling *del my_obj *(if you even call del, rather than
just relying on GC).

Alternatively, if it suits the scenario, use a context manager.

All suggestions lifted from (a SO that informed me in the past):
http://stackoverflow.com/questions/6104535/i-dont-understand-this-python-del-behaviour


On Mon, Feb 24, 2014 at 6:24 PM, Alex Martelli <aleax at google.com> wrote:

> 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
>>
>
>
> _______________________________________________
> 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/c8eef07d/attachment.html>


More information about the Python-list mailing list