Python总是让我们能够看到它的内部是如何实现的,其中meta class 就是一个很好的例子。首先我们从class谈起。
1. class is also one object
>>> class ObjectCreator(object):
... pass
>>> my_object = ObjectCreator()
>>> print(my_object)
<__main__.ObjectCreator object at 0x8974f2c>
This object (the class) is itself capable of creating objects (the instances), and this is why it's a class. But still, it's an object, and therefore:
- you can assign it to a variable
- you can copy it
- you can add attributes to it
- you can pass it as a function parameter
>>> print(ObjectCreator) # you can print a class because it's an object
<class '__main__.ObjectCreator'>
>>> def echo(o):
... print(o)
...
>>> echo(ObjectCreator) # you can pass a class as a parameter
<class '__main__.ObjectCreator'>
>>> print(hasattr(ObjectCreator, 'new_attribute'))
False
>>> ObjectCreator.new_attribute = 'foo' # you can add attributes to a class
>>> print(hasattr(ObjectCreator, 'new_attribute'))
True
>>> print(ObjectCreator.new_attribute)
foo
>>> ObjectCreatorMirror = ObjectCreator # you can assign a class to a variable
>>> print(ObjectCreatorMirror.new_attribute)
foo
>>> print(ObjectCreatorMirror())
<__main__.ObjectCreator object at 0x8997b4c>
>>> def choose_class(name):
... if name == 'foo':
... class Foo(object):
... pass
... return Foo # return the class, not an instance
... else:
... class Bar(object):
... pass
... return Bar
...
>>> MyClass = choose_class('foo')
>>> print(MyClass) # the function returns a class, not an instance
<class '__main__.Foo'>
>>> print(MyClass()) # you can create an object from this class
<__main__.Foo object at 0x89c6d4c>
acctually, you can create class manually. by using the function 'type'. type works this way:
type(name of the class,
tuple of the parent class (for inheritance, can be empty),
dictionary containing attributes names and values)
e.g.:
>>> class MyShinyClass(object):
... pass
Can be translate to:
>>> MyShinyClass = type('MyShinyClass', (), {}) # returns a class object
>>> print(MyShinyClass)
<class '__main__.MyShinyClass'>
>>> print(MyShinyClass()) # create an instance with the class
<__main__.MyShinyClass object at 0x8997cec>
>>> class FooChild(Foo):
... pass
can be created manually this way:
>>> FooChild = type('FooChild', (Foo,), {})
>>> print(FooChild)
<class '__main__.FooChild'>
>>> print(FooChild.bar) # bar is inherited from Foo
True
3. '__class__' attribute
Everything, and I mean everything, is an object in Python. That includes ints, strings, functions and classes.
All of them are objects. And all of them have been created from a class:
>>> age = 35
>>> age.__class__
<type 'int'>
>>> name = 'bob'
>>> name.__class__
<type 'str'>
>>> def foo(): pass
>>> foo.__class__
<type 'function'>
>>> class Bar(object): pass
>>> b = Bar()
>>> b.__class__
<class '__main__.Bar'>
#Now, what is the __class__ of any __class__ ?
>>> age.__class__.__class__
<type 'type'>
>>> name.__class__.__class__
<type 'type'>
>>> foo.__class__.__class__
<type 'type'>
>>> b.__class__.__class__
<type 'type'>
#The default metaclass for a new style object is called 'type'.
4. What are metaclasses?? '__metaclass__' attribute
metaclass are the 'stuff' that creates classes.They are the classes' classes, you can picture them this way:
MyClass = MetaClass()
MyObject = MyClass()
So when the call to MyMeta is done above, what happens under the hood is this:
MyKlass = MyMeta.__new__(MyMeta, name, bases, dct)
MyMeta.__init__(MyKlass, name, bases, dct)
The __metaclass__ attribute. You can hook on __new__, __init__ and __call__ in the metaclass
class MyMeta(type):
def __new__(meta, name, bases, dct):
print '-----------------------------------'
print "Allocating memory for class", name
print meta
print bases
print dct
return super(MyMeta, meta).__new__(meta, name, bases, dct)
def __init__(cls, name, bases, dct):
print '-----------------------------------'
print "Initializing class", name
print cls
print bases
print dct
super(MyMeta, cls).__init__(name, bases, dct)
class MyKlass(object):
__metaclass__ = MyMeta
def foo(self, param):
pass
barattr = 2
Another example.
class MyMeta(type):
def __call__(cls, *args, **kwds):
print '__call__ of ', str(cls)
print '__call__ *args=', str(args)
return type.__call__(cls, *args, **kwds)
class MyKlass(object):
__metaclass__ = MyMeta
def __init__(self, a, b):
print 'MyKlass object with a=%s, b=%s' % (a, b)
print 'gonna create foo now...'
foo = MyKlass(1, 2)
class MetaSingleton(type):
instance = None
def __call__(cls, *args, **kw):
if cls.instance is None:
cls.instance = super(MetaSingleton, cls).__call__(*args, **kw)
return cls.instance
class Foo(object):
__metaclass__ = MetaSingleton
a = Foo()
b = Foo()
assert a is b
5. When to use metaclass?
The most notable example of metaclasses in Python is probably their usage in ORM (Object Relational Mapping) frameworks, such as Django’s models.
It allows you to define something like this:
class Person(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField()
guy = Person(name='bob', age='35')
print(guy.age)
Ref:
http://eli.thegreenplace.net/2011/08/14/python-metaclasses-by-example/
http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python