I just wrote a fully commented metaclass example. This is in Python 2.7. I am sharing this and I hope that it will help you better understand the __new__ , __init__ , __call__ , __dict__ and the concept of limited / unlimited in Python, as well as the use of metaclasses.
The problem with the metaclass, I feel, is that it has too many places where you can do the same things or similar, but with some slight differences . Therefore, my comments and test cases mainly emphasize where to write what, what goes to where at certain points, and what is available for a particular object.
The example tries to build a factory class while maintaining the correct class definitions.
from pprint import pprint from types import DictType class FactoryMeta(type): """ Factory Metaclass """
The result is as follows (for a better demonstration):
================================================================ Metaclass __new__ (creates class objects) ---------------------------------------------------------------- Bounded to object: <class '__main__.FactoryMeta'> Bounded object __dict__: { ..., 'clsVar': <function clsVar at 0x00000000029BC828>, 'count': 1, 'extra': 'default extra', 'metaVar': <classmethod object at 0x00000000029B4B28>, 'var': "Change made to <class '__main__.FactoryMeta'> by metaclass' __new__"} ---------------------------------------------------------------- Parameter 'name': Factory Parameter 'bases': (<type 'object'>,) Parameter 'dict': { ..., 'classFactory': <classmethod object at 0x00000000029B4DC8>, 'extra': 'overridng extra', 'new_elem': 'effective', 'selfVar': <function selfVar at 0x00000000029BC6D8>} ================================================================ Metaclass __init__ (initiates class objects) ---------------------------------------------------------------- Bounded to object: <class '__main__.Factory'> Bounded object __dict__: { ..., 'classFactory': <classmethod object at 0x00000000029B4DC8>, 'extra': 'overridng extra', 'new_elem': 'effective', 'selfVar': <function selfVar at 0x00000000029BC6D8>, 'var': "Change made to <class '__main__.Factory'> by metaclass' __init__"} ---------------------------------------------------------------- Parameter 'name': Factory Parameter 'bases': (<type 'object'>,) Parameter 'dict': { ..., 'classFactory': <classmethod object at 0x00000000029B4DC8>, 'extra': 'overridng extra', 'init_elem': 'defective', 'new_elem': 'effective', 'selfVar': <function selfVar at 0x00000000029BC6D8>}
The calling sequence is the metaclass' __new__ , then its __init__ . __call__ will not be called at this time.
And if we create an instance,
func1 = ( "def printElems(self):\n" " print \"Member new_elem: \" + self.new_elem\n" " print \"Member init_elem: \" + self.init_elem\n" ) factory = Factory(func1)
Output:
================================================================ Metaclass __call__ (initiates instance objects) ---------------------------------------------------------------- Bounded to object: <class '__main__.Factory'> Bounded object __dict__: { ..., 'classFactory': <classmethod object at 0x00000000029B4DC8>, 'extra': 'overridng extra', 'metaVar': <bound method type.metaVar of <class '__main__.FactoryMeta'>>, 'new_elem': 'effective', 'selfVar': <function selfVar at 0x00000000029BC6D8>, 'var': "Change made to <class '__main__.Factory'> by metaclass' __call__"} ================================================================ Class' __new__ ("creates" instance objects) ---------------------------------------------------------------- Bounded to object: <class '__main__.Factory'> Bounded object __dict__: { ..., 'classFactory': <classmethod object at 0x00000000029B4DC8>, 'extra': 'def printElems(self):\n print "Member new_elem: " + self.new_elem\n print "Member init_elem: " + self.init_elem\n', 'metaVar': <bound method type.metaVar of <class '__main__.FactoryMeta'>>, 'new_elem': 'effective', 'selfVar': <function selfVar at 0x00000000029BC6D8>, 'var': "Change made to <class '__main__.Factory'> by metaclass' __call__"} ---------------------------------------------------------------- Parameter 'function': def printElems(self): print "Member new_elem: " + self.new_elem print "Member init_elem: " + self.init_elem ================================================================ Class' __init__ (initiates instance objects) ---------------------------------------------------------------- Bounded to object: <__main__.Factory object at 0x00000000029BB7B8> Bounded object __dict__: {'classFactory': <bound method FactoryMeta.classFactory of <class '__main__.Factory'>>} ---------------------------------------------------------------- Parameter 'function': def printElems(self): print "Member new_elem: " + self.new_elem print "Member init_elem: " + self.init_elem
The metaclass ' __call__ first called, then class' __new__ and __init__ .
By comparing the printed elements of each object, you can find out when and where they were added or changed, just as I commented on the code.
I also run the following test cases:
factory.clsVar() # Will raise exception Factory.clsVar() factory.metaVar() factory.selfVar() func2 = ( "@classmethod\n" "def printClassID(cls):\n" " print \"Class ID: %02d\" % cls.class_id\n" ) ProductClass1 = factory.classFactory("ProductClass", (object, ), { 'another_func': func2 }) product = ProductClass1() product.printClassID() product.printElems() # Will raise exception ProductClass2 = Factory.classFactory("ProductClass", (Factory, ), { 'another_func': "pass" }) ProductClass2.printClassID() # Will raise exception ProductClass3 = ProductClass2.classFactory("ProductClass", (object, ), { 'another_func': func2 })
What you can run yourself to see how it works.
Please note that I intentionally left the names of dynamically generated classes different from the names of the variables to which they were assigned. This means which names actually act.
One more note: I put βstaticβ in quotation marks, which I call a concept similar to C ++, not a Python decorator. Traditionally, I am a C ++ programmer, so I still like to think in my own way.