Path: csiph.com!v102.xanadu-bbs.net!xanadu-bbs.net!feeder.erje.net!eu.feeder.erje.net!newsfeed.xs4all.nl!newsfeed3a.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.001 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'example:': 0.03; 'resulting': 0.04; 'yet.': 0.04; 'class,': 0.07; '*args,': 0.09; '__init__': 0.09; 'function,': 0.09; 'wrapped': 0.09; 'wrapper': 0.09; 'cc:addr:python-list': 0.11; 'python': 0.11; 'def': 0.12; '*args):': 0.16; 'callable,': 0.16; 'code?': 0.16; 'constructs': 0.16; 'from:addr:rosuav': 0.16; 'from:name:chris angelico': 0.16; 'invokes': 0.16; 'retains': 0.16; 'simplest': 0.16; 'tracing': 0.16; 'wraps': 0.16; 'wrote:': 0.18; 'cc:addr:python.org': 0.22; 'decorators': 0.24; 'passes': 0.24; 'cc:2**0': 0.24; 'class.': 0.26; 'this:': 0.26; 'gets': 0.27; 'header:In-Reply-To:1': 0.27; 'function': 0.29; 'am,': 0.29; "doesn't": 0.30; 'message- id:@mail.gmail.com': 0.30; 'invoke': 0.31; 'piece': 0.31; 'class': 0.32; 'becomes': 0.33; 'skip:_ 10': 0.34; 'basic': 0.35; 'something': 0.35; 'but': 0.35; 'received:google.com': 0.35; 'object,': 0.36; 'doing': 0.36; 'method': 0.36; 'so,': 0.37; 'two': 0.37; 'whatever': 0.38; 'does': 0.39; 'itself': 0.39; 'even': 0.60; 'new': 0.61; 'first': 0.61; "you'll": 0.62; 'taking': 0.65; 'anything.': 0.68; 'jul': 0.74; 'special': 0.74; '4:29': 0.84; 'wrapper,': 0.84; 'facilities.': 0.91; 'thing,': 0.91; 'to:none': 0.92 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:cc :content-type; bh=UOUZQSAPN17sktD6KKKxLK/GFoRpQV2mDUf/A4cz8Vo=; b=WeNwUVYYyEDmUM012tO6aSZSnjoXK1FXCeFukyNBOctoGGJdsaIyi0ous2XQc02fuT YsBzBA3/OSpCn4YkMiZZufVChNzPlfHAGcplppR6BY9PXvQr7vAUkEDIp/QRAmritvor j+j6AZwcOPR/wApgmKjpNQa9pO0Qoytc4YA3T3Zfy8xG8x2OvAjNOd7s4NPObyLPPw1v bgpKrwdoYpVKrundFylu9Ua8+4FauwUXtforp37Hw2MrdessIkxtvILpMxWOOKdAJocJ zcg/IZtV4rC0bhZt4mBIXFITNh1jG6ZfAMaKI/xBHsj3+8FD88v6hihL/bbtq1bCt6S3 ofEQ== MIME-Version: 1.0 X-Received: by 10.220.81.194 with SMTP id y2mr2796275vck.29.1406400019510; Sat, 26 Jul 2014 11:40:19 -0700 (PDT) In-Reply-To: <23517efd-6d71-4182-9f18-7aaae3b95afb@googlegroups.com> References: <23517efd-6d71-4182-9f18-7aaae3b95afb@googlegroups.com> Date: Sun, 27 Jul 2014 04:40:19 +1000 Subject: Re: Return class. From: Chris Angelico Cc: "python-list@python.org" Content-Type: text/plain; charset=UTF-8 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: 57 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1406400496 news.xs4all.nl 2943 [2001:888:2000:d::a6]:56055 X-Complaints-To: abuse@xs4all.nl Xref: csiph.com comp.lang.python:75253 On Sun, Jul 27, 2014 at 4:29 AM, Satish ML wrote: > What does "return Wrapper" do in the following piece of code? Which method does it invoke? > I mean "return Wrapper" invokes __init__ method? > > def Tracer(aClass): > class Wrapper: > def __init__(self, *args, **kargs): > self.fetches = 0 > self.wrapped = aClass(*args, **kargs) > def __getattr__(self, attrname): > print('Trace: ' + attrname) > self.fetches += 1 > print(self.fetches) > return getattr(self.wrapped, attrname) > return Wrapper > It doesn't invoke anything. It returns the class itself - a callable, subclassable thing, which wraps the passed-in class. When it's used as a decorator, what happens is that first the basic class gets constructed, then it gets passed to this function, and whatever this function returns becomes the resulting class. So, taking the simplest example: @Tracer class Spam: def __init__(self, *args): print(*args) def display(self): print('Spam!' * 8) This is like doing this: class Spam: def __init__(self, *args): print(*args) def display(self): print('Spam!' * 8) Spam = Tracer(Spam) And then Tracer begins executing, with the Spam class as "aClass". It constructs a new class with two methods: an __init__ which passes everything through to the wrapped class and retains the resulting object, and a __getattr__ which proxies through to the original with tracing facilities. But all it does is construct and return that class. It doesn't call anything, yet. Calling the class (instantiating an object of it) happens when the Spam("CARST") call happens; instead of calling the original Spam class, it calls the special wrapper, which then calls on the original. You can look up class decorators in the Python docs; they're not something you'll use often (and they're something you'll write even less often), but they can give you a lot of flexibility. ChrisA