最近刚接触python的元类,网络上有比较详细的介绍,这里是在看Django时候发现一点关于元类的应用,做个笔记。
from django.utils import six
class A(type):
def __new__(cls, name, parents, attrs):
return type.__new__(cls, name, parents, attrs)
class C(six.with_metaclass(A)):
pass
创建C类的时候,他会先调用metaclass属性里面的东西。上面C类中的代码可以是
class C(object):
__metaclass__ = A
def with_metaclass(meta, *bases):
"""Create a base class with a metaclass."""
# This requires a bit of explanation: the basic idea is to make a dummy
# metaclass for one level of class instantiation that replaces itself with
# the actual metaclass.
class metaclass(meta):
def __new__(cls, name, this_bases, d):
return meta(name, bases, d)
return type.__new__(metaclass, 'temporary_class', (), {})
如果我们需要做一些小动作,可以在这里下手。
那么现在就在A类继承一个B类,在加上几个新的变量。
from django.utils import six
class A(type):
def __new__(cls, name, parents, attrs):
attrs['name'] = 'sora'
attrs['sex'] = 'man'
name = 'Hello'
parents = (B,)
return type.__new__(cls, name, parents, attrs)
class B(object):
a = 123456
class C(six.with_metaclass(A)):
pass
c = C()
print dir(c)
print c.name
print c.__class__
print c.a
输出结果:
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'name', 'sex']
sora
<class '__main__.Hello'>
123456
parents是父类,attrs是一个字典,注意的是,attrs不能写成{‘name’:’sora’,’sex’:’,man’}这样是不对的.name是创建的类名字.
这里就是一些简单的一些应用了,在Django里面,经常要用到class Meta这个东西,Django相关的tastypie里面也有,比如Resource类,看了一下源代码学习了下.
from django.utils import six
class B(object):
opt_1 = 1
opt_2 = 2
opt_3 = 3
def __new__(cls, meta=None):
overrides = {}
if meta:
for override_name in dir(meta):
if not override_name.startswith('_'):
overrides[override_name] = getattr(meta,override_name)
return object.__new__(type(b'B',(cls,),overrides))
class A(type):
def __new__(cls, name, bases, attrs):
new_class = super(A,cls).__new__(cls,name,bases,attrs)
# new_class = type.__new__(cls, name, bases, attrs)
ops = getattr(new_class,'Meta',None)
new_class._opt = B(ops)
return new_class
class C(six.with_metaclass(A)):
def show_opt(self):
opt = self._opt
print 'opt_1:',opt.opt_1
print 'opt_2:',opt.opt_2
print 'opt_3:',opt.opt_3
class D(C):
class Meta:
opt_1 = 5
d = D()
d.show_opt()
输出结果:
opt_1: 5
opt_2: 2
opt_3: 3
def with_metaclass(meta, *bases):
# This requires a bit of explanation: the basic idea is to make a
# dummy metaclass for one level of class instantiation that replaces
# itself with the actual metaclass. Because of internal type checks
# we also need to make sure that we downgrade the custom metaclass
# for one level to something closer to type (that's why __call__ and
# __init__ comes back from type etc.).
#
# This has the advantage over six.with_metaclass in that it does not
# introduce dummy classes into the final MRO.
class metaclass(meta):
__call__ = type.__call__
__init__ = type.__init__
def __new__(cls, name, this_bases, d):
if this_bases is None:
return type.__new__(cls, name, (), d)
return meta(name, bases, d)
return metaclass('temporary_class', None, {})