Python 元类(MetaClass)

时间:2022-04-26
本文章向大家介绍Python 元类(MetaClass),主要内容包括Python 动态语言的动态特性、元类(MetaClass)、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

Python 动态语言的动态特性

Python是解释运行的动态语言,它与Java最大的不同是Java的类和方法是在编译时完成定义的,而对Python来说,类和函数在解释器进行解释时动态创建。

class Sample(object):
    def display(self):
    print('This is a sample of class')
#交互环境示例
>>> from test import Sample
>>> s = Sample()
>>> s
<test.Sample object at 0x00000125C335D6A0>
>>> print(type(Sample))
<class 'type'>   #Sample的类型是 class type???
>>> print(type(s))
<class 'test.Sample'>
>>>

type()函数可以查看一个对象的类型,在上例中,Sample是一个class,它的类型是type,而s是一个实例,而它的类型是test里的Sample。也就是说,class Sample是class type的实例。从这一点我们发现,不同于Java的类和实例对象的两层结构,Python还存在类的类(class of class),抽象程度要更高一层。 前面已经多次提到过,诸如Python的脚本语言中,一切都是对象,类也是对象。type()函数既可以查看一个类的类型,也是动态创建出一个类,而不必非得像Java那个通过类的定义来实现。

#type()动态创建类的一个实例
>>> def function(self):  #定义一个类 作为type()的参数
...     print('This is a function.')
...
>>> Example = type('Example', (object,), dict(show = function))
>>> e = Example()
>>> e
<__main__.Example object at 0x00000125C337CC18>
>>> print(type(Example))
<class 'type'>
>>> print(type(e))
<class '__main__.Example'>
>>>

你会发现,就创建结果的类型来说,使用type()创建出来的类与class Sample(object)一样都是type类型。事实上,Python在解释器类的定义代码时,会运行type()函数动态创建一个类。也就是说上面的例子就是Python中类的具体实现。 为什么type()函数有2个功能? 这叫做函数重载,是基本的面向对象概念,同名函数可以有不同的参数表,这些函数会有相同的名字,但其实并不是同一个函数,它们实现的功能也不同。 (这篇博客默认你已经有面向对象的知识了,如果没有,请停止阅读先去掌握面向对象的概念,不要打击自己的自信心。)

动态创建类是所调用的type()函数参数表 1. 要创建的类的名称 2. 要创建的类所继承的类的名称(tuple 类型) 3. 要创建的类包含的方法(dict类型, 并且要求value是函数对象)

以下叙述很少会用的到,也是Python中非常难懂的地方,你可以选择跳过,看懂下面的内容你需要有面向对象的整体概念基础。

元类(MetaClass)

MetaClass,直译过来就是元类,顾名思义,就是类的类,如果说class是object的模板,那么MetaClass就是class的模板(Java使用抽象类或者接口来做类的模板, Python则没有这些东西)。

这个特性是从同为脚本语言的Smalltalk那里借鉴来的。

In object-oriented programming, a metaclass is a class whose instances are classes. Just as an ordinary class defines the behavior of certain objects, a metaclass defines the behavior of certain classes and their instances. Not all object-oriented programming languages support metaclasses. Among those that do, the extent to which metaclasses can override any given aspect of class behavior varies. Metaclasses can be implemented by having classes be first-class citizen, in which case a metaclass is simply an object that constructs classes. Each language has its own metaobject protocol, a set of rules that govern how objects, classes, and metaclasses interact. https://en.wikipedia.org/wiki/Metaclass

元类的命名规则是 名字 + MetaClass

#说明 python中双下划线加名字再加双下划线的变量名是预先定义的特殊类型
#下面的__new__是一个类在被创建时调用的函数  其余的特殊变量参见Python官网

#MetaClass是类的模板 继承自type
class ListMetaclass(type):
    def __new__(cls, name, bases, attrs):
        attrs['add'] = lambda self, value: self.append(value)
        return type.__new__(cls, name, bases, attrs)
#使用元类来创建类
class MyList(list, metaclass=ListMetaclass):
    pass

l = MyList()
l.add(1)
l.add((1,2,3))
l.add([1, 2, 3, 4])
print(l)

#结果 
C:Usershongze>python test.py
[1, (1, 2, 3), [1, 2, 3, 4]]
#由于我们定义了ListMetaClass里的__new__函数, 因此MyList的实例在创建时,会调用其父类的__new__函数(面向对象继承基本知识)
#__new__在return时又会调用class type的__new__函数以最终实现创建

__new__接受4个参数用以创建对象(类也是对象,别忘了),分别是:

  1. cls 要创建的对象
  2. name 创建对象使用的类名
  3. bases 创建对象使用的类的基类
  4. attr 创建对象使用的类的属性(方法表) list类型

stackoverflow讨论: https://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python 第二个回答的翻译: http://blog.jobbole.com/21351/

“元类就是深度的魔法,99%的用户应该根本不必为此操心。如果你想搞清楚究竟是否需要用到元类,那么你就不需要它。那些实际用到元类的人都非常清楚地知道他们需要做什么,而且根本不需要解释为什么要用元类。” —— Python界的领袖 Tim Peters