CaptainChen

Python中的元类

2017-01-23 965 words (about 5 min read) Views
Python

本文摘自我的笔记Python2笔记—类

1. 继承与实例化

在面向对象体系里面,存在两种关系:

  • 继承关系:在python里面用__base__可查看,顶层是object
  • 实例关系:表现为某个类型的实例化。在python里面用__class__查看,顶层为type
>>> object.__base__  # 继承关系上object为顶层
None
>>> object.__class__  # object是type的实例
<type 'type'>

>>> type.__base__  # type继承自obect
<type 'object'>
>>> type.__class__  # type是type的实例
<type 'type'>

# python中type和object就像鸡和蛋的关系

>>> int.__base__  # int继承自object
<type 'object'>
>>> int.__class__  # int是type的实例
<type 'type'>

再看一个实例化的例子:

>>> class A(object):
... 	pass 
>>> a = A()
>>> a.__class__  # a是A的实例
<class '__main__.A'>
>>> a.__base__  # 报错。实例没有继承关系,所以没有__base__属性
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute '__base__'

2. type的用法

  • type(obj):获取对象的相应类型,与obj.__class__等同
  • type(className, (parents), {attr: value}):创建并返回一个类,三个参数分别对应与类名(字符串),父类(元组形式),属性(字典形式)

因此以下两个语句等价:

class Integer(object):
    name = 'interger'
    def inc(self, num):
        return num + 1
#------------------------
# 父类元组为空,默认继承object
Integer = type('Integer', (), {'name': 'interger',
                                   'increase': lambda self, num: num + 1})

也就是说,类的定义过程,其实是type类型实例化的过程

3. 元类metaclass

先总结下:

  • 类的类就是元类(强调实例化),默认是type

  • type是所有元类的父亲

  • 在实例化时,也就是创建类型对象时,会按以下顺序查找__metaclass__属性:

class.__metaclass__ -> bases.__metaclass__ -> module.__metaclass__ -> type

理解以上几点,看下面例子:

>>> class M(type):
... 	pass
>>> M.__class__
<type 'type'>
>>> M.__base__  # 继承自type
<type 'type'>

上面的M就是一个元类。要实例化,可定义一个类:

>>> class TM(object):
... 	__metaclass__ = M  # 指定元类
>>> TM.__class__
<class '__main__.M'>
>>> TM.__base__
<type 'object'>

其实上面的__metaclass__ = M是一个语法糖,它等价于TM = M('TM', (), {})

4. 元类的作用

元类的作用:控制类的创建过程。

例子: 让定义的类的所有方法和属性名称前面都加上my_前缀:

class PrefixMetaclass(type):
    def __new__(cls, className, bases, attrs):
        _attrs = dict(('my_' + name, value) for name, value in attrs.items())
        return type.__new__(cls, className, bases, _attrs)
        # return type(className, bases, _attrs)
        # return super(PrefixMetaclass, cls).__new__(cls, className, bases, _attrs)


class Foo(object):
    __metaclass__ = PrefixMetaclass  # 这样Foo就是PrefixMetaclass的实例了
    name = 'foo'

    def bar(self):
        return 'bar'


foo = Foo()
print foo.name    # AttributeError: 'Foo' object has no attribute 'name'
print foo.my_name # foo
print foo.bar()   # AttributeError: 'Foo' object has no attribute 'bar'
print foo.my_bar()# bar

参数解释:

  • cls:指向当前类PrefixMetaclass
  • className: 后面要创建的类名字
  • bases: 要创建的类的父类
  • attrs: 要创建的类的属性和方法,为一个字典

最后三个return语句本质上是相同的。

5. 应用

例1:创建一个静态类(static class): 不允许创建实例,通常作为工具类(Utility)存在:

class StaticMetaclass(type):
    def __new__(cls, name, base, attr):
        ret = type.__new__(cls, name, base, attr)  # 创建类实例

        def ctor(cls, *args, **kwargs):
            raise RuntimeError("Cannot create a instance of the static class!")

        ret.__new__ = staticmethod(ctor)  # 无法实例化

        return ret

class Data(object):
    __metaclass__ = StaticMetaclass

Data()  # RuntimeError: Cannot create a instance of the static class!

例2: 创建一个密封类(sealed class):禁止被继承

class SealedMetaclass(type):
    _types = set()
    
    def __init__(cls, name, base, attr):
        if cls._types & set(base):  # 其实是只能继承自object,创建的类_types非空,再创建子类会报错
            raise SyntaxError("Cannot inherit form a sealed class!")
        cls._types.add(cls)

class A(object):
    __metaclass__ = SealedMetaclass

class B(A):
    pass
# SyntaxError: Cannot inherit form a sealed class!

参考资料:

Pyton之旅

使用元类 - 廖雪峰的官方网站

Python:元类metaclass

Python Types and Objects

如果你这里看到有广告,不妨点击一下,就是对本站最大的支持~



本文由 CaptainChen 创作
该文章采用 知识共享署名-非商业性使用 4.0 国际许可协议进行许可。转载请注明出处!
CopyRight © 2017 - 2020
本站已稳定运行 天 总访问量