Path: csiph.com!v102.xanadu-bbs.net!xanadu-bbs.net!eternal-september.org!feeder.eternal-september.org!border1.nntp.ams1.giganews.com!nntp.giganews.com!newsfeed.xs4all.nl!newsfeed2a.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; 'modify': 0.04; 'subject:Python': 0.05; 'override': 0.07; 'behave': 0.09; 'enum': 0.09; 'subclass': 0.09; 'cc:addr:python-list': 0.10; 'python': 0.11; 'itself.': 0.11; '*always*': 0.16; '__new__': 0.16; 'cc:name:python list': 0.16; 'length:': 0.16; 'metaclass': 0.16; 'metaclasses': 0.16; 'py3': 0.16; 'skip:@ 20': 0.16; 'third,': 0.16; 'two,': 0.16; 'wrote:': 0.16; "wouldn't": 0.16; 'implementing': 0.18; 'result,': 0.18; '>': 0.18; '(in': 0.18; 'solution.': 0.18; 'changes': 0.20; 'email addr:gmail.com>': 0.20; 'cc:2**0': 0.21; 'cc:addr:python.org': 0.21; 'class,': 0.22; 'decorator': 0.22; 'suppose': 0.22; 'code,': 0.23; '2015': 0.23; 'module': 0.23; '(like': 0.23; "i've": 0.24; 'header:In-Reply- To:1': 0.24; 'previously': 0.24; 'second': 0.24; 'equivalent': 0.27; '(e.g.,': 0.27; 'cool': 0.27; 'message-id:@mail.gmail.com': 0.28; 'parent': 0.29; '~ethan~': 0.29; 'function': 0.30; 'allows': 0.30; '(i.e.,': 0.31; 'fri,': 0.31; 'certain': 0.31; "can't": 0.32; 'especially': 0.32; 'skip:[ 10': 0.32; 'creating': 0.32; 'implement': 0.32; 'operate': 0.32; 'class': 0.33; 'third': 0.33; 'decorators': 0.33; 'instances': 0.33; 'wrap': 0.33; 'case,': 0.34; 'definition': 0.34; 'subject:?': 0.34; 'skip:& 20': 0.34; 'skip:& 10': 0.34; 'received:google.com': 0.34; 'behind': 0.35; 'could': 0.35; 'instance': 0.35; 'jason': 0.35; 'something': 0.35; 'but': 0.36; 'created': 0.36; 'cases': 0.36; 'subject:" ': 0.36; 'should': 0.37; "didn't": 0.37; 'subject:: ': 0.37; 'correctly': 0.37; 'desired': 0.37; 'best,': 0.38; 'pm,': 0.39; 'whatever': 0.39; 'does': 0.39; 'skip:t 20': 0.40; 'some': 0.40; 'behavior': 0.61; 'necessarily': 0.61; 'more': 0.62; '8bit%:10': 0.64; '8bit%:40': 0.66; 'inherit': 0.66; 'rare': 0.66; 'fact,': 0.67; "class's": 0.84; 'ethan': 0.91; 'dirty': 0.93 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:to :cc:content-type; bh=Bj9jJ2l/wRRHerLzET0vxjJ6xUhVAnyb1JV457CvKaY=; b=rf2SykwaZJl35bqnsGUfvMbDPeeZWC0ZH5MWrGvBdYVp1KgYOPmwfsM2gh5FAljaeF NyNKafZdpq49IBf45B4Bl2VQ6aay76w0omWunAdrIx+iZ44kH2tyvU/2R2HOWarqZZim 76uYUD1+OcMMI/VbFkVcIEFXVyMWddQS+MVYJf4Fs3arugrsbpXoEyGo2XqZErkGZ1VR 88BjeJq/aEqX5OyBrVXHHtQfmlx60/x9YyHJRbFzx3PsrOoVoW2Q1jK33MQmSKuvrPoC 4BLR+jmQ4C3H436+oN1z/qjlFPnBaZ0RzVFl8vNUEjn9E1xns+P0Xw3RCQ8y7NgNjmEQ EpyA== MIME-Version: 1.0 X-Received: by 10.107.138.208 with SMTP id c77mr12820364ioj.24.1432934923390; Fri, 29 May 2015 14:28:43 -0700 (PDT) In-Reply-To: <656488c4-e706-4fea-ab45-3d1454e35a7f@googlegroups.com> References: <33b7ab62-8cc2-4a27-b229-64c94bce16b6@googlegroups.com> <656488c4-e706-4fea-ab45-3d1454e35a7f@googlegroups.com> Date: Fri, 29 May 2015 17:28:43 -0400 Subject: Re: What is considered an "advanced" topic in Python? From: Jason Swails To: sohcahtoa82@gmail.com Cc: python list Content-Type: multipart/alternative; boundary=001a113ed3d218565905173f291c X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.20+ 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: 163 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1432934931 news.xs4all.nl 2910 [2001:888:2000:d::a6]:44241 X-Complaints-To: abuse@xs4all.nl Xref: csiph.com comp.lang.python:91503 --001a113ed3d218565905173f291c Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable On Fri, May 29, 2015 at 5:06 PM, wrote: > > > For example, the new (in 3.4) Enum class uses a metaclass. > > > > class SomeEnum(Enum): > > first =3D 1 > > second =3D 2 > > third =3D 3 > > > > The metaclass changes normal class behavior to: > > > > - support iterating: list(SomeEnum) --> [SomeEnum.first, > SomeEnum.second, SomeEnum.third] > > - support a length: len(SomeEnum) --> 3 > > - not allow new instances to be created: --> SomeEnum(1) is > SomeEnum(1) # True > > > > -- > > ~Ethan~ > > Regarding the first two, you can implement __iter__ and __len__ functions > to create that functionality, though those functions would operate on an > instance of the class, not the class itself. > > As for the third, can't you override the __new__ function to make attempt= s > to create a new instance just return a previously created instance? > =E2=80=8BOf course, but with metaclasses you don't *have* to (in fact, that= 's the type of thing that the metaclass could do behind the scenes). =E2=80=8BIn this case, any Enum subclass should *always* behave as Ethan de= scribed -- without metaclasses that wouldn't necessarily be true (e.g., if the person creating an Enum subclass didn't bother to correctly implement __new__, __iter__, and __len__ for their subclass). By using metaclasses, you can declare an Enum subclass as simply as Ethan showed, since the metaclass does all of the dirty work implementing the desired behavior at the time the class object is constructed (subclasses inherit their parent class's metaclass). In this use-case, you can think of it as a kind of "implicit class factory". Suppose you have a prescription for how you modify a class definition (i.e., by implementing certain behavior in __new__ or __init__) that you wrap up into some function "tweak_my_class". The metaclass would allow the class definition to be the equivalent of something like: class MyClass(SubClass): # whatever MyClass =3D tweak_my_class(MyClass) Or as a class decorator @tweak_my_class class MyClass(SubClass): # whatever (In fact, the `six` module allows you to implement metaclasses as decorators to work with both Python 2 and Python 3, but I think metaclasses are more powerful in Py3 than they are in Py2).=E2=80=8B =E2=80=8B They are cool ideas, and I've used them in my own code, but they do have a kind of magic-ness to them -- especially in codes that you didn't write but are working on. As a result, I've recently started to prefer alternatives, but in some rare cases (like Enum, for example), they are just the best solution. All the best, Jason --001a113ed3d218565905173f291c Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable

<= /div>

On Fri, May = 29, 2015 at 5:06 PM, <sohcahtoa82@gmail.com> wrote:
=

> For example, the new (in 3.4) Enum class uses a metaclass.
>
>=C2=A0 =C2=A0 class SomeEnum(Enum):
>=C2=A0 =C2=A0 =C2=A0 =C2=A0first =3D 1
>=C2=A0 =C2=A0 =C2=A0 =C2=A0second =3D 2
>=C2=A0 =C2=A0 =C2=A0 =C2=A0third =3D 3
>
> The metaclass changes normal class behavior to:
>
>=C2=A0 =C2=A0 - support iterating: list(SomeEnum) --> [SomeEnum.firs= t, SomeEnum.second, SomeEnum.third]
>=C2=A0 =C2=A0 - support a length:=C2=A0 len(SomeEnum) --> 3
>=C2=A0 =C2=A0 - not allow new instances to be created:=C2=A0 --> Som= eEnum(1) is SomeEnum(1)=C2=A0 # True
>
> --
> ~Ethan~

Regarding the first two, you can implement __iter__ and __len__ func= tions to create that functionality, though those functions would operate on= an instance of the class, not the class itself.

As for the third, can't you override the __new__ function to make attem= pts to create a new instance just return a previously created instance?
=

=E2=80=8BOf course, but with metaclasses you d= on't *have* to (in fact, that's the type of thing that the metaclas= s could do behind the scenes).

=E2=80=8BIn this case, any En= um subclass should *always* behave as Ethan described -- without metaclasse= s that wouldn't necessarily be true (e.g., if the person creating an En= um subclass didn't bother to correctly implement __new__, __iter__, and= __len__ for their subclass).

By using metaclasses, you can declare an Enum subclass as simply as = Ethan showed, since the metaclass does all of the dirty work implementing t= he desired behavior at the time the class object is constructed (subclasses= inherit their parent class's metaclass).

In this use-case, you can think of it as a kind of &= quot;implicit class factory".=C2=A0 Suppose you have a prescription fo= r how you modify a class definition (i.e., by implementing certain behavior= in __new__ or __init__) that you wrap up into some function "tweak_my= _class".=C2=A0 The metaclass would allow the class definition to be th= e equivalent of something like:

class MyClass(SubClass):
=C2=A0 =C2=A0 # whatever

MyClass =3D tweak_my_class(MyClass)

Or as a class decorator

@tweak_my_class
class MyClass(SubClass):
=C2=A0 =C2=A0 # whatever=

(In fact, the `six` mo= dule allows you to implement metaclasses as decorators to work with both Py= thon 2 and Python 3, but I think metaclasses are more powerful in Py3 than = they are in Py2).=E2=80=8B
=E2=80=8B
They are cool ideas, and I've used them in my own= code, but they do have a kind of magic-ness to them -- especially in codes= that you didn't write but are working on.=C2=A0 As a result, I've = recently started to prefer alternatives, but in some rare cases (like Enum,= for example), they are just the best solution.

All the best,
Jason
--001a113ed3d218565905173f291c--