Path: csiph.com!usenet.pasdenom.info!gegeweb.org!de-l.enfer-du-nord.net!feeder1.enfer-du-nord.net!feeds.phibee-telecom.net!newsfeed.xs4all.nl!newsfeed2.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; 'yet.': 0.04; 'explicitly': 0.05; 'class,': 0.07; 'variables': 0.07; 'decorator': 0.09; 'messing': 0.09; 'pep': 0.09; 'received:80.91': 0.09; 'received:80.91.229': 0.09; 'received:gmane.org': 0.09; 'received:list': 0.09; 'subject:using': 0.09; 'variant': 0.09; 'python': 0.11; 'def': 0.12; '(1,': 0.16; '3):': 0.16; 'cls': 0.16; 'definition.': 0.16; 'eckhardt': 0.16; 'instantiated': 0.16; 'limiting': 0.16; 'metaclass': 0.16; 'metaclasses': 0.16; 'metaclasses.': 0.16; 'namespace,': 0.16; 'once.': 0.16; 'received:80.91.229.3': 0.16; 'received:plane.gmane.org': 0.16; 'tool.': 0.16; 'attach': 0.16; 'language': 0.16; 'wrote:': 0.18; 'looked': 0.18; 'variable': 0.18; 'bit': 0.19; 'seems': 0.21; '>>>': 0.22; 'header:User-Agent:1': 0.23; 'decorators': 0.24; "haven't": 0.24; 'question': 0.24; 'developers': 0.25; 'class.': 0.26; 'define': 0.26; 'first,': 0.26; 'order.': 0.26; 'second': 0.26; 'pass': 0.26; 'least': 0.26; 'defined': 0.27; 'header:X -Complaints-To:1': 0.27; 'header:In-Reply-To:1': 0.27; 'function': 0.29; 'appreciated.': 0.29; 'am,': 0.29; 'skip:@ 10': 0.30; 'code': 0.31; 'usually': 0.31; 'steven': 0.31; 'class': 0.32; 'probably': 0.32; 'handled': 0.32; 'guess': 0.33; 'there,': 0.34; 'subject:with': 0.35; "can't": 0.35; 'something': 0.35; 'definition': 0.35; 'objects': 0.35; 'but': 0.35; 'there': 0.35; 'really': 0.36; 'options:': 0.36; 'thanks': 0.36; "i'll": 0.36; 'two': 0.37; 'e.g.': 0.38; 'to:addr:python-list': 0.38; 'does': 0.39; 'to:addr:python.org': 0.39; 'skip:p 20': 0.39; 'received:org': 0.40; 'upgrading': 0.60; 'mentioned': 0.61; 'received:173': 0.61; 'simply': 0.61; 'such': 0.63; 'provide': 0.64; 'more': 0.64; 'surrounding': 0.68; 'inline': 0.74; 'guaranteed': 0.75; '(loop': 0.84; 'received:fios.verizon.net': 0.84 X-Injected-Via-Gmane: http://gmane.org/ To: python-list@python.org From: Terry Jan Reedy Subject: Re: name lookup failure using metaclasses with unittests Date: Fri, 12 Apr 2013 10:58:01 -0400 References: <5166720e$0$29977$c3e8da3$5496439d@news.astraweb.com> Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Gmane-NNTP-Posting-Host: pool-173-75-251-66.phlapa.fios.verizon.net User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:17.0) Gecko/20130328 Thunderbird/17.0.5 In-Reply-To: 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: 90 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1365778697 news.xs4all.nl 2590 [2001:888:2000:d::a6]:59484 X-Complaints-To: abuse@xs4all.nl Xref: csiph.com comp.lang.python:43461 On 4/12/2013 3:17 AM, Ulrich Eckhardt wrote: > Am 11.04.2013 10:19, schrieb Steven D'Aprano: >> if sys.version >= '3': > > Use sys.version_info >= (3,), otherwise your code breaks when upgrading > to Python 10 and greater. ;^) > > >>> The second question that came up was if there is a way to keep a >>> metaclass defined inside the class or if the only way is to provide it >>> externally. [...] >> >> Not in general, since the metaclass has to exist independently of the >> class. > > Thanks for your explanations, they are appreciated. > > > > The class is an instance of your metaclass. That means that the > > metaclass must exist first, so it can be instantiated when you > > define the class. > > I don't like the approach to define the code to post-process a class > before defining the class. It's a bit like top-posting, it messes up the > reading order. Since I really intend to post-process the class, it seems > that metaclasses are simply not the right tool. Using a post-processing object as a metaclass or decorator necessarily requires predefinition. Such objects are usually used more than once. For one-off postprocessing, I probably would not bother. > At the moment, this leaves me with two options: > > 1. post-process the class > > class X: > pass > # attach constants to clas X > for i in (1, 2, 3): > setattr(X, 'f{}' % i, i) > > 2. generate code inline > > class Y: pass > # generate constants in local (class-)namespace > for i in (1, 2, 3): > locals()['f{}' % i] = i Mutating class locals() currently works in CPython, but is explicitly not guaranteed to work by the language definition. > In both cases, variables (loop variable 'i') are leaked into the > surrounding namespace, which is kind-of ugly. The second approach also > seems a bit hackish and I can't use the class-in-definition there, which > is limiting when you want to attach e.g. constants of type X to X. > > >>> Also PEP 3115 "Metaclasses in Python 3000"[2] seems to >>> consider postprocessing of a class definition as better handled by a >>> class decorator, which is something I haven't looked at yet. >> >> Generally, class decorators are less brain-melting than metaclasses. > > Alas, they also need to be defined before the class, messing with the > mentioned order of declaration. They can be used to call a class > function though which then does the necessary postprocessing... > > 3. post-process the class triggered with decorator > > def postprocess_class(cls): > """invoke postprocess() on the decorated object""" > cls.postprocess() > del cls.postprocess > return cls > > @postprocess_class > class Z: > @classfunction > def postprocess(cls): > # attach constants to class > for i in (1, 2, 3): > setattr(cls, 'f{}' % i, i) > > > I guess I'll stay with variant 1 for now, since it requires the least > amount of code and the least amount of questions from other developers > here.