• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

详解python metaclass(元类)

python 搞代码 4年前 (2022-01-09) 16次浏览 已收录 0个评论

元编程,一个听起来特别酷的词,强大的Lisp在这方面是好手,对于Python,尽管没有完善的元编程范式,一些天才的开发者还是创作了很多元编程的魔法。Django的ORM本文来源gaodaimacom搞#^代%!码&网*就是元编程的一个很好的例子。

本篇的概念和例子皆在Python3.6环境下

一切都是对象

Python里一切都是对象(object),基本数据类型,如数字,字串,函数都是对象。对象可以由类(class)进行创建。既然一切都是对象,那么类是对象吗?

是的,类也是对象,那么又是谁创造了类呢?答案也很简单,也是类,一个能创作类的类,就像上帝一样,开启了万物之始。这样的类,称之为元类(classmeta)。

类的定义

对象是通过类创建的,这个很好理解。例如下面的代码:

class Bar(object):
  pass

bar = Bar()
print(bar, bar.__class__)  # <__main__.Bar object at 0x101eb4630> <class '__main__.Bar'>
print(Bar, Bar.__class__) # <class '__main__.Bar'> <class 'type'>

可以看见对象 bar 是类 Bar 创建的实例。然而 Bar,看起来却是由一个叫 type 的类创建的实例。即 bar <-- Bar < -- type

上面的例子,对象是动态创建的,类则是通过关键字 class 声明定义的。class关键字背后的玄机是什么呢?

实际上,class Bar(object) 这样的代码,等价于 Bar = type('Bar', (objects, ), {})
即类 type 通过实例化创建了它的对象 Bar,而这个 Bar 恰恰是一个类。这样能创建类的类,就是 Python 的元类。

从创建 Bar 的代码上来看,元类 type 的 __init__ 方法有3个参数,

  • 第一个是创建的类的名字
  • 第二个是其继承父类的元类列表,
  • 最后就是一个属性字典,即该类所具有的属性。

type 元类

type是小写,因而很容易误以为它是一个函数。通过help(type)可以看到它的定义如下:

class type(object):
  """
  type(object_or_name, bases, dict)
  type(object) -> the object's type
  type(name, bases, dict) -> a new type
  """
  def __init__(cls, what, bases=None, dict=None): # known special case of type.__init__
    """
    type(object_or_name, bases, dict)
    type(object) -> the object's type
    type(name, bases, dict) -> a new type
    # (copied from class doc)
    """
    pass

   @staticmethod # known case of __new__
  def __new__(*args, **kwargs): # real signature unknown
    """ Create and return a new object. See help(type) for accurate signature. """
    pass

如前所述,__init__方法接受三个参数,type 实例化的过程,会创建一个新的类。创建类的代码来自 __new__ 方法,它的参数其实和 __init__,一样。至于它们之间有什么关系,后面再做介绍。目前只要知道,当调用 type 进行实例化的时候,会先自动调用 __new__ 方法,然后再接着调用 __init__方法,在类外面来看,最终会实例化一个对象,这个对象是一个类。

从 type 的定义来看,它继承 object,Python3的所有类,都继承来着 object,类type 也是 object 的实例,令人奇怪的是,object 既是类也是对象,它也是由 type实例化而来。有一种鸡生蛋,蛋生鸡的悖论。暂且先不管,只要知道所有类的顶级继承来自 object 就好。

自定义元类

既然元类可以创建类,那么自定义元类就很简单了,直接继承类 type 即可。先看下面一个例子:

class MyType(type):
  pass


class Bar(object, metaclass=MyType):
  pass


print(MyType, MyType.__class__) # <class '__main__.MyType'> <class 'type'>
print(Bar, Bar.__class__) # <class '__main__.Bar'> <class '__main__.MyType'>

搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:详解python metaclass(元类)

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址