陌生的metaclass

程派微信号:codingpy


作者:Ethan。

原文链接为:https://funhacks.net/2016/11/12/metaclass/

本文约 6500 字,加上代码,读完可能需要 17 分钟。

Python 中的元类(metaclass)是一个深度魔法,平时我们可能比较少接触到元类,本文将通过一些简单的例子来理解这个魔法。

类也是对象

在 Python 中,一切皆对象。字符串,列表,字典,函数是对象,类也是一个对象,因此你可以:

  • 把类赋值给一个变量

  • 把类作为函数参数进行传递

  • 把类作为函数的返回值

  • 在运行时动态地创建类

看一个简单的例子:

熟悉又陌生的 type

在日常使用中,我们经常使用 object 来派生一个类,事实上,在这种情况下,Python 解释器会调用 type 来创建类。

这里,出现了 type,没错,是你知道的 type,我们经常使用它来判断一个对象的类型,比如:

事实上,type 除了可以返回对象的类型,它还可以被用来动态地创建类(对象)。下面,我们看几个例子,来消化一下这句话。

使用 type 来创建类(对象)的方式如下:

type(类名, 父类的元组(针对继承的情况,可以为空),包含属性和方法的字典(名称和值))

最简单的情况

假设有下面的类:

现在,我们不使用 class 关键字来定义,而使用 type,如下:

上面两种方式是等价的。我们看到,type 接收三个参数:

  • 第 1 个参数是字符串 ‘Foo’,表示类名

  • 第 2 个参数是元组 (object, ),表示所有的父类

  • 第 3 个参数是字典,这里是一个空字典,表示没有定义属性和方法

在上面,我们使用 type() 创建了一个名为 Foo 的类,然后把它赋给了变量 Foo,我们当然可以把它赋给其他变量,但是,此刻没必要给自己找麻烦。

接着,我们看看使用:

有属性和方法的情况

假设有下面的类:

type 来创建这个类,如下:

上面两种方式的效果是一样的,看下使用:

继承的情况

再来看看继承的情况,假设有如下的父类:

我们用 Base 派生一个 Foo 类,如下:

改用 type 来创建,如下:

—-|—-

什么是元类(metaclass)

元类(metaclass)是用来创建类(对象)的可调用对象。这里的可调用对象可以是函数或者类等。但一般情况下,我们使用类作为元类。对于实例对象、类和元类,我们可以用下面的图来描述

我们在前面使用了 type 来创建类(对象),事实上,type 就是一个元类

那么,元类到底有什么用呢?要你何用…

元类的主要目的是为了控制类的创建行为。我们还是先来看看一些例子,以消化这句话。

元类的使用

先从一个简单的例子开始,假设有下面的类:

现在我们想给这个类的方法和属性名称前面加上 my_ 前缀,即 name 变成 my_name,bar 变成 my_bar,另外,我们还想加一个 echo 方法。当然,有很多种做法,这里展示用元类的做法。

1.首先,定义一个元类,按照默认习惯,类名以 Metaclass 结尾,代码如下:

上面的代码有几个需要注意的点:

  • PrefixMetaClass 从 type 继承,这是因为 PrefixMetaclass 是用来创建类的

  • __new__ 是在 __init__ 之前被调用的特殊方法,它用来创建对象并返回创建后的对象,对它的参数解释如下:

2.接着,我们需要指示 Foo 使用 PrefixMetaclass 来定制类。

在 Python2 中,我们只需在 Foo 中加一个 __metaclass__ 的属性,如下:

在 Python3 中,这样做:

现在,让我们看看使用:

可以看到,Foo 原来的属性 name 已经变成了 my_name,而方法 bar 也变成了 my_bar,这就是元类的魔法。

再来看一个继承的例子,下面是完整的代码:

其中,PrefixMetaclass 和 Foo 跟前面的定义是一样的,只是新增了 Bar,它继承自 Foo。先让我们看看使用:

我们发现,Bar 没有 prop 这个属性,但是有 my_prop 这个属性,这是为什么呢?

原来,当我们定义 class Bar(Foo) 时,Python 会首先在当前类,即 Bar 中寻找__metaclass__,如果没有找到,就会在父类 Foo 中寻找 __metaclass__,如果找不到,就继续在 Foo的父类寻找,如此继续下去,如果在任何父类都找不到 __metaclass__,就会到模块层次中寻找,如果还是找不到,就会用 type 来创建这个类。

这里,我们在 Foo 找到了 __metaclass__,Python 会使用 PrefixMetaclass 来创建Bar,也就是说,元类会隐式地继承到子类,虽然没有显示地在子类使用 __metaclass__,这也解释了为什么 Bar 的 prop属性被动态修改成了 my_prop。

写到这里,不知道你理解元类了没?希望理解了,如果没理解,就多看几遍吧~

小结

  • 在 Python 中,类也是一个对象。

  • 类创建实例,元类创建类。

  • 当你创建类时,解释器会调用元类来生成它,定义一个继承自 object 的普通类意味着调用 type 来创建它。

参考资料

扫码关注编程派

获取最新教程及资源推送


↓↓↓ 点击阅读原文,查看更多Python教程


阅读原文:http://tluoyi.blog.163.com/blog/static/2672490212016101611100747/
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容

  • 原文出处: geekvi 元类 Python 中的元类(metaclass)是一个深度魔法,平时我们可能比较少接触...
    PyChina阅读 264评论 0 2
  • 1.元类 1.1.1类也是对象 在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段。在Python中这...
    TENG书阅读 1,255评论 0 3
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • Class也是Object 在理解metaclass之前,我们需要先理解Python中的class。从某种程度上来...
    耀凯考前突击大师阅读 25,830评论 6 34
  • (八)杜丘一脚刚踏出门外而另一脚还在门里,在门里的那一脚刚离开地面,就见胡一蝶猛地把门摔上,杜丘在被推出来时,幸亏...
    王王李阅读 144评论 0 0