<div dir="ltr"><div class="gmail_default" style="font-family:'courier new',monospace"><div class="gmail_default">This question was initially asked in <a href="mailto:tutor@python.org">tutor@python.org</a>; Now I am widening the audience to gain attention.</div>
<div class="gmail_default"><br></div><div class="gmail_default">I want to create a decorator which should do the following things:</div><div class="gmail_default"> => 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. </div>
<div class="gmail_default"> => When an object of the decorated class is deleted, the record with this deleted objects name (i.e. <a href="http://object.id">object.id</a>) should be removed from the table. </div><div class="gmail_default">
<br></div><div class="gmail_default">Now, for example - consider the following snippet:</div><div class="gmail_default"><br></div><div class="gmail_default">@saveme</div><div class="gmail_default">class A(object):</div><div class="gmail_default">
    def __init__(self, id):</div><div class="gmail_default">        <a href="http://self.id">self.id</a> = id</div><div class="gmail_default"><br></div><div class="gmail_default">@saveme</div><div class="gmail_default">class B(object):</div>
<div class="gmail_default">    def __init__(self, id):</div><div class="gmail_default">        <a href="http://self.id">self.id</a> = id</div><div class="gmail_default"><br></div><div class="gmail_default">"saveme" should do what I have explained earlier.</div>
<div class="gmail_default"><br></div><div class="gmail_default">a1 = A("A1")</div><div class="gmail_default">a2 = A("A2")</div><div class="gmail_default">a3 = A("A3")</div><div class="gmail_default">
b1 = B("B1")</div><div class="gmail_default">b2 = B("B2")</div><div class="gmail_default"><br></div><div class="gmail_default">At this point if I query and print all the records in a table, I should get the following output: </div>
<div class="gmail_default">["A1", "A2", "A3", "B1", "B2"]</div><div class="gmail_default"><br></div><div class="gmail_default">del a1</div><div class="gmail_default">del a2</div>
<div class="gmail_default">del a3</div><div class="gmail_default">del b1</div><div class="gmail_default">del b2</div><div class="gmail_default"><br></div><div class="gmail_default">At this point, all entries in the table should be deleted; query should return an empty list!</div>
<div class="gmail_default"><br></div><div class="gmail_default">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]!</div>
<div class="gmail_default"><br></div><div class="gmail_default">Now the following is what I have tried:</div><div class="gmail_default"><br></div><div class="gmail_default">class saveme(object):</div><div class="gmail_default">
    def __init__(self, klass):</div><div class="gmail_default">        print "saveme::__init__()"</div><div class="gmail_default">        self._klass = klass</div><div class="gmail_default"><br></div><div class="gmail_default">
    def __call__(self, *args, **kwargs):</div><div class="gmail_default">        print "saveme::__call__()"</div><div class="gmail_default">        obj = self._klass(*args, **kwargs)</div><div class="gmail_default">
        # creation of DB record will happen here!</div><div class="gmail_default">        # i.e. something like add_to_db(kwargs.get("id"))</div><div class="gmail_default">        return obj</div><div class="gmail_default">
<br></div><div class="gmail_default">    def __del__(self):</div><div class="gmail_default">        # deletion of DB record will happen here!</div><div class="gmail_default">        # i.e. something like remove_from_db(id)</div>
<div class="gmail_default">        # TODO: how to retrieve the "id" here?!</div><div class="gmail_default">        print "saveme::__del__()"</div><div class="gmail_default"><br></div><div class="gmail_default">
<br></div><div class="gmail_default">class Parent1(object):</div><div class="gmail_default">    def __init__(self):</div><div class="gmail_default">        print "Parent1:: __init__()"</div><div class="gmail_default">
        super(Parent1, self).__init__()</div><div class="gmail_default"><br></div><div class="gmail_default"><br></div><div class="gmail_default">class Parent2(object):</div><div class="gmail_default">    def __init__(self):</div>
<div class="gmail_default">        print "Parent2:: __init__()"</div><div class="gmail_default">        super(Parent2, self).__init__()</div><div class="gmail_default"><br></div><div class="gmail_default"><br></div>
<div class="gmail_default">@saveme</div><div class="gmail_default">class A(Parent1, Parent2):</div><div class="gmail_default">    def __init__(self, id):</div><div class="gmail_default">        print "A::__init__()"</div>
<div class="gmail_default">        <a href="http://self.id">self.id</a> = id</div><div class="gmail_default">        #super(A, self).__init__()</div><div class="gmail_default"><br></div><div class="gmail_default"><br></div>
<div class="gmail_default">#@saveme</div><div class="gmail_default">#class B(object):</div><div class="gmail_default">#    def __init__(self, id):</div><div class="gmail_default">#        print "B::__init__()"</div>
<div class="gmail_default">#        <a href="http://self.id">self.id</a> = id</div><div class="gmail_default"><br></div><div class="gmail_default"><br></div><div class="gmail_default">def main():</div><div class="gmail_default">
    a1 = A(id="A1")</div><div class="gmail_default">#    b1 = B(id="B1")</div><div class="gmail_default"><br></div><div class="gmail_default">if __name__ == "__main__":</div><div class="gmail_default">
    main()</div><div class="gmail_default"><br></div><div class="gmail_default"><br></div><div class="gmail_default">When executed the above, I ran in to the following:</div><div class="gmail_default"><br></div><div class="gmail_default">
saveme::__init__()</div><div class="gmail_default">saveme::__call__()</div><div class="gmail_default">A::__init__()</div><div class="gmail_default">Traceback (most recent call last):</div><div class="gmail_default">  File "1.py", line 54, in <module></div>
<div class="gmail_default">    main()</div><div class="gmail_default">  File "1.py", line 50, in main</div><div class="gmail_default">    a1 = A(id="A1")</div><div class="gmail_default">  File "1.py", line 10, in __call__</div>
<div class="gmail_default">    obj = self._klass(*args, **kwargs)</div><div class="gmail_default">  File "1.py", line 39, in __init__</div><div class="gmail_default">    super(A, self).__init__()</div><div class="gmail_default">
TypeError: must be type, not saveme</div><div class="gmail_default">saveme::__del__()</div><div class="gmail_default"><br></div><div class="gmail_default"><div class="gmail_default" style="font-size:13px"><br></div><div class="gmail_default" style="font-size:13px">
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! </div>
<div class="gmail_default" style="font-size:13px"><br></div><div class="gmail_default" style="font-size:13px">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.</div>
<div class="gmail_default" style="font-size:13px"><br></div><div class="gmail_default" style="font-size:13px">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()? </div>
<div class="gmail_default" style="font-size:13px"><br></div><div class="gmail_default" style="font-size:13px">Or, is there any other better way to capture the __call__ and __del__  events for an object of a certain class - if so, how?!</div>
<div><br></div></div><div class="gmail_default">Thank you,</div><div class="gmail_default"><br></div><div class="gmail_default">Sangeeth</div><div class="gmail_default"><br></div><div class="gmail_default"><br></div><div class="gmail_default">
PS: <a href="http://stackoverflow.com/questions/21826854/typeerror-when-using-super-method-with-class-decorator-for-a-derived-class">http://stackoverflow.com/questions/21826854/typeerror-when-using-super-method-with-class-decorator-for-a-derived-class</a></div>
<div class="gmail_default"><br></div></div></div>