元类在很多编程语言中都有这样的概念,我们都知道,类可以创建对象,类本身也是对象,既然是对象,那么它肯定也是被创造出来的,元类就专门用来创造类对象,于是,这就给我们提供了一种操纵或者监听类的能力。

平时我们创建一个类,使用的是这种方式:

class MyClass(object):
def method(self):
return 1 instance1 = MyClass()
print(instance1.method())

如果把类也看成一个对象,利用元类,我们这样创建一个类:

def method(self):
return 1 klass = type('MyClass', (object,), {'method': method})
instance1 = klass()
print(instance1.method())

如果从写法上看,没什么太大的区别,MetaClass真正有用的地方是,我们可以自定义元类,接下来我们看一段代码:

class RevealingMeta(type):
def __new__(mcs, name, bases, namespace, **kwargs):
print(mcs, "__new__ called")
return super().__new__(mcs, name, bases, namespace) @classmethod
def __prepare__(metacls, name, bases, **kwargs):
print(metacls, "__prepare__ called")
return super().__prepare__(name, bases, **kwargs) def __init__(cls, name, bases, namespace, **kwargs):
print(cls, "__init__ called")
super().__init__(name, bases, namespace) def __call__(cls, *args, **kwargs):
print(cls, "__call__ called")
return super().__call__(*args, **kwargs)

上边的代码可以算是固定写法了,这其中比较重要的概念是这4个方法的调用时机:

  • __new__ 当某个类被创建的时候会调用
  • __prepare__ 在创建类的时候,可以传入额外的字典class Klass(metaclass=Metaclass, extra="value"):,这个方法就是用来创建接收dict的,所以这个方法会在__new__ 前边调用
  • __init__ 这个方法算是对__new__ 的一些补充
  • __call__ 这个方法会在类被创建的时候调用

我们就利用上边代码创建出来的元类,创建一个类:

class RevealingMeta(type):
def __new__(mcs, name, bases, namespace, **kwargs):
print(mcs, "__new__ called")
return super().__new__(mcs, name, bases, namespace) @classmethod
def __prepare__(metacls, name, bases, **kwargs):
print(metacls, "__prepare__ called")
return super().__prepare__(name, bases, **kwargs) def __init__(cls, name, bases, namespace, **kwargs):
print(cls, "__init__ called")
super().__init__(name, bases, namespace) def __call__(cls, *args, **kwargs):
print(cls, "__call__ called")
return super().__call__(*args, **kwargs) class RevealingClass(metaclass=RevealingMeta):
def __new__(cls, *args, **kwargs):
print(cls, "__new__ called")
return super().__new__(cls) def __init__(self):
print(self, "__init__ called")
super().__init__()

如果这时候直接执行代码,会打印出:

<class '__main__.RevealingMeta'> __prepare__ called
<class '__main__.RevealingMeta'> __new__ called
<class '__main__.RevealingClass'> __init__ called
<class '__main__.RevealingClass'> __call__ called

这说明,只要创建了类就会调用上边的方法,这些方法的调用跟实例的创建没有关系,接下来执行:

instance12 = RevealingClass()

在上边打印的后边,会打印出:

<class '__main__.RevealingClass'> __new__ called
<__main__.RevealingClass object at 0x104032048> __init__ called

这就是元类的基本用法了,它一般会用在很多的framework中,但也容易出错,我们可以为某个类随意指定元类,如果该元类没有实现这些方法,就有可能会出现崩溃。

python中MetaClass的一些用法的更多相关文章

  1. Python中 sys.argv[]的用法

    Python中 sys.argv[]的用法 因为是看书自学的python,开始后不久就遇到了这个引入的模块函数,且一直在IDLE上编辑了后运行,试图从结果发现它的用途,然而结果一直都是没结果,也在网上 ...

  2. 31 Python中 sys.argv[]的用法简明解释(转)

    Python中 sys.argv[]的用法简明解释 因为是看书自学的python,开始后不久就遇到了这个引入的模块函数,且一直在IDLE上编辑了后运行,试图从结果发现它的用途,然而结果一直都是没结果, ...

  3. Python中sorted()方法的用法

    Python中sorted()方法的用法 2012-12-24 22:01:14|  分类: Python |字号 订阅 1.先说一下iterable,中文意思是迭代器. Python的帮助文档中对i ...

  4. Python中int()函数的用法浅析

      int()是Python的一个内部函数 Python系统帮助里面是这么说的 >>> help(int)  Help on class int in module __builti ...

  5. Python中 sys.argv的用法简明解释

    Python中 sys.argv[]的用法简明解释 sys.argv[]说白了就是一个从程序外部获取参数的桥梁,这个“外部”很关键,所以那些试图从代码来说明它作用的解释一直没看明白.因为我们从外部取得 ...

  6. Python中metaclass解释

    Classes as objects 首先,在认识metaclass之前,你需要认识下python中的class.python中class的奇怪特性借鉴了smalltalk语言.大多数语言中,clas ...

  7. python中super()的一些用法

    在看python高级编程这本书的时候,在讲到super的时候,产生了一些疑惑,super在python中的用法跟其他的语言有一些不一样的地方,在网上找了一些资料,发现基本上很少有文章能把我的疑惑讲明白 ...

  8. Python中return self的用法

      在Python中,有些开源项目中的方法返回结果为self. 对于不熟悉这种用法的读者来说,这无疑使人困扰,本文的目的就是给出这种语法的一个解释,并且给出几个例子.   在Python中,retur ...

  9. python中Metaclass的理解

    今天在学习<python3爬虫开发实战>中看到这样一段代码3 class ProxyMetaclass(type): def __new__(cls, name, bases, attrs ...

随机推荐

  1. 简单的C程序

    1.最简单的C程序 #include<stdio.h> //预编译处理指令 int main() // 定义主函数 { printf("hello world"); } ...

  2. 1084: 开心的小明(dengdengoj)

    题目描述 小明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N 元钱就行”.今 ...

  3. axios简单理解

    发起一个GET请求 直接使用axios('/user')方法,axios()方法默认为GET方式 axios(’/user/12345’); 使用axios.get()方法,参数直接写以?key=va ...

  4. python反转列表的三种方式

    1.内建函数reversed() li =[1, 2, 3, 4, 5, 6] a = list(reversed(li)) print (a) 注意:reversed()函数返回的是一个迭代器,而不 ...

  5. LINUX配置Django

    django项目: 依赖包[root@web01 ~]# yum install openssl-devel bzip2-devel expat-devel gdbm-devel readline-d ...

  6. BZOJ2808 : 那些年我们画格子

    若$\min(n,m)=1$,那么设$f[i][j][k]$表示考虑前$i$个格子,改变了$j$次颜色,$i$的颜色为$k$的方案数,直接转移即可. 否则$\min(n,m)\geq 2$,那么有解当 ...

  7. 一个封装不错的 TcpClient 类

    using System;using System.Net;using System.Net.Sockets;using System.Text;using System.Threading; nam ...

  8. 百度杯 ctf 九月场---Text

    一看题目发现善于查资料就行了,那估计就是以前的漏洞,需要百度搜一下,果然是海洋cms的漏洞!这个漏洞是前台getshell漏洞,seach漏洞,该漏洞成因在于search.php没有对用户输入内容进行 ...

  9. Spark 1.x 爆内存相关问题汇总及解

    Spark 1.x 爆内存相关问题汇总及解决 OOM # 包括GC Overhead limitjava.lang.OutOfMemoryError # on yarn org.apache.hado ...

  10. Oracle中连接与加号(+)的使用

    1.左外连接(Left outer join/ left join) left join是以左表的记录为基础的,左表的记录将会全部表示出来,而右表只会显示符合搜索条件的记录.右表记录不足的地方均为NU ...