什么是元类(metaclass)

元类是类的类,是类的模板

元类的实例为类,正如类的实例为对象

class Foo:
     pass

t1=Foo() #t1是通过Foo类实例化的对象

print(type(f1))
print(type(Foo))

所有的对象都是实例化或者说调用类而得到的(调用类的过程称为类的实例化),比如对象t1是调用FOO类得到的一个实例。

如果一切皆为对象,那么类Foo本质也是一个对象,既然所有的对象都是调用类得到的,那么Foo必然也是调用了一个类得到的,这个类称为元类。

于是可以推导出===>产生Foo的过程一定发生了:Foo=元类(...)

print(type(Foo)) # 结果为<class 'type'>,证明是调用了type这个元类而产生的Foo,即默认的元类为type

Foo类就是type类的一个实例

我们基于python中一切皆为对象,字符串、列表、字典、函数是对象,类也是一个对象的概念分析出:我们用class关键字定义的类本身也是一个对象,负责产生该对象的类称之为元类(元类可以简称为类的类),内置的元类为type,type是Python的一个内建元类,用来直接控制生成类,Python中任何class定义的类其实都是type类实例化的对象。

class关键字在帮我们创建类时,必然帮我们调用了元类Foo=type(...),那调用type时传入的参数是什么呢?必然是类的关键组成部分,一个类有三大组成部分,分别是

1、类名class_name='Foo'

2、基类们class_bases=(object,)   #继承新式类的父类object

3、类的名称空间class_dic,类的名称空间是执行类体代码而得到的

调用type时会依次传入以上三个参数

综上,class关键字帮我们创建一个类应该细分为以下四个过程

拿到类名:class_name='Foo'

拿到类的基类们:class_bases=(object,)

执行类体代码,拿到类的名称空间:class_dic={......}

调用元类得到类Foo = type(class_name,class_bases,class_dic)

自定义元类

一个类没有声明自己的元类,默认他的元类就是type,除了使用元类type,用户也可以通过继承type来自定义元类

1)最简单的情况

假设有下面的类:

class Foo(object):
     pass

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

Foo = type('Foo', (object, ), {})    # 使用 type 创建了一个类对象

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

  • 第 1 个参数是字符串 'Foo',表示类名
  • 第 2 个参数是元组 (object, ),表示所有的父类
  • 第 3 个参数是字典,这里是一个空字典,表示没有定义属性和方法

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

接着,我们看看使用:

>>> print Foo
<class '__main__.Foo'>
>>> print Foo()
<__main__.Foo object at 0x10c34f250>

2)有属性和方法的情况

假设有下面的类:

class Foo(object):
    foo = True
    def greet(self):
        print 'hello world'
        print self.foo

用type来创建这个类,如下:

def greet(self):
    print('hello world')
    print(self.foo)

Foo = type('Foo', (object, ), {'foo': True, 'greet': greet})

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

>>> f = Foo()
>>> f.foo
True
>>> f.greet
<bound method Foo.greet of <__main__.Foo object at 0x10c34f890>>
>>> f.greet()
hello world
True

把自定义函数名称写进底层字典里封存

def __init__(self,name,age):

self.name=name

self.age=age

def test(self):

print('=====>')

FFo=type('FFo',(object,),{'x':1,'__init__':__init__,'test':test}) #用元类的方法把类方法里的属性按键值对形式写入到函数底层字典里封存

print(FFo)   #<class '__main__.FFo'>

print(FFo.__dict__)

f1=FFo('jamfiy',18)

print(f1.name) #jamfiy

f1.test()  #=====>

继承的情况

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

class Base(object):
    pass

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

class Foo(Base):
   foo = True

现在改用type来创建,如下:

Foo = type('Foo', (Base, ), {'foo': True})

f1 = Foo()

print(f1.foo)

在父类中声明继承元类,子类再继承是元类的父类

例:

class MyType(type):  #声明继承元类type
    def __init__(self,a,b,c):    #Foo实例化f1触发__init__方法
        print('元类的构造函数执行')
        # print(a)   #打印self,Foo
        # print(b)   #打印元组()的内容,来自*args传过来的参数
        # print(c)   #打印字典{}的内容,来自**kwargs传过来的参数
    def __call__(self, *args, **kwargs):   #调用Foo()方法触发__call__方法
        # print('=-======>')
        # print(self)  #Foo
        # print(args,kwargs)
        obj=object.__new__(self)  #调用新式类都继承的object基类,__new__方法生成一个对象引用,object.__new__(Foo)-->f1
        self.__init__(obj,*args,**kwargs)  #相当于执行Foo.__init__(f1,*arg,**kwargs)
        return obj   #返回结果给实例化对象f1
class Foo(metaclass=MyType):  # 继承MyType元类,Foo=MyType(Foo,'Foo',(),{})  ---》 __init__
    def __init__(self,name):
        self.name=name   #相当于执行f1.name=name
# print(Foo)
f1=Foo('alex')
print(f1)
print(f1.__dict__)

python高级(元类、自定义元类)相关推荐

  1. 13.6 Thread类自定义线程类

    package cn.chen.thread; /** * 线程:* 多线程:* 一个java程序只是有两个线程:* 一个是主线程负责main方法代码执行,一个是垃圾回收器线程,负责* 创建线程的方式 ...

  2. 网络请求之优化参数添加工具类自定义Map类

    导入依赖: implementation 'com.squareup.okhttp3:okhttp:3.4.1' 调用方法: File file = new File("");Ht ...

  3. 专题---自定义实体类

    目录 一.概述 二.项目初始化 2.1 创建空解决方案 2.2 DBX操作 2.2.1 创建DBX 2.2.2 调试DBX 2.2.3 创建实体类 2.2.4 调试实体类 2.3 ARX操作 2.3. ...

  4. python:改良廖雪峰的使用元类自定义ORM

    概要 本文仅仅是对廖雪峰老师的使用元类自定义ORM进行改进,并不是要创建一个ORM框架 编写field class Field(object):def __init__(self, column_ty ...

  5. python高端写法_python高级篇:使用元类方式实现单例模式详解

    对于编程开发的朋友来说,设计模式应该最为熟悉不过了,如果要谈到哪种设计模式最为简单,也最容易理解,首当其冲的"单例模式"应该不为过了.本文主要讲解在python3中如何使用元类实现 ...

  6. python 元类 type_Python 使用元类type创建类对象常见应用详解

    本文实例讲述了Python 使用元类type创建类对象.分享给大家供大家参考,具体如下: type("123") 可以查看变量的类型;同时 type("类名", ...

  7. Python中的元类及元类实现的单例模式

    https://www.cnblogs.com/tkqasn/p/6524879.html 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元 ...

  8. python——元类、元类实现orm

    元类 1. 类也是对象 在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.在Python中这一点仍然成立: >>> class ObjectCreator(object ...

  9. python面试题~反射,元类,单例

    1 什么是反射?以及应用场景? test.py def f1():print('f1') def f2():print('f2') def f3():print('f3') def f4():prin ...

最新文章

  1. apache开启gzip压缩
  2. 怎么查看电脑多少内核和多少逻辑处理器?
  3. 【面试招聘】阿里、腾讯 | 算法岗面试复盘
  4. RuoYi-Vue 部署 Linux环境 若依前后端分离项目(war 包+nginx版本)
  5. 信息学奥赛一本通(1003:对齐输出)
  6. c语言验证寝室是否满人,寝室管理系统c语言.doc
  7. java arraylist_死磕 java集合之ArrayList源码分析
  8. oracle掉电后ora 00600,ORA-00600: 内部错误代码, 参数: [kcratr1_lastbwr](转)
  9. [转]Go语言中的make和new
  10. l4d2服务器修改武器伤害,辐射4武器伤害及护甲修改攻略
  11. 设计模式演练——工厂方法模式
  12. 那些我们卖掉的二手iPhone到底去哪了?
  13. python手撕链表_图解_leetcode707_设计链表
  14. Kali-DDoS工具集合
  15. 数据库的ACID是什么
  16. Tips_linux
  17. 友情链接加nofollow_如何在WordPress中Nofollow所有外部链接
  18. 基于51单片机的电烤箱微波炉数码管显示proteus仿真
  19. 超过ChatGPT3达到ChatGPT4%90性能的小羊驼来了-Vicuna(校招社招必备,chatgpt风口来了赶紧学起来吧)
  20. Linux服务器下载日志到本地

热门文章

  1. Linux开源硬件,关于开源硬件
  2. 解决Ubuntu18.04触摸板右键不能用的问题
  3. 简单理解modbus功能码和分区
  4. 达梦数据库关键字大全
  5. [ZT]SUN非常有用之 Unix/Linux 单行脚本
  6. 网站打开速度对网站的影响!
  7. 用Python做一个控制台程序实现图书管理器的简单功能,例如添加图书、查询库里的图书、删除图书、修改书籍信息、显示书籍信息,或者是借阅/归还...
  8. ES6 —— 3、async-await、微任务和宏任务、class、proxy(代理)
  9. 书单丨邹欣的书架:从程序到创新
  10. 计算机二级Python——题库4知识点