Python程序设计案例课堂
上QQ阅读APP看书,第一时间看更新

6.10 元类

所谓元类,就是一个用来当作创建其他类的模板(template)的类。一般来讲,用户使用类来创建类实例变量。使用元类的目的是以某些类为基准来创建metaclass类,然后将元类当作要创建的类的基类。

使用元类让用户有机会可以存取与改变Python的内部类。利用元类创建的元实例可以让操作对象属性的工作更容易。

下列程序代码定义一个简单的元类与其支持的类:

        1:   >>>import types
        2:   >>>class METACLASS:
        3:      def __init__(self, name, bases, namespace):
        4:          self.__name__ = name
        5:          self.__bases__ = bases
        6:          self.__namespace__ = namespace
        7:      def __call__(self):
        8:          return METAINSTANCE(self)
        9:
        10:  >>> class METAINSTANCE:
        11:     def __init__(self, metaclass):
        12:         self.__metaclass__ = metaclass
        13:     def __getattr__(self, name):
        14:         try:
        15:             value = self.__metaclass__.__namespace__[name]
        16:         except KeyError:
        17:             raise AttributeError.name
        18:         if type(value) is not types.FunctionType:
        19:             return value
        20:         return METHODWRAPPER(value, self)
        21:
        22:  >>> class METHODWRAPPER:
        23:     def __init__(self, function, metainstance):
        24:         self.function = function
        25:         self.instance = metainstance
        26:         self.__name__ = self.function.__name__
        27:     def __call__(self, *args):
        28:         return apply(self.function, (self.instance, ) + args)
        29:

上述代码的含义分析如下。

(1)第2行:定义一个元类,类名称为METACLASS。

(2)第3~6行:创建一个新的元类,此元类的构造方法需要3个参数。name参数是元实例的名称,bases参数是一个基类的元组,namespace参数是元实例命名空间的字典。

(3)第7~8行:当调用METACLASS时,运行METAINSTANCE.__init__()来返回一个元实例。

(4)第10行:定义一个元实例,类名称为METAINSTANCE。

(5)第13行:存取此用户定义实例变量的属性时,检查它是否属于用户类命名空间(第14~17行)。如果此属性是一个数值,则返回此数值;若此属性是一个函数,返回一个METHODWRAPPER类的实例。

(6)第22行:定义一个类,名称为METHODWRAPPER,用来处理存取用户类的方法属性。

下列程序代码创建一个元类的实例:

        >>> BASECLASS = METACLASS("BASECLASS", (), {})

下列程序代码以BASECLASS当作基类,来创建一个用户类:

        >>>class myClass(BASECLASS):
        def push(self, name):
                  self.name = [name]
              def pop(self):
                if len(self.name) > 0:
                    item = self.name[-1]
                    print (item)

下列案例使用用户类myClass来新增与删除name属性:

        1:  >>>x = myClass()
        2:  >>>x.push("Andre")
        3:  >>>x.name
        4:  ['Andre']
        5:  >>> x.pop()
        6:  Andre
        7:  >>> x.name
        8:  []

上述代码的含义分析如下

(1)第1行:创建一个用户定义类myClass的实例x。当创建x时,会运行METACLASS.__call__()函数。而METACLASS.__call__()函数又会调用METAINSTANCE.__getattr__()。

(2)第2行:新增一个name属性"Andre"。

(3)第3~4行:显示实例x的name属性。

(4)第5行:删除name属性列表的最后一个元素Andre。

(5)第7~8行:显示实例x的name属性。