Python进阶:一步步理解Python中的元类metaclass
ahrr6660
8年前
<p style="text-align:center"><img src="https://simg.open-open.com/show/65d2a7c41f6962eed773c6ca9c45f2d5.png"></p> <p>虽然Python本身很难说是面向对象语言,但Python中的数据模型可以说真的是“纯面向对象”。在Python的世界里,一切皆是对象。无论是数值、字符串、序列、字典、函数、模块、类、实例、文件等等。</p> <p>元类(metaclass)是Python 2.2中引入的概念,它的作用是定制类的创建行为。这么解释可能有点难理解,那么这篇文章就通过实例,一步步解释Python中的元类。</p> <h2><strong>1. Python中一切皆对象,包括类</strong></h2> <pre> <code class="language-python">class Foo: def hello(self): print("hello world!") return foo = Foo() print(type(foo)) # <class '__main__.Foo'> print(type(foo.hello)) # <class 'method'> print(type(Foo)) # <class 'type'> temp = Foo # 赋值给其他变量 Foo.var = 11 # 增加参数 print(Foo) # 作为函数参数</code></pre> <p>例子中type(Foo)说明Foo本身也是一个对象,可以将其赋值给其他对象、对其添加属性、将其作为函数参数传递等等。</p> <h2><strong>2. 类的创建过程</strong></h2> <p>在上边的例子中,类Foo的创建过程中会执行class语句,此时需要首先确定元类(元类定制类的创建行为)。元类的确定过程如下:</p> <ul> <li>确定类Foo的父类是否有参数metaclass,如果没有则:</li> <li>确定类Foo的父类的父类是否有参数metaclass,如果没有则:</li> <li>使用默认元类type(type的用法会在3中讲解)。</li> </ul> <p>上边的例子中,前三项都不符合,则直接使用默认元类type。即上边的语句相当于:</p> <pre> <code class="language-python">def hello(self): print("hello world") return Foo = type("Foo", (object,), {"hello": hello})</code></pre> <p>此时可以看出,实际上类Foo是元类type的实例。参见文章的封面图。</p> <h2><strong>3. 动态创建类</strong></h2> <p>Python中的类可以动态创建,用的就是默认元类type。动态创建类的type函数原型为:</p> <pre> <code class="language-python">type(object_or_name, bases, dict)</code></pre> <p>这里不过多赘述,上个章节中有介绍。举个比较复杂的动态创建类的例子:</p> <pre> <code class="language-python">def init(self, name): self.name = name return def hello(self): print("hello %s" % self.name) return Foo = type("Foo", (object,), {"__init__": init, "hello": hello, "cls_var": 10}) foo = Foo("xianhu") print(foo.hello()) print(Foo.cls_var)</code></pre> <h2><strong>4. 自定义元类</strong></h2> <p>再一次说明实例、类和元类之间的关系:</p> <pre> <code class="language-python">>>> foo.__class__ # <class 'Foo'> >>> Foo.__class__ # <class 'type'> >>> type.__class__ # <class 'type'></code></pre> <p>foo是Foo的实例,Foo是type的实例,type的类又是type。type是默认的元类。那么如何自定义元类呢?(注意,百分之99的工程中不会用到自定义元类,除非你对元类非常理解)</p> <p>举个例子,假设我们需要对一个模块中的所有函数添加作者属性。首先自定义一个元类,自定义时,需要继承默认元类type,并重写其中的__new__方法:</p> <pre> <code class="language-python">class Author(type): def __new__(mcs, name, bases, dict): # 添加作者属性 dict["author"] = "xianhu" return super(Author, mcs).__new__(mcs, name, bases, dict)</code></pre> <p>对模块中所有函数的继承类参数中添加metaclass参数:</p> <pre> <code class="language-python">class Foo(object, metaclass=Author): pass foo = Foo() print(foo.author)</code></pre> <p>注意:Python3中不再有__metaclass__属性以及模块级别的__metaclass__属性。如果一个模块中函数较多,可以利用正则表达式进行查找替换。</p> <p>不过在平时的使用中,我发现了模块级别有个__build_class__函数,将其改为Author,就能达到模块级别元类的效果。但具体有哪些副作用还不太清楚,慎用!!!</p> <p>后再强调一遍:</p> <p>Metaclasses are deeper magic that 99% of users should never worry about. If you wonder whether you need them, you don't (the people who actually need them know with certainty that they need them, and don't need an explanation about why).</p> <p> </p> <p>来自:https://zhuanlan.zhihu.com/p/23887627</p> <p> </p>