Python元类(type()和metaclass)

1. 元类是什么

众所周知,对象由类实例化而来,类是对象的模板,而python一切皆对象,类也是对象,它由元类(type)创建,所以元类是类的类,是类的模板

2. 创建类的另一种方法

一般情况下,我们使用class关键字申明一个类,就像

class Demo:def __init__(self,name,age):self.name = nameself.age = agedef output(self):print("name is " + str(self.name) + " age is " + str(self.age))if __name__ == '__main__':demo = Demo("Bob",18)demo.output()

python 中所有的类都是通过type创建的,所以当我们使用type()函数查看类的类型时会显式<class type>

>>> class Demo:pass>>> type(Demo)
<class 'type'>
>>> demo = Demo()
>>> type(demo)
<class '__main__.Demo'>

通过类实例化出来的对象的类型是<class 类名>,这样也更加验证了所有类都是由元类type实例化而来

通过type创建类

可以看一下type的文档,type可以传入三个参数,object_or_name, bases, dict,当只有一个参数是object时,返回该对象的类型,就是最常使用的这种情况,当传入name, bases, dict参数时,会返回一个类,name是类名,bases是基类元组,dict是类中属性和方法的字典

class type(object):"""type(object_or_name, bases, dict)type(object) -> the object's typetype(name, bases, dict) -> a new type"""

我们使用type重写一下上面的Demo类

# 模拟__init__()
def __init__(self,name,age):self.name = nameself.age = agedef output(self):print("name is " + str(self.name) + " age is " + str(self.age))class_name = 'Demo'
class_bases = (object,)
class_dict = {'__init__':__init__,'output': output,
}# type(name, bases, dict) -> a new type
Demo = type(class_name,class_bases,class_dict)
demo = Demo('Bob',18)
demo.output()  # name is Bob age is 18

实际上,每次用class定义类时,执行的都是type()方法

3. MetaClass

既然所有类都是由type创建的,那我们就可以控制类的创建行为,这就需要使用元类metaclass

  • 元类用来创建类,实质上也是一个类,继承自type
  • __new__是真正的构造函数,用来分配内存空间__new__(cls: type, name: str, bases: Tuple[type, ...], namespace: Dict[str, Any]) -> type
def add(self, value):print('add one value')self.append(value)class ListMetaclass(type):def __new__(mcs, name, bases, namespace):namespace['add'] = addreturn type.__new__(mcs, name, bases, namespace)class MyList(list, metaclass=ListMetaclass):passli = MyList()
li.add(1)
print(li)

在用class定义类时,括号中可以指定metaclass,指定后会创建__metaclass__,python在创建类的时候,会先检查有没有__metaclass__,如果有,就会以此方法创建对象,没有就会逐级向上查找父类中有没有该,如果找到当前package中还没有找到,就会使用默认的type创建(调用metaclass.__new__())

值得注意的是,如果我们在做类的定义时,在class声明处传入关键字metaclass=ListMetaclass,那么如果传入的这个metaclass有__call__函数,这个__call__函数将会覆盖掉MyList class的__new__函数。这是为什么呢?请大家回想一下,当我们实例化MyList的时候,用的语句是L1=MyList(),而我们知道,__call__函数的作用是能让类实例化后的对象能够像函数一样被调用。也就是说MyList是ListMetaclass实例化后的对象,而MyList()调用的就是ListMetaclass的__call__函数。另外,值得一提的是,如果class声明处,我们是让MyList继承ListMetaclass,那么ListMetaclass的__call__函数将不会覆盖掉MyList的__new__函数。

元类在一般情景下很少用到,但在像ORM中还是会有应用的,ORM(对象关系映射),ORM看这位大佬的文章谈谈Python中元类Metaclass(二):ORM实践

4. 总结

  • 通过class定义的类其实是通过type()创建的
  • type(object_or_name, bases, dict)
  • 如果想要控制类的创建行为,需要在创建类时指定metaclass,一旦指定了metaclass,就会在class上添加__metaclass__,创建类时会找__metaclass__指向的类,并用这个类创建类,如果找不到,就会调用默认的type()

参考文章

Python中的元类(metaclass)
谈谈Python中元类Metaclass(一):什么是元类
Python之元类

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/457612.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

word文档打印 自动编码_办公室文件打印有哪些技巧 办公室文件打印技巧介绍【图文】...

办公室文件打印实用技巧三则一. 打印文件直接装订——逆序打印相信使用Word打印过长篇文档的朋友一定都清楚&#xff0c;打印完成后的装订一直是个麻烦事儿&#xff0c;因为文件由打印机打出时&#xff0c;第一页肯定会在最下面&#xff0c;装订之前总要费时费力的把纸张按顺序…

Strategy 策略模式

意图 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。 动机 策略模式为了适应不同的需求&#xff0c;只把变化点封装了&#xff0c;这个变化点就是实现不同需求的算法&#xff0c;但是&#xff0c;用户需要知道各种…

python 消息中间件_消息队列中间件 RabbitMQ 详细介绍——安装与基本应用(Python)...

RabbitMQ 是当前最流行的消息中间件(Message Broker)之一&#xff0c;支持多种消息协议(如 AMQP、MQTT)。同时它也是一个轻量级的非常易于部署的开源软件&#xff0c;可以运行在当前大多数操作系统及云端环境中&#xff0c;也能够部署在分布式的集群环境里以达到高可用、可伸缩…

用 Flask 来写个轻博客 (1) — 创建项目

目录 目录前言扩展阅读部署开发环境创建 Github 项目前言 一步一步的实现一个 Flask 轻博客项目启动&#xff0c;最新的代码会上传到 Github。 扩展阅读 欢迎使用 Flask — virtualenv 部署开发环境 连接 GitHubhostnamectl set-hostname flask-dev # 设置 hostname ssh-keyg…

python静态方法,类方法,属性方法,实例方法

DAY 3. 静态方法&#xff0c;类方法&#xff0c;属性方法&#xff0c;实例方法 有四种方法&#xff0c;实例方法&#xff0c;类方法&#xff0c;静态方法&#xff0c;属性方法 实例方法 实例方法的第一个参数是self&#xff0c;他会指向类的实例化对象&#xff0c;只能被对象…

ubuntu 软件包降级

ubuntu 软件包降级 sudo aptitude install libssl-dev 1. 是否接受该解决方案&#xff1f; [Y/n/?] n 2. 是否接受该解决方案&#xff1f; [Y/n/?] y 3. 您要继续吗&#xff1f; [Y/n/?] ysudo aptitude install libcairo21.4.10-1ubuntu4 # 强制降级 sudo aptitude forbid…

java后期发展方向_Java程序员的4个职业发展方向,该如何把握黄金5年?

在Java程序界流行着一种默认的说法叫“黄金5年”&#xff0c;意思是说&#xff0c;一个Java程序员从入职的时候算起&#xff0c;前五年我选择直接影响着整个职业生涯的发展方向和薪资走向。而这5年&#xff0c;也决定了一个程序员能否成为职业大牛的可能。那么&#xff0c;在这…

python 类变量(属性)和实例变量(属性

DAY 4. 类变量&#xff08;属性&#xff09;和实例变量&#xff08;属性&#xff09; 类变量&#xff1a;在所有类的实例之间都可以共享的变量&#xff0c;类变量在所有对象间只保留一份 在类体中定义类的所有实例对象都可以访问类变量类变量只能由类修改&#xff0c;实例对象…

MySQL 关联表批量修改(数据同步)

update table1 t1 ,table2 t2 set t1.field1 t2.field2 where t1.id t2.id 转载于:https://www.cnblogs.com/52php/p/5677908.html

sourcetree不好做到的一些git操作

2019独角兽企业重金招聘Python工程师标准>>> 日常中我们有很多操作通过sourcetree就可以实现界面化操作&#xff0c;但是有一些场景不好去实现&#xff0c;这里总结下&#xff1a; 场景1&#xff1a;我们有个A分支&#xff0c;需要跟master分支合并等待上线&#xf…

vue大括号里接受一个函数_vue源码探究(第四弹)

vue源码探究&#xff08;第四弹&#xff09;结束了上一part的数据代理&#xff0c;这一部分主要讲讲vue的模板解析&#xff0c;感觉这个有点难理解&#xff0c;而且内容有点多&#xff0c;hhh。模板解析废话不多说&#xff0c;先从简单的入手。按照之前的套路&#xff0c;先举一…

类级别的分装 ---四种访问级别

privateprivate成员为类的私有性质&#xff0c;仅有类本身和友元可以访问&#xff1b;protected和private类似&#xff0c;区别于protected可以被该类所有派生类访问&#xff1b;publicpublic的成员可以被外界的所有客户代码直接访问published和public的区别仅在于published的成…

python自省与反射

DAY 5. python自省 这是很久之前写的&#xff0c;当时对自省和反射的概念没理解&#xff0c;学习Java以后多了一点理解&#xff0c;自省是获取对象的能力&#xff0c;反射是操纵对象的能力&#xff0c;python中使用getattr()和setattr()实现反射&#xff0c;而其他的则是自省&…

vb.net 窗体接收键盘事件_(十五)C#WinFrom自定义控件系列-键盘(二)

前提入行已经7,8年了&#xff0c;一直想做一套漂亮点的自定义控件&#xff0c;于是就有了本系列文章。本系列文章将讲解各种控件的开发及思路&#xff0c;欢迎各位批评指正。此系列控件开发教程将全部在原生控件基础上进行重绘开发&#xff0c;目标的扁平化、漂亮、支持触屏。如…

centos下cmake安装

步骤一、安装gcc等必备程序包&#xff08;已安装则略过此步&#xff0c;用gcc -v检测&#xff09; yum install -y gcc gcc-c make automake 步骤二、安装wget &#xff08;已安装则略过此步&#xff09; yum install -y wget 步骤三、获取CMake源码包 wget http://www.cmake.…

python 生成式,迭代器,生成器

DAY 6. 生成式,迭代器&#xff0c;生成器 6.1 生成式 6.1.1 列表生成式 list [index for index in range(10)]6.1.2 字典生成式 dict {zhangsan: 10,lisi: 12,wangwu: 18 } # 实现键值互换 dict {k:v for v,k in dict.items() if k > 12}6.1.3 集合生成式 # 100以内…

shell MAC 地址 校验

/**************************************************************************************** shell MAC 地址 校验* 说明&#xff1a;* 要对MAC地址进行校验&#xff0c;记录一下正则表达式写法&#xff0c;有些方法在PC上验证是可行的&…

移动端Web开发如何处理横竖屏

<!Doctype html> <html> <head> <meta charset"utf-8"> <meta id"viewport" name"viewport" content"widthdevice-width,initial-scale1.0;"> <title>横竖屏切换检测</title> <style ty…

恩智浦智能车大赛2020_内蒙古科技大学第九届智能车大赛校内公开赛总决赛

为了激发学生的创新意识&#xff0c;提高学生的动手能力&#xff0c;培养团队合作意识&#xff0c;秉承“实践源于真知&#xff0c;创新放飞梦想”的思想。2020年12月6日&#xff0c;内蒙古科技大学第九届智能车大赛总决赛如约而至。本次大赛有来自各院系的223支队伍报名参加了…

python格式化字符串的三种方法(%,format,f-string)

DAY 7. 格式化字符串 到目前为止&#xff0c;我所知道的&#xff0c;python格式化字符串有三种方法&#xff0c;第一是早期就有的%&#xff0c;其次是2.5之后的format(),还有就是3.6添加的f字符串调试 7.1 %格式化字符串 %格式化字符串是python最早的&#xff0c;也是能兼容…