Python元类编程——with_metaclass

six.with_metaclass

最近刚接触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里面,经常要用到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

来自flask的增强版with_metaclass

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, {})

参考

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值