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

Ethan Furman ethan at stoneleaf.us
Sun Sep 8 09:42:20 CEST 2013


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.

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


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__.

--
~Ethan~


More information about the Python-Dev mailing list