Python元类(Metaclasses)

“元类的魔幻变化比 99% 的用户所担心的更多,当你搞不懂是否真的需要用它的时候,就是不需要。”—Tim ">Peters

本文源于在 PyCon UK 2008 上的一个快速演讲。

元类被称为 Python 中的“深奥的巫术”。尽管你需要用到它的地方极少(除非你基于 zope编程),可事实上它的基础理论其实令人惊讶地易懂。

一切皆对象

◆ 一切皆对象

◆ 一切都有类型

◆ “class”和“type”之间本质上并无不同

◆ 类也是对象

◆ 它们的类型是 type

以前,术语 type 用于内置类型,而术语 class 用于用户定义的类,但自 Pythoon 2.2 以来“class”和“type”本质上并无不同。

对于旧风格(old-style)类的类型是 types.ClassType。

真的,这是真的

Python 2.5.1 (r251:54869, Apr 18 2007, 22:08:04)  >>> class Something(object):  …     pass …  >>> Something  <class ‘__main__.Something’>  >>> type(Something)  <type ‘type’>

从这里可以看出在交互式解释器中创建的类是一个 first class 的对象。

类的类是……

它的元类……

就像对象是类的实例一样,类是它的元类的实例。

调用元类可以创建类。

确切来说,Python 中的其它对象也是如此。

因此当你创建一个类时……

解释器会调用元类来生成它……

定义一个继承自 object 的普通类意味着调用 type 来创建它:

>>> help(type)   Help on class type in module __builtin__:       class type(object)    |  type(object) -> the object’s type    |  type(name, bases, dict) -> a new type 

type 的第二种用法尤为重要。当 Python 解释器在执行一条类定义语句时(如例子中最初的两行代码之后),它会用下面的参数调用 type:

◆ 字符串形式的类名

◆ 元组形式的基类序列——在我们的例子中是只有一个元素的元组(’one-pl’)[1],如(object,)。

◆ 包括由名字影射的类成员(类属性、方法等)的字典

简单模拟

>>> def __init__(self):  …     self.message = ‘Hello World’ …  >>> def say_hello(self):  …     print self.message  …  >>> attrs = {‘__init__': __init__, ‘say_hello': say_hello}  >>> bases = (object,)  >>> Hello = type(‘Hello’, bases, attrs)  >>> Hello  <class ‘__main__.Hello’>  >>> h = Hello()  >>> h.say_hello()  Hello World 

以上代码创建了类属性的字典,然后调用 type 来创建了名为 Hello 的类。

__metaclass__ 的魔法

只要在类定义中把 __metaclass__ 设置为任意有着与 type 相同参数的可调用对象,就能够提供自定义的元类。

通常使用从 type 继承的方法:

class PointlessMetaclass(type):      def __new__(meta, name, bases, attrs):          # do stuff…          return type.__new__(meta, name, bases, attrs) 

重要的是在 __new__ 方法中我们能够读取或改变传入的用以创建新类的参数。从而能够内省属性字典和改动、增加或者删除成员。

尽管当实例化一个类时这两个函数都会被调用,但覆盖 __new__ 比 __init__ 更为重要。__init__ 初始化一个实例,而 __new__ 的职责是创建它。因此如果元类用以自定义类的创建,就需要覆盖 type 的 __new__。

使用新类而非仅仅提供工厂函数的原因在于如果使用工厂函数(那样只是调用 type)的话元类不会被继承。

In Action…

>>> class WhizzBang(object):  …     __metaclass__ = PointlessMetaclass  …  >>> WhizzBang  <class ‘__main__.WhizzBang’>  >>> type(WhizzBang)  <class ‘__main__.PointlessMetaClass’>

WhizzBang 是一个类,但它现在已经不是 type 的实例,而是我们自定义的元类的实例了……

这有什么用?

很好的问题,元类将用在创建使用了它的新类时调用,这里是一些关于这样做的好处的观点:

◆ 装饰(Decorate)类的所有方法,用以日志记录或者性能剖分。

◆ 自动 Mix-in 新方法

◆ 在创建时注册类。(例如自动注册插件或从类成员创建数据库模式。)

◆ 提供接口注册,功能自动发现和接口适配。

◆ 类校验:防止子类化,校验所有的方法是否都有 docstrings。

最重要之处在于元类中是在最后对 type 的调用时才真正创建类,所以可以自由地随你喜欢地改变属性字典(以及名称和元组形式的基类序列)。

一些流行的 Python ORM(Object Relational Mappers(对象关系影射),用以和数据库协同工作)也如此使用元类。

哦,还有因为元类是继承的,所以你能够提供一个使用了你的元类的基类,而继承自它的子类就无需显式声明它了。

但是……

我曾未需要使用它来编写代码……(我们用它来剖分,也在 Ironclad 项目广泛应用它,但我不编写这些)。

还有,这一切只适用于 Python 2.x,其中的机制在 Python 3 中已经改变了。

type(type) is type

在 Python 2.6 中现在也可用使用 class decorators 来实现许多以前可能需要用元类来实现的东西。

最后,还有一个极尽奇技淫巧的例子(稍为深入,但仍然不难消化),可以去看看 The Selfless Metaclass。它通过字节码和方法签名重写来避免显式地声明 self。

时间: 2024-10-27 18:29:28

Python元类(Metaclasses)的相关文章

对象-关于python元类遇到的问题(TypeError: metaclass conflict)?

问题描述 关于python元类遇到的问题(TypeError: metaclass conflict)? from abc import ABCMeta class test1(object):metaclass = ABCMeta def test1(self): print 'test1' class UpperAttrMetaclass(type): def new(cls, name, bases, dct={}): a = super(UpperAttrMetaclass, cls).

Python 元类使用说明_python

我要一大群的类都具有一中特点,我怎么给他们加上呢?模板模板吗,我从这个模板创建一群类不就OK了?那就需要元类了.霍霍> 定义一个元类(就所一个类的模板!莫多想,还要记住这是类级别的,不是对象级别的!): 复制代码 代码如下: class MyMeta(type): def __init__(cls,name,bases,dic): print cls.__name__ print name def __str__(cls):return 'Beautiful class %s'%cls.__na

在Python中使用元类的教程

  这篇文章主要介绍了在Python中使用元类的教程,是Python当中的基础知识,代码基于Python2.x版本,需要的朋友可以参考下 type() 动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的. 比方说我们要定义一个Hello的class,就写一个hello.py模块: ? 1 2 3 class Hello(object): def hello(self, name='world'): print('Hello, %s.' % name) 当Py

Python类和元类(metaclass)的理解和简单运用

(一) python中的类 今天看到一篇好文,然后结合自己的情况总结一波. 这里讨论的python类,都基于python2.7x以及继承于object的新式类进行讨论. 首先在python中,所有东西都是对象.这句话非常重要要理解元类我要重新来理解一下python中的类. class Trick(object):      pass  当python在执行带class语句的时候,会初始化一个类对象放在内存里面.例如这里会初始化一个Trick对象. 这个对象(类)自身拥有创建对象(通常我们说的实例

python中元类用法实例_python

本文实例讲述了python中元类用法,分享给大家供大家参考.具体方法分析如下: 1.元类(metaclass)是用来创建类的类 2.type(object):返回一个对象的类型,与object.__class__的值相同,type(name,bases,dict):创建一个新的type类型,name就是新class的name,值存到__name__属性中,bases是tuple类型,值会存到__bases__中,dict的值存到__dict__中 复制代码 代码如下: class X: ... 

Python中的元类编程入门指引_python

回顾面向对象编程 让我们先用 30 秒钟来回顾一下 OOP 到底是什么.在面向对象编程语言中,可以定义 类,它们的用途是将相关的数据和行为捆绑在一起.这些类可以继承其 父类的部分或全部性质,但也可以定义自己的属性(数据)或方法(行为).在定义类的过程结束时,类通常充当用来创建 实例(有时也简单地称为 对象)的模板.同一个类的不同实例通常有不同的数据,但"外表"都是一样 - 例如, Employee 对象 bob 和 jane 都有 .salary 和 .room_number ,但两者

深入理解Python中的元类(metaclass)_python

译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得不太明白,希望大家可以给出一些实际的例子和代码片段以帮助理解,以及在什么情况下需要进行元编程.于是e-satis同学给出了神一般的回复,该回复获得了985点的赞同点数,更有人评论说这段回复应该加入到Python的官方文档中去.而e-satis同学本人在Stack Overflow中的声望积分也高达6

Python栈类实例分析

 本文实例讲述了python栈类.分享给大家供大家参考.具体如下: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Path: #a list used like a stack def __init__(self): self.P = [] def push(self,t): self.P.append(t) def pop(self): return self.P.pop() def top(self): return self.P[-1] def r

python实现类的静态变量用法

  这篇文章主要介绍了python实现类的静态变量用法,实例分析了Python中基于数组实现静态队列的相关使用技巧,需要的朋友可以参考下 这里使用静态变量目的是在类中实现一个静态的队列,这里用数组实现,任何时候插入到队列中的数据不会和类的实例有直接关系. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 __author__ = 'Administrator' class CaptchaImage: def queue(self,arr=list()): return arr de