[Python-Dev] metaclasses, classes, instances, and proper nomenclature

Nick Coghlan ncoghlan at gmail.com
Sun Sep 8 12:06:17 CEST 2013


On 8 Sep 2013 18:38, "Ethan Furman" <ethan at stoneleaf.us> wrote:
>
> I've run across two different ways to think about this:
>
>   1) the type of the first argument
>
>   2) where the method/attribute lives
>
> Since attributes don't take a first argument they default to 2:  an
instance attribute lives in the instance, a class attribute lives in the
class, and a metaclass attribute lives in the metaclass.
>
> Methods, on the other hand, do take a first argument:  an instance method
takes itself, a class method takes the class, and a metaclass method takes
the metaclass.

No, there's no such thing as a "metaclass method".

Metaclass instance methods are equivalent to hidden class methods - they
don't appear in dir() and can't be accessed through instances of the class.

It's only class methods on the metaclass that receive that rather than the
class object (__new__ is technically a static method, but still accepts the
metaclass as the first argument).

> Going by option 1 above there is only one way to get an instance method,
and only one way to get a metaclass method -- calling with the instance
(either directly or indirectly via the class), or calling a metaclass
method that has been marked as a @classmethod.
>
> Therein lies my confusion.
>
> class Meta(type):
>
>     @classmethod
>     def meta_method(mcls):
>         print("I'm a metaclass method!")
>
>     def cls_method1(cls):
>         print("I'm a class method!  Aren't I?")
>
> class Class(metaclass=Meta):
>
>     @classmethod
>     def cls_method2(cls):
>         print("I'm a class method for sure!")
>
>     def instance_method(self):
>         print("And I'm a regular ol' instance method")
>
>
> So, is Meta.cls_method1 a class method?  On the one hand, it takes the
class as it's first parameter, on the other hand it lives in the metaclass.
 And on the third hand you can't get to it from the instance Class().

It's a hidden class method.

> If you're wondering why this is posted to PyDev, the related question is
this:  What is the proper role of a metaclass?  Should it basically fiddle
with the class creation process and then get out of the way?  The case in
point is, of course, Enum.  Currently it has a custom __getattr__, but it
lives in the metaclass, EnumMeta.  Now this is handy, because it means that
Color.red.blue raises an AttributeError, where if __getattr__ lived in Enum
itself that would work.  It also has the __members__ attribute living in
EnumMeta, which means it's not accessible from Color.red.  In other words,
EnumMeta is not getting out the way, it is still very much involved.  On
the one hand, that's cool; on the other hand, I hand to think hard to
figure out why Color.red.blue was not getting routed through EnumMeta's
__getattr__, but was instead getting routed through object.__getattr__.

This is exactly how a metaclass is intended to be used - to affect the
behaviour of the class without affecting the behaviour of instances.

And yes, introspection does get a little interesting when a non-trivial
metaclass is in play :)

Cheers,
Nick.

>
> --
> ~Ethan~
> _______________________________________________
> Python-Dev mailing list
> Python-Dev at python.org
> https://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe:
https://mail.python.org/mailman/options/python-dev/ncoghlan%40gmail.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20130908/ee9f1ed2/attachment.html>


More information about the Python-Dev mailing list