Path: csiph.com!v102.xanadu-bbs.net!xanadu-bbs.net!news.mixmin.net!feeds.phibee-telecom.net!newsfeed.xs4all.nl!newsfeed1a.news.xs4all.nl!xs4all!newsgate.cistron.nl!newsgate.news.xs4all.nl!post.news.xs4all.nl!not-for-mail Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.000 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'subject:: [': 0.04; 'argument': 0.05; 'baypiggies': 0.07; 'nested': 0.07; 'table.': 0.07; '"__main__":': 0.09; '*args,': 0.09; '__init__': 0.09; '__name__': 0.09; 'alter': 0.09; 'created,': 0.09; 'decorator': 0.09; 'derived': 0.09; 'executed': 0.09; 'function,': 0.09; 'main()': 0.09; 'method,': 0.09; 'obj': 0.09; 'todo:': 0.09; 'type,': 0.09; 'url:baypiggies': 0.09; 'cc:addr:python-list': 0.11; 'def': 0.12; 'stored': 0.12; '(say': 0.16; '**kwargs)': 0.16; '**kwargs):': 0.16; '24,': 0.16; '39,': 0.16; '54,': 0.16; '__del__': 0.16; 'a(object):': 0.16; 'argument)': 0.16; 'cc:addr:chennaipy': 0.16; 'class;': 0.16; 'commented': 0.16; 'deleted,': 0.16; 'deleted;': 0.16; 'deletion': 0.16; 'earlier.': 0.16; 'email name:baypiggies': 0.16; 'highlight': 0.16; 'initiation': 0.16; 'main():': 0.16; 'subject: \n ': 0.16; 'subject:Baypiggies': 0.16; 'tried:': 0.16; 'typeerror:': 0.16; 'wrote:': 0.18; 'alex': 0.19; 'replacing': 0.19; 'subject:] ': 0.20; 'seems': 0.21; '8bit%:5': 0.22; 'feb': 0.22; 'example': 0.22; 'email addr:gmail.com>': 0.22; 'cc:addr:python.org': 0.22; 'print': 0.22; 'error': 0.23; 'entries': 0.24; 'mon,': 0.24; 'question': 0.24; 'options': 0.25; 'query': 0.26; 'certain': 0.27; 'skip:" 20': 0.27; 'header:In-Reply-To:1': 0.27; 'record': 0.27; 'point': 0.28; 'function': 0.29; 'rest': 0.29; 'cc:2**2': 0.30; 'returned': 0.30; 'message-id:@mail.gmail.com': 0.30; 'url:mailman': 0.30; 'asked': 0.31; 'code': 0.31; '50,': 0.31; 'explained': 0.31; 'prints': 0.31; 'table,': 0.31; 'file': 0.32; 'class': 0.32; 'url:python': 0.33; '(i.e.': 0.33; '(most': 0.33; 'skip:# 10': 0.33; 'skip:& 30': 0.33; 'table': 0.34; 'skip:_ 10': 0.34; 'subject:the': 0.34; "i'd": 0.34; 'could': 0.34; 'classes': 0.35; 'something': 0.35; 'objects': 0.35; 'but': 0.35; 'received:google.com': 0.35; 'there': 0.35; '8bit%:9': 0.36; 'i.e.': 0.36; 'object,': 0.36; 'url:listinfo': 0.36; 'url:org': 0.36; 'should': 0.36; 'so,': 0.37; 'too': 0.37; 'list': 0.37; 'email addr:python.org': 0.37; 'being': 0.38; 'skip:& 10': 0.38; 'thank': 0.38; 'initially': 0.38; 'skip:[ 10': 0.38; 'pm,': 0.38; 'skip:_ 40': 0.38; 'recent': 0.39; 'skip:& 20': 0.39; 'mailing': 0.39; '8bit%:6': 0.40; 'url:mail': 0.40; 'how': 0.40; 'above,': 0.60; 'skip:a 30': 0.61; 'name': 0.63; 'happen': 0.63; 'to:addr:gmail.com': 0.65; 'attention.': 0.68; 'incoming': 0.72; 'records': 0.73; 'audience': 0.74; 'unsubscribe:': 0.77; 'gain': 0.79; 'here!': 0.84; 'url:self': 0.84; 'capture': 0.91; 'cc:no real name:2**2': 0.91; 'subject:Class': 0.91 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; bh=eARuh3cMtRY0cS2odT/k0FQSNxdHsYQahCQbvAd4fzc=; b=B2Grv4hRLYwrVLQE5r9kCY8iMEDUmmfimeQa3a6lFUlcupM5e7pXL2/QzT83/bDM8U 4krwjxUk1cTAVpp5jfIVi/hHNCL/fYWBtl3AeNj6Z0XfDpIJFql6lc0fD6XTkHaW3RdD AWmhuphl7pUjEOCWFahmY0C3UMiM9TS9QwRlu4wyjITavy/NsN+/1O4hbtDphRruts2B /VmseiIrudRNSRLDK+xdiklLlJoutxxuKoHXNJS8m99Gwe4FzQG+IF6UfwBU4xMJeLQK +h+q0WjfEZfRGCeCnCQVdyXBN1YFSwo1E0ljwL8bAt6NADiikgvEsvnXJme/4yCvAPsV 1/Dg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:date :message-id:subject:from:to:cc:content-type; bh=eARuh3cMtRY0cS2odT/k0FQSNxdHsYQahCQbvAd4fzc=; b=UTRqlkiIF3p/u5rxpSeH6yt00BS1uFWwHgBzj/u29GpZ1DdoDI2eXW+tZZBOWvLFEB tBhVJQxDgugCQnmknCazo/wywDZVhMy2+nC3iP1ZjnDGptNXTcoVhF3LKGaGnwIkiBHp AOmENfshJ8fPw5YmVGpZfsL7iaKh/WDi/SSHqBNtCVI/zI/PM0vqulwb1mVk6TWYapEd rzorGHTkpXt0ZyfH60R/QsCW0i/v01hFw9I5IxIyR1xhchhj8r5YlkQ4+BPGvXGzimXp c61tlFyDvhM/luXopuEEv5sHOT4aG2wYeH4CPRJ1F5BijeXDPdSU0W8JXZooubEszlSC 1c/w== X-Gm-Message-State: ALoCoQnPyHbYmILIvr8R2wJPs00OWKPO7UFtQrdSOp+NKzKAoXc+8DN3PmSf+PeWcuQOIHe5um1PWBflTVZwYtUUPtq5qGJCxoAgyrtB1Jdw7X9sPOEw1fw9lcaW7FBXOsEaD+gZGCF/79puwXnruFJosCvwqMzYl7eeVSK2lzUViZoU99rC3pjmB6saAAIT7p7JIZJQLyXNCOx+OtQVuwbVFJPxAc0oYA== MIME-Version: 1.0 X-Received: by 10.182.166.40 with SMTP id zd8mr20101939obb.25.1393295092176; Mon, 24 Feb 2014 18:24:52 -0800 (PST) In-Reply-To: References: Date: Mon, 24 Feb 2014 18:24:52 -0800 Subject: Re: [Baypiggies] Class decorator to capture the creation and deletion of objects From: Alex Martelli To: Sangeeth Saravanaraj Content-Type: multipart/alternative; boundary=e89a8ff1ce02097e0704f331cb25 Cc: python-list@python.org, BayPiggies , bangpypers@python.org, chennaipy@python.org X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Newsgroups: comp.lang.python Message-ID: Lines: 384 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1393295100 news.xs4all.nl 2870 [2001:888:2000:d::a6]:60350 X-Complaints-To: abuse@xs4all.nl Xref: csiph.com comp.lang.python:67014 --e89a8ff1ce02097e0704f331cb25 Content-Type: text/plain; charset=UTF-8 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@gmail.com> wrote: > This question was initially asked in tutor@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 > 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@python.org > To change your subscription options or unsubscribe: > https://mail.python.org/mailman/listinfo/baypiggies > --e89a8ff1ce02097e0704f331cb25 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable
Off the cuff, I'd make saveme into a function, not a c= lass; the=C2=A0saveme=C2=A0function would alter the class passed in as its = only argument (saving __init__ and/or __del__ methods it may have and repla= cing 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 sou= nder architecture.


Alex
<= br>


On Mon, Feb 24, 2014 at 4:49 PM, Sangeeth Saravanaraj <= ;sangee= th.saravanaraj@gmail.com> wrote:
This question was ini= tially asked in tutor= @python.org; Now I am widening the audience to gain attention.

I want = to create a decorator which should do the following things:
=C2=A0=3D> When an object of the decorated class is c= reated, the objects name (say the value of the incoming "id" argu= ment) should be stored as a record in a table in a database.=C2=A0
=C2=A0=3D> When an object of the decorated = class is deleted, the record with this deleted objects name (i.e. object.id) should be removed fr= om the table.=C2=A0

Now, for example - consider the foll= owing snippet:

@saveme
class A(object):
=C2=A0 =C2=A0 def __init__(self, id):
=C2= =A0 =C2=A0 =C2=A0 =C2=A0 self.= id =3D id

@saveme
class B(object):
=C2=A0 =C2=A0 def __init__(self, id):
=C2=A0 =C2=A0 =C2=A0 =C2=A0 self.id =3D id

"saveme" should do what I have explained earlier.

a1 =3D = A("A1")
a2 =3D A("A2"= )
a3 =3D A("A3")
b1 =3D B("B1")
b2 =3D B("B= 2")

At this point if I query and print all the records in a table, I sho= uld get the following output:=C2=A0
["A1", "A2", "A3"= ;, "B1", "B2"]

del a1
d= el a2
del a3
del b= 1
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 "save= me" can de derived classes too [which initialises its base classes usi= ng super() method]!

Now the= following is what I have tried:

class saveme(object):
=C2=A0 =C2=A0 def __init__(self, klass):
= =C2=A0 =C2=A0 =C2=A0 =C2=A0 print "saveme::__init__()"
=C2=A0 =C2=A0 =C2=A0 =C2=A0 self._klass =3D klass

=C2=A0 =C2=A0 def __call__(self, *args, **kwargs):
=C2=A0 =C2=A0 =C2=A0 =C2=A0 print "saveme::__call__()"<= /div>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 obj =3D self.= _klass(*args, **kwargs)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 # creation of DB record will happen here!
=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 # i.e. something l= ike add_to_db(kwargs.get("id"))
=C2=A0 =C2=A0 =C2=A0 =C2=A0 return obj

=C2=A0 =C2=A0 def __del__(self):
=C2=A0 =C2=A0 =C2=A0 =C2=A0 # deletion of DB= record will happen here!
=C2=A0 =C2=A0 = =C2=A0 =C2=A0 # i.e. something like remove_from_db(id)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 # TODO: how to ret= rieve the "id" here?!
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 print "saveme::__del__()"


class Parent1(object):
=C2=A0 =C2=A0 def __init__(self):
=C2=A0 =C2=A0 =C2=A0 =C2=A0 print "Parent1:: __init__()&= quot;
=C2=A0 =C2=A0 =C2=A0 =C2=A0 super(Parent1, self).__init__()


class Parent2(object):
=C2=A0 =C2=A0 def __init__(self):
=C2=A0 =C2=A0 =C2=A0 =C2=A0 print "Parent= 2:: __init__()"
=C2=A0 =C2=A0 =C2=A0= =C2=A0 super(Parent2, self).__init__()
<= br>

@saveme
clas= s A(Parent1, Parent2):
=C2=A0 =C2=A0 def = __init__(self, id):
=C2=A0 =C2=A0 =C2=A0 = =C2=A0 print "A::__init__()"
=C2=A0 =C2=A0 =C2=A0 =C2=A0 self.id =3D id
=C2=A0 =C2=A0 =C2=A0 =C2=A0 #super(A, self).__init__()


#@saveme
#cl= ass B(object):
# =C2=A0 =C2=A0def __init_= _(self, id):
# =C2=A0 =C2=A0 =C2=A0 =C2= =A0print "B::__init__()"
# =C2=A0 =C2=A0 =C2=A0 =C2=A0self.id =3D id


def main():
=C2=A0 =C2=A0 a1 =3D A(id=3D"A1")
# =C2=A0 =C2=A0b1 =3D B(id=3D"B1")

if __name__ =3D=3D "__ma= in__":
=C2=A0 =C2=A0 main()


When executed the= above, I ran in to the following:

saveme::__init__()
saveme::__call__()
A::__init__()
Traceback (most recent call last):
= =C2=A0 File "1.py", line 54, in <module>
=C2=A0 =C2=A0 main()
=C2=A0 File "1.py", line 50, in main
=C2=A0 =C2=A0 a1 =3D A(id=3D"A1")
=C2=A0 File "1.py", line 10, in __call__
=C2=A0 =C2=A0 obj =3D self._klass(*args, **kwa= rgs)
=C2=A0 File "1.py", line 3= 9, in __init__
=C2=A0 =C2=A0 super(A, sel= f).__init__()
TypeError: must be type, not saveme
savem= e::__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 th= e base classes (Parent1 & Parent2) were not called!=C2=A0

From the error message, what I = could understand is - the object returned by saveme::__call__() is not of t= ype 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 d= o I initialise the base classes using super()?=C2=A0

Or, is there any other better w= ay to capture the __call__ and __del__ =C2=A0events for an object of a cert= ain class - if so, how?!

Thank you,

Sangeeth


_______________________________________________
Baypiggies mailing list
Baypiggies@python.org
To change your subscription options or unsubscribe:
https://mail.python.org/mailman/listinfo/baypiggies

--e89a8ff1ce02097e0704f331cb25--