On 8 Sep 2013 18:38, "Ethan Furman" <email@example.com> 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):
> 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):
> 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 :)
> Python-Dev mailing list
> Unsubscribe: https://mail.python.org/mailman/options/python-dev/ncoghlan%40gmail.com