1.什么是元类
元类让你来定义某些类是如何被创建的,从根本上说,赋予你如何创建类的控制权。可以把元类想成是一个类中类,或是一个类,它的实例是其它的类。当某个类调用type()函数时,你就会看到它到底是谁的实例。
>>> class C(object):
pass
>>> class CC:
pass
>>> type(C)
<type 'type'>
>>> type(CC)
<type 'classobj'>
>>> import types
>>> type(CC) is types.ClassType
True
2.什么时候使用元类
元类一般用于创建类。在执行类定义时,将检查此类正确的元类,元类通常传递三个参数:类名、从基类继承数据的元组和类的属性字典。
使用class语句定义新类时,解释器执行类的整个主体并填充字典。一旦字典填充完毕,就会被传递给元类构造函数,以创建相应的类对象。
在执行类定义时,解释器必须要知道这个类的正确的元类。
首先,类可以显式地指定其元类,这通过设置__metaclass__类变量来实现:
class Foo:
__metaclass__ = type
在Python3中,使用下面的语法(在基类元组中提供metaclass关键字参数):
class Foo(metaclass=type)
如果没有显式指定元类,class语句将检查基类元组(如果存在)中的第一个条目。在这种情况下,元类与第一个基类的类型相同。所以,在编写以下内容时,Foo的类类型将与object相同。
class Foo(object):pass
如果没有指定基类,class语句将检查全局变量__metaclass__是否存在。如果找到了该变量,将使用它来创建类。
__metaclass__ = type
class Foo:
pass
最后,如果没有找到任何__metaclass__值,Python将使用默认的元类。在Python2中,默认的元类是types.ClassType(旧样式类),在Python3中,默认的元类就是type()。
3.谁在使用元类
元类的最终使用者不是用户,正是程序员自己。你可以通过定义一个元类来“迫使”程序员按照某种方式实现目标类,这既可以简化他们的工作,也可以使所编写的程序更符合特定标准。
4.元类何时被创建
创建的元类用于改变类的默认行为和创建方式。创建一个新风格的类或传统类的做法是使用系统自己所提供的元类的默认方式。
自定义元类时,它通常会继承自type(),并重新实现__init__()或__new__()方法。
5.技巧
显式选择元类的最常用技巧是首先定义一个基类,该基类然后用作要被归档的所有对象的父类。例如:
class Documented:
__metaclass__ = DocMeta#Docmeta是已定义的基类
在Python3中,使用下面的语法(在基类元组中提供metaclass关键字参数):
class Documented(metaclass=DocMeta)
class Foo(Documented):
spam(self,a,b):
'spam does something'
pass
元类示例1:用元类创建类时,显示时间标签:
from time import ctime
print '***Welcome to Metaclasses!'
print '\tMetaclasses declaration first.'
class MetaC(type):
def __init__(cls,name,bases,attrd):
super(MetaC,cls).__init__(name,bases,attrd)
print '***Created class %r at: %s' % (name,ctime())
print '\tClass "Foo" declaration next.'
class Foo(object):
__metaclass__ = MetaC
def __init__(self):
print '***Instantiated class %r at: %s' %(self.__class__.__name__,ctime())
print '\tClass "Foo" instantiation next.'
f = Foo()
print '\tDONE'
执行后输出:
***Welcome to Metaclasses!
Metaclasses declaration first.
Class "Foo" declaration next.
***Created class 'Foo' at: Thu May 30 11:22:35 2013
Class "Foo" instantiation next.
***Instantiated class 'Foo' at: Thu May 30 11:22:35 2013
DONE
元类示例2:创建一个元类,要求程序员在他们写的类中提供一个__str__()方法的实现。如果你还没有在类中覆盖__repr__()方法,元类会给出警告,提示你这么做。如果未实现__str__()方法,将引发一个TypeError的异常。
from warnings import warn
class ReqStrSugRepr(type):
def __init__(cls,name,bases,attrd):
super(ReqStrSugRepr,cls).__init__(name,bases,attrd)
if '__str__' not in attrd:
raise TypeError('Class requires overriding of __str__()')
if '__repr__' not in attrd:
warn('Class suggests overriding of __repr__()\n',stacklevel = 3)
print '***Defined ReqStrSugRepr (meta)class\n'
class Foo(object):
__metaclass__ = ReqStrSugRepr
def __str__(self):
return 'Instance of class:',self.__class__.__name__
def __repr__(self):
return self.__class__.__name__
print '***Defined Foo class\n'
class Bar(object):
__metaclass__ = ReqStrSugRepr
def __str__(self):
return 'Instance of class:',self.__class__.__name__
print '***Defined Bar class\n'
class FooBar(object):
__metaclass__ = ReqStrSugRepr
print '***Defined FooBar class\n'
我们编写了三个关于元类的示例,其中一个(Foo)重载了特殊方法__str__()和__repr__(),另一个(Bar)只实现了特殊方法__str__(),还有一个都没有实现,这种情况是错误的。执行此脚本后,我们得到如下输出:
***Defined ReqStrSugRepr (meta)class
***Defined Foo class
Warning (from warnings module):
File "C:\Python27\lib\idlelib\run.py", line 298
exec code in self.locals
UserWarning: Class suggests overriding of __repr__()
***Defined Bar class
Traceback (most recent call last):
File "C:\Documents and Settings\Administrator\桌面\meta.py", line 29, in <module>
class FooBar(object):
File "C:\Documents and Settings\Administrator\桌面\meta.py", line 7, in __init__
raise TypeError('Class requires overriding of __str__()')
TypeError: Class requires overriding of __str__()
需要注意的是我们并没有创建任何测试类的实例,这些类本身就是元类的实例。
- Python中的元类(metaclass)
推荐+收藏:深刻理解Python中的元类(metaclass) 做一些笔记学习学习: 在大多数编程语言中,类就是用来描述如何生成一个对象的代码段,在Python中类也是一个对象,这个(类)对象自身拥有 ...
- [转]深刻理解Python中的元类(metaclass)以及元类实现单例模式
使用元类 深刻理解Python中的元类(metaclass)以及元类实现单例模式 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例 ...
- 深刻理解Python中的元类metaclass(转)
本文由 伯乐在线 - bigship 翻译 英文出处:stackoverflow 译文:http://blog.jobbole.com/21351/ 译注:这是一篇在Stack overflow上很热 ...
- 深刻理解Python中的元类(metaclass)
译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得 ...
- [转] 深刻理解Python中的元类(metaclass)
非常详细的一篇深入讲解Python中metaclass的文章,感谢伯乐在线-bigship翻译及作者,转载收藏. 本文由 伯乐在线 - bigship 翻译.未经许可,禁止转载!英文出处:stacko ...
- Python中的元类
从前面"Python对象"文章中了解到,在Python中一切都是对象,类可以创建实例对象,但是类本身也是对象. class C(object): pass c = C() prin ...
- 深刻理解Python中的元类(metaclass)【转】
译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得 ...
- 深刻理解Python中的元类(metaclass)以及元类实现单例模式
在理解元类之前,你需要先掌握Python中的类.Python中类的概念借鉴于Smalltalk,这显得有些奇特.在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.在Python中这一点仍 ...
- Python中的元类(译)
add by zhj: 这是大stackoverflow上一位小白提出的问题,好吧,我承认我也是小白,元类这块我也是好多次想搞明白, 但终究因为太难懂而败下阵来.看了这篇文章明白了许多,再加下啄木鸟社 ...
随机推荐
- 【转】MessageBox
MessageBox对话框是比较常用的一个信息对话框,其不仅能够定义显示的信息内容.信息提示图标,而且可以定义按钮组合及对话框的标题,是一个功能齐全的信息对话框. 1.函数原型及参数 function ...
- 【摘抄】Application.StartupPath和System.Environment.CurrentDirectory的区别
System.Environment.CurrentDirectory的含义是获取或设置当前工作路径,而Application.StartupPath是获取程序启动路径,表面上看二者没什么区别,但实际 ...
- 第一个android应用程序
首先打开Eclipse和一个AVD.在Eclipse中选择File→New→Project→Android→Android Application Project 点击Next,按照下图所示填写 注: ...
- bc命令
bc 命令: bc 命令是用于命令行计算器. 它类似基本的计算器. 使用这个计算器可以做基本的数学运算. [tough@localhost *|bc [tough@localhost expr ...
- arcgis中注记的高级处理
在实际制图过程中,常遇到一个图层的多个要素展示,将标注转换为注记的之后,可以对注记进行移动调整位置等手动更改.这样为避免重复地移动注记位置.可以采用如下方案: 1.将图层标注转换为注记 2.将注记存储 ...
- 鲁棒性是 Robustness
鲁棒性是 Robustness 的音译,是指当系统受到不正常干扰时,是否还能保证主体功能正常运作.可参考 维基百科:http://zh.wikipedia.org/zh/ 鲁棒性 _( 计算机科学 ) ...
- Swift function how to return nil
这两天在学习Stanford出品的iOS7的课程,这个课程去年也看过,但是看到第3课就不行了,满篇的OC,把人都搞晕了.这段时间因为要写个iOS的App,正好赶上了Swift问世,所以趁着这股劲继续学 ...
- TcpClient 错误"不能做任何连接,因为目标机器积极地拒绝它" 的解决
TcpClient 错误"不能做任何连接,因为目标机器积极地拒绝它" 的解决 //以下是tcpclient服务器端的监听程序,假设服务器端和客户端在同一台机器上,//为了使客户端可 ...
- 实体框架 (EF) 入门 => 一、我该用哪个工作流?
入门的参考资料:http://msdn.microsoft.com/zh-cn/data/ee712907 本篇的参考资料:http://msdn.microsoft.com/zh-cn/data/j ...
- asp.net web.config 经典模式和集成模式相关配置
<?xml version="1.0"?> <configuration> <!--IIS经典模式下使用--> <system.web&g ...