>
> � � 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().

">

(original) (raw)


On 8 Sep 2013 18:38, "Ethan Furman" <ethan@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@python.org
\> https://mail.python.org/mailman/listinfo/python-dev
\> Unsubscribe: https://mail.python.org/mailman/options/python-dev/ncoghlan%40gmail.com