摘要:先简单介绍下中的元类。元类就是创建类的类,对于元类来说,类是它的实例,将返回。中的所有类,都是的实例,换句话说,是元类的基类。
我在看源代码的时候,经常蹦出这一句:How does it work!竟然有这种操作?本系列文章,试图剖析代码中发生的魔法。顺便作为自己的阅读笔记,以作提高。
先简单介绍下Python中的元类(metaclass)。元类就是创建类的类,对于元类来说,类是它的实例,isinstance(cls, metaclass)将返回True。Python中的所有类,都是type的实例,换句话说,type是元类的基类。使用type创建一个类的方法如下:
>>>type("MyClass", (), {})
注:使用type创建的类和使用元类的类,都是新式类
使用元类后,该类将由定义的元类实例化来创建。定义的方法在Python 2与Python 3中有所不同:
# Python 2: class MyClass(object): __metaclass__ = MyMeta # Python 3: class MyClass(metaclass=MyMeta): pass
如果你的项目需要兼容Python 2和Python 3,就需要使用一种方法,同时支持Python 2和Python 3。元类有两个基本特性:
元类实例化得到类
元类能被子类继承
根据这两个特性,我们不难得到解决方案:
用元类实例化得到一个临时类
定义类时继承这个临时类
我们可以写出一个with_metaclass函数:
def with_metaclass(meta, *bases): """Compatible metaclass :param meta: the metaclass :param *bases: base classes """ return meta("temp_class", bases, {}) # Testing: class TestMeta(type): def __new__(cls, name, bases, d): d["a"] = "xyz" return type.__new__(cls, name, bases, d) class Foo(object):pass class Bar(with_metaclass(TestMeta, Foo)): pass
我们就创建了一个以TestMeta为元类,继承Foo的类Bar。验证:
>>> Bar.a "xyz" >>> Bar.__mro__ (, , , )
一切正常,但我们看到在Bar的mro里混进了一个临时类temp_class,你忽略它吧,有时会很麻烦。作为完美主义者,我想寻找一种解决办法,不要在mro中引入多余的类。
Python的six模块专门为解决Python 2to3兼容问题而生,模块里带有一个with_metaclass函数,我们来看它是怎么实现的:(为了debug,添加了一个print语句)
def with_metaclass(meta, *bases): class metaclass(type): def __new__(cls, name, this_bases, d): print(cls, "new is called") return meta(name, bases, d) return type.__new__(metaclass, "temp_class", (), {}) # Testing: class TestMeta(type): def __new__(cls, name, bases, d): d["a"] = "xyz" print(cls, "new is called") return type.__new__(cls, name, bases, d)
一时看不懂?没关系,我们来用用看,为了看清楚过程,我们分成两步执行:
>>> temp = with_metaclass(TestMeta, Foo) >>> class Bar(temp): pass ....metaclass"> new is called new is called >>> Bar.a "xyz" >>> Bar.__mro__ ( , , )
我们明明生成了一个临时类temp_class,但后来竟然消失了!下面来仔细分析函数的运行过程。首先我们看到,执行第一步生成临时类时,两个__new__都没有调用,而第二步定义类时,两个__new__都调用了。奥秘就在函数的返回语句return type.__new__(metaclass, "temp_class", (), {}),它创建了一个临时类,具有如下属性:
名称为temp_class
是函数内部类metaclass的实例,它的元类是metaclass
没有基类
创建时仅调用了type的__new__的方法
这是一个metaclass实例的不完全版本。接下来,定义Bar时,Bar得到继承的元类metaclass,过程如下:
实例化metaclass
调用metaclass.__new__
返回meta(name, bases, d), meta=TestMeta,bases=(Foo,)
调用TestMeta.__new__实例化得到Bar
Bar的基类由第3步得到,于是就去除了temp_class,这其实用到了闭包,with_metaclass返回的临时类中,本身无任何属性,但包含了元类和基类的所有信息,并在下一步定义类时将所有信息解包出来。
以上就是with_metaclass源代码的解析,通过这篇文章,相信能加深元类与闭包的理解。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/41088.html
摘要:许多的顶尖研究人员都会积极的在现场回答问题。虽然有许多主题的常见问题页面比如,这是一个机器学习的,但是这些都是非常不全面的,或者不够精致。在这篇文章中,我试图做一个更加全面的有关机器学习和问题的。 作者:chen_h微信号 & QQ:862251340微信公众号:coderpai简书地址:http://www.jianshu.com/p/ac18... showImg(https:/...
摘要:请注意,正斜杠位于结束标记中的标记描述之前。正斜杠必须在所有结束标签之前,但标签的语言必须与开头标签相同,上面的示例是。无论元素是否包含值,只要使用两个标签,开始和关闭标签必须完全匹配,精确到大小写除了结束标签中的正斜杠。 By Rob Sheldon, 2014/03/26 (首次发表于: 2012/09/20) 关于系列 本文属于进阶系列:XML进阶 自2003年以来,XML一直是...
摘要:编程语言及面向对象基础题 编程语言及面向对象基础题 Design Pattern What is singleton? Whats its cons and pros? How to implement it?Definition: Singleton pattern is a design pattern that ensure that only one instance of a...
摘要:本文仅用于学习和交流目的,不得用于商业目的。今年,我们依然会组织。随着语言的发展,这种情况将不再适用。本系列主要讨论如何获得这些高度模块化的应用程序。这一系列内的后续图书会讨论测试及部署等内容。更多精彩,加入图灵访谈微信 本文仅用于学习和交流目的,不得用于商业目的。非商业转载请注明作译者、出处,并保留本文的原始链接:http://www.ituring.com.cn/art... 访谈...
阅读 1619·2021-09-26 09:55
阅读 1358·2021-09-23 11:22
阅读 2685·2021-09-06 15:02
阅读 2602·2021-09-01 11:43
阅读 3907·2021-08-27 13:10
阅读 3655·2021-08-12 13:24
阅读 2056·2019-08-30 12:56
阅读 2977·2019-08-30 11:22