| Python 中的 元类(metaclass) 是一个深度魔法,平时我们可能比较少接触到元类,本文将通过一些简单的例子来理解这个魔法。 类也是对象在 Python 中,一切皆对象。字符串,列表,字典,函数是对象, 类也是一个对象,因此你可以: 
 看一个简单的例子: 
class Foo(object):
    foo = True
class Bar(object):
    bar = True
def echo(cls):
    print cls
def select(name):
    if name == 'foo':
        return Foo        # 返回值是一个类
    if name == 'bar':
        return Bar
>>> echo(Foo)             # 把类作为参数传递给函数 echo
<class '__main__.Foo'>
>>> cls = select('foo')   # 函数 select 的返回值是一个类,把它赋给变量 cls
>>> cls
__main__.Foo熟悉又陌生的 type在日常使用中,我们经常使用 object 来派生一个类,事实上,在这种情况下,Python 解释器会调用 type 来创建类。 这里,出现了 type ,没错,是你知道的 type ,我们经常使用它来判断一个对象的类型,比如: 
class Foo(object):
    Foo = True
>>> type(10)
<type 'int'>
>>> type('hello')
<type 'str'>
>>> type(Foo())
<class '__main__.Foo'>
>>> type(Foo)
<type 'type'>事实上, type 除了可以返回对象的类型,它还可以被用来动态地创建类(对象) 。下面,我们看几个例子,来消化一下这句话。 使用 type 来创建类(对象)的方式如下: type(类名, 父类的元组(针对继承的情况,可以为空),包含属性和方法的字典(名称和值)) 最简单的情况假设有下面的类: 
class Foo(object):
    pass现在,我们不使用 class 关键字来定义,而使用 type ,如下: 
Foo = type('Foo', (object, ), {})    # 使用 type 创建了一个类对象上面两种方式是等价的。我们看到, type 接收三个参数: 
 在上面,我们使用 type() 创建了一个名为 Foo 的类,然后把它赋给了变量 Foo,我们当然可以把它赋给其他变量,但是,此刻没必要给自己找麻烦。 接着,我们看看使用: >>> print Foo <class '__main__.Foo'> >>> print Foo() <__main__.Foo object at 0x10c34f250> 有属性和方法的情况假设有下面的类: 
class Foo(object):
    foo = True
    def greet(self):
        print 'hello world'
        print self.foo用 type 来创建这个类,如下: 
def greet(self):
    print 'hello world'
    print self.foo
Foo = type('Foo', (object, ), {'foo': True, 'greet': greet})上面两种方式的效果是一样的,看下使用: >>> f = Foo() >>> f.foo True >>> f.greet <bound method Foo.greet of <__main__.Foo object at 0x10c34f890>> >>> f.greet() hello world True 继承的情况再来看看继承的情况,假设有如下的父类: 
class Base(object):
    pass我们用 Base 派生一个 Foo 类,如下: class Foo(Base): foo = True 改用 type 来创建,如下: 
Foo = type('Foo', (Base, ), {'foo': True})什么是元类(metaclass)元类(metaclass)是用来创建类(对象)的可调用对象。这里的可调用对象可以是函数或者类等。但一般情况下,我们使用类作为元类。对于实例对象、类和元类,我们可以用下面的图来描述: 类是实例对象的模板,元类是类的模板 +----------+ +----------+ +----------+ | | | | | | | | instance of | | instance of | | | instance +------------>+ class +------------>+ metaclass| | | | | | | | | | | | | +----------+ +----------+ +----------+ 我们在前面使用了 type 来创建类(对象),事实上, type 就是一个元类 。 那么,元类到底有什么用呢?要你何用... 元类的主要目的是为了控制类的创建行为。我们还是先来看看一些例子,以消化这句话。 元类的使用先从一个简单的例子开始,假设有下面的类: 
class Foo(object):
    name = 'foo'
    def bar(self):
        print 'bar'现在我们想给这个类的方法和属性名称前面加上 my_ 前缀,即 name 变成 my_name,bar 变成 my_bar,另外,我们还想加一个 echo 方法。当然,有很多种做法,这里展示用元类的做法。 1.首先,定义一个元类,按照默认习惯,类名以 Metaclass 结尾,代码如下: 
class PrefixMetaclass(type):
    def __new__(cls, name, bases, attrs):
        # 给所有属性和方法前面加上前缀 my_
        _attrs = (('my_' + name, value) for name, value in attrs.items())  
        
        _attrs = dict((name, value) for name, value in _attrs)  # 转化为字典
        _attrs['echo'] = lambda self, phrase: phrase  # 增加了一个 echo 方法
        
        return type.__new__(cls, name, bases, _attrs)  # 返回创建后的类上面的代码有几个需要注意的点: 
 2.接着,我们需要指示 Foo 使用 PrefixMetaclass 来定制类。 在 Python2 中,我们只需在 Foo 中加一个 __metaclass__ 的属性,如下: 
class Foo(object):
    __metaclass__ = PrefixMetaclass
    name = 'foo'
    def bar(self):
        print 'bar'在 Python3 中,这样做: 
class Foo(metaclass=PrefixMetaclass):
    name = 'foo'
    def bar(self):
        print 'bar'现在,让我们看看使用: 
>>> f = Foo()
>>> f.name    # name 属性已经被改变
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-774-4511c8475833> in <module>()
----> 1 f.name
AttributeError: 'Foo' object has no attribute 'name'
>>>
>>> f.my_name
'foo'
>>> f.my_bar()
bar
>>> f.echo('hello')
'hello'可以看到,Foo 原来的属性 name 已经变成了 my_name,而方法 bar 也变成了 my_bar,这就是元类的魔法。 再来看一个继承的例子,下面是完整的代码: 
class PrefixMetaclass(type):
    def __new__(cls, name, bases, attrs):
        # 给所有属性和方法前面加上前缀 my_
        _attrs = (('my_' + name, value) for name, value in attrs.items())  
        
        _attrs = dict((name, value) for name, value in _attrs)  # 转化为字典
        _attrs['echo'] = lambda self, phrase: phrase  # 增加了一个 echo 方法
        
        return type.__new__(cls, name, bases, _attrs)
class Foo(object):
    __metaclass__ = PrefixMetaclass   # 注意跟 Python3 的写法有所区别
    name = 'foo'
    def bar(self):
        print 'bar'
class Bar(Foo):
    prop = 'bar'其中,PrefixMetaclass 和 Foo 跟前面的定义是一样的,只是新增了 Bar,它继承自 Foo。先让我们看看使用: 
>>> b = Bar()
>>> b.prop     # 发现没这个属性
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-778-825e0b6563ea> in <module>()
----> 1 b.prop
AttributeError: 'Bar' object has no attribute 'prop'
>>> b.my_prop
'bar'
>>> b.my_name
'foo'
>>> b.my_bar()
bar
>>> b.echo('hello')
'hello'我们发现,Bar 没有 prop 这个属性,但是有 my_prop 这个属性,这是为什么呢? 原来,当我们定义 class Bar(Foo) 时,Python 会首先在当前类,即 Bar 中寻找 __metaclass__ ,如果没有找到,就会在父类 Foo 中寻找 __metaclass__ ,如果找不到,就继续在 Foo 的父类寻找,如此继续下去,如果在任何父类都找不到 __metaclass__ ,就会到模块层次中寻找,如果还是找不到,就会用 type 来创建这个类。 这里,我们在 Foo 找到了 __metaclass__ ,Python 会使用 PrefixMetaclass 来创建 Bar,也就是说,元类会隐式地继承到子类,虽然没有显示地在子类使用 __metaclass__ ,这也解释了为什么 Bar 的 prop 属性被动态修改成了 my_prop。 写到这里,不知道你理解元类了没?希望理解了,如果没理解,就多看几遍吧~ 小结
 | 



 英文卖包包衣服商城|ecs
							人气:5353
							英文卖包包衣服商城|ecs
							人气:5353
						 ecshop大气综合商城模板2
							人气:810
							ecshop大气综合商城模板2
							人气:810
						 凡客成品ecshop模板二钻石
							人气:758
							凡客成品ecshop模板二钻石
							人气:758
						 ecshop内衣服装综合模板
							人气:1237
							ecshop内衣服装综合模板
							人气:1237
						 shopex茶叶网模板
							人气:1347
							shopex茶叶网模板
							人气:1347
						 shopex西街时尚模板
							人气:2155
							shopex西街时尚模板
							人气:2155