本文实例讲述了python中metaclass原理与用法。分享给大家供大家参考,具体如下:
什么是 metaclass.
metaclass (元类)就是用来创建类的类。在前面一篇文章《python动态创建类》里我们提到过,可以用如下的一个观点来理解什么是metaclass:
MyClass = MetaClass() MyObject = MyClass()
metaclass是python 里面的编程魔法
同时在前面一篇《python动态创建类》文章里描述动态创建class 的时候介绍了type,他允许你用如下的方法创建一个类:
MyClass = type('MyClass', (), {})
其根本原因就在于 type 就是一个 metaclass, python利用type在后面创建各种各样的类。搞不明白的是,为什么是 "type" 而不是 "Type",可能考虑到 str 是用来创建字符串的,int 是用来 创建整形对象,所以type 用来创建 class object的,都用小写好了。
在python中的任何东西都是对象。包括int,str,function,class等。他们都是从一个class 创建的,我们可以通过查看 __class__ 属性来检查.
> age = 35 > age.__class__ <type 'int'> > name = 'bob' > name.__class__ <type 'str'> > def foo(): pass > foo.__class__ <type 'function'> > class Bar(object): pass > b = Bar() > b.__class__ <class '__main__.Bar'>
检查__class__属性
> a.__class__.__class__ <type 'type'> > age.__class__.__class__ <type 'type'> > foo.__class__.__class__ <type 'type'> > b.__class__.__class__ <type 'type'>
发现什么了,结果都是 "type", 其实 type 就是python内置的一个metaclass.当然,你可以创建自己的metaclass. 这里有一个很重要的属性:
__metaclass__ 属性
当你在写一个class的时候,你可以加入__metaclass__属性.
class Foo(object): __metaclass__ = something... [...]
如果你这么做了,那么python 将调用 metaclass 去创建 Foo class, 感觉是不是让你有点困惑呢。
python 将在你的class定义中查找__metaclass__,如果找到,就会用这个metaclass去创建Foo class,如果没有找到,就会用 type 去创建class.如果上篇文章提到的一样.所以,当你
class Foo(Bar): pass
pyton 将会如下去解析:是否有__metaclass__ 在Foo 里面,如果是的,则用metaclass 去创建一个名字为 ”Foo" 的class object. 如果没有找到,则看其基类Bar里面是否有__metaclass__,如果基类没有,则看所在的module 层是否有__metaclass__,如果都没有的话,则调用 type 去创建这个类。
现在的问题是,__metaclass__ 里面到底能做什么?结论是:能创建一个class的东西。什么能创建一个class, 其实就是 type,或者type 的子类(subclass)。
自定义 metaclass
metaclass的主要目的就是在创建类的时候,做一些自动的改变。比如,打个不恰当的比方,我们打算将一个module里所有类的属性都变成大写的。其中一种处理办法就是用 __metaclass__(申明在module上).
我们打算利用 metaclass 把所有的属性变成大写的。__metaclass__并不一定要求是一个class, 是一个可以调用的方法也是可以的。我们就从一个简单的例子看起
def upper_attr(future_class_name, future_class_parents, future_class_attr): """ Return a class object, with the list of its attribute turned into uppercase. """ # pick up any attribute that doesn't start with '__' attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__')) # turn them into uppercase uppercase_attr = dict((name.upper(), value) for name, value in attrs) # let `type` do the class creation return type(future_class_name, future_class_parents, uppercase_attr) __metaclass__ = upper_attr # this will affect all classes in the module class Foo(): # global __metaclass__ won't work with "object" though # but we can define __metaclass__ here instead to affect only this class # and this will work with "object" childrend bar = 'bip' print hasattr(Foo, 'bar') # Out: False print hasattr(Foo, 'BAR') # Out: True f = Foo() print f.BAR # Out: 'bip'
现在用一个类来处理
# remember that `type` is actually a class like `str` and `int` # so you can inherit from it class UpperAttrMetaclass(type): # __new__ is the method called before __init__ # it's the method that creates the object and returns it # while __init__ just initializes the object passed as parameter # you rarely use __new__, except when you want to control how the object # is created. # here the created object is the class, and we want to customize it # so we override __new__ # you can do some stuff in __init__ too if you wish # some advanced use involves overriding __call__ as well, but we won't # see this def __new__(upperattr_metaclass, future_class_name, future_class_parents, future_class_attr): attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__')) uppercase_attr = dict((name.upper(), value) for name, value in attrs) return type(future_class_name, future_class_parents, uppercase_attr)
显然这不是很oop的做法,直接调用了type
方法,而不是调用父类的__new__
方法,下面这么做:
class UpperAttrMetaclass(type): def __new__(upperattr_metaclass, future_class_name, future_class_parents, future_class_attr): attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__')) uppercase_attr = dict((name.upper(), value) for name, value in attrs) # reuse the type.__new__ method # this is basic OOP, nothing magic in there return type.__new__(upperattr_metaclass, future_class_name, future_class_parents, uppercase_attr)
你可能注意到 upperattr_metaclass ,这其实就相于self
,普通类方法里的self.一个更通用的方法如下:
class UpperAttrMetaclass(type): def __new__(cls, name, bases, dct): attrs = ((name, value) for name, value in dct.items() if not name.startswith('__')) uppercase_attr = dict((name.upper(), value) for name, value in attrs) return super(UpperAttrMetaclass, cls).__new__(cls, name, bases, uppercase_attr)
通过上面的例子可以了解metaclass了,也了解了在__init__
方法,__new__
方法里去做一个hook.当然还可以在__call__
里面做文章,但更多的人喜欢在__init__
里面修改 。
更多关于Python相关内容感兴趣的读者可查看本站专题:《Python面向对象程序设计入门与进阶教程》、《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python编码操作技巧总结》及《Python入门与进阶经典教程》
希望本文所述对大家Python程序设计有所帮助。
python,metaclass
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。