阅读目录
- 一 知识储备
- 二 引子(类也是对象)
- 三 什么是元类?
- 四 创建类的两种方式
- 五 自定义元类控制类的行为
- 六 练习题
exec:三个参数
参数一:字符串形式的命令
参数二:全局作用域(字典形式),如果不指定,默认为globals()
参数三:局部作用域(字典形式),如果不指定,默认为locals()
#可以把exec命令的执行当成是一个函数的执行,会将执行期间产生的名字存放于局部名称空间中
g={
'x':1,
'y':2
}
l={}
exec('''
global x,z
x=100
z=200
m=300
''',g,l)
print(g) #{'x': 100, 'y': 2,'z':200,......}
print(l) #{'m': 300}
class Foo:
pass
f1=Foo() #f1是通过Foo类实例化的对象
python中一切皆是对象,类本身也是一个对象,当使用关键字class的时候,python解释器在加载class的时候就会创建一个对象(这里的对象指的是类而非类的实例),因而我们可以将类当作一个对象去使用,同样满足第一类对象的概念,可以:
-
把类赋值给一个变量
-
把类作为函数参数进行传递
-
把类作为函数的返回值
-
在运行时动态地创建类
上例可以看出f1是由Foo这个类产生的对象,而Foo本身也是对象,那它又是由哪个类产生的呢?
1 #type函数可以查看类型,也可以用来查看对象的类,二者是一样的
2 print(type(f1)) # 输出: 表示,obj 对象由Foo类创建
3 print(type(Foo)) # 输出:
三 什么是元类?
元类是类的类,是类的模板
元类是用来控制如何创建类的,正如类是创建对象的模板一样,而元类的主要目的是为了控制类的创建行为
元类的实例化的结果为我们用class定义的类,正如类的实例为对象(f1对象是Foo类的一个实例,Foo类是 type 类的一个实例)
type是python的一个内建元类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象
方式一:使用class关键字
class Chinese(object):
country='China'
def __init__(self,name,age):
self.name=name
self.age=age
def talk(self):
print('%s is talking' %self.name)
方式二:就是手动模拟class创建类的过程):将创建类的步骤拆分开,手动去创建
#准备工作:
#创建类主要分为三部分
1 类名
2 类的父类
3 类体
#类名
class_name='Chinese'
#类的父类
class_bases=(object,)
#类体
class_body="""
country='China'
def __init__(self,name,age):
self.name=name
self.age=age
def talk(self):
print('%s is talking' %self.name)
"""
步骤一(先处理类体->名称空间):类体定义的名字都会存放于类的名称空间中(一个局部的名称空间),我们可以事先定义一个空字典,然后用exec去执行类体的代码(exec产生名称空间的过程与真正的class过程类似,只是后者会将__开头的属性变形),生成类的局部名称空间,即填充字典
class_dic={}
exec(class_body,globals(),class_dic)
print(class_dic)
#{'country': 'China', 'talk': , '__init__': }
步骤二:调用元类type(也可以自定义)来产生类Chinense
Foo=type(class_name,class_bases,class_dic) #实例化type得到对象Foo,即我们用class定义的类Foo
print(Foo)
print(type(Foo))
print(isinstance(Foo,type))
'''
True
'''
我们看到,type 接收三个参数:
-
第 1 个参数是字符串 ‘Foo’,表示类名
-
第 2 个参数是元组 (object, ),表示所有的父类
-
第 3 个参数是字典,这里是一个空字典,表示没有定义属性和方法
补充:若Foo类有继承,即class Foo(Bar):.... 则等同于type('Foo',(Bar,),{})
五 自定义元类控制类的行为#一个类没有声明自己的元类,默认他的元类就是type,除了使用元类type,用户也可以通过继承type来自定义元类(顺便我们也可以瞅一瞅元类如何控制类的行为,工作流程是什么)
#!!!如果你拷贝不注明出处的话,以后老子都不写了!!!
#知识储备:
#产生的新对象 = object.__new__(继承object类的子类)
#步骤一:如果说People=type(类名,类的父类们,类的名称空间),那么我们定义元类如下,来控制类的创建
class Mymeta(type): # 继承默认元类的一堆属性
def __init__(self, class_name, class_bases, class_dic):
if '__doc__' not in class_dic or not class_dic.get('__doc__').strip():
raise TypeError('必须为类指定文档注释')
if not class_name.istitle():
raise TypeError('类名首字母必须大写')
super(Mymeta, self).__init__(class_name, class_bases, class_dic)
class People(object, metaclass=Mymeta):
country = 'China'
def __init__(self, name, age):
self.name = name
self.age = age
def talk(self):
print('%s is talking' % self.name)
#步骤二:如果我们想控制类实例化的行为,那么需要先储备知识__call__方法的使用
class People(object,metaclass=type):
def __init__(self,name,age):
self.name=name
self.age=age
def __call__(self, *args, **kwargs):
print(self,args,kwargs)
# 调用类People,并不会出发__call__
obj=People('egon',18)
# 调用对象obj(1,2,3,a=1,b=2,c=3),才会出发对象的绑定方法obj.__call__(1,2,3,a=1,b=2,c=3)
obj(1,2,3,a=1,b=2,c=3) #打印: (1, 2, 3) {'a': 1, 'b': 2, 'c': 3}
#总结:如果说类People是元类type的实例,那么在元类type内肯定也有一个__call__,会在调用People('egon',18)时触发执行,然后返回一个初始化好了的对象obj
#步骤三:自定义元类,控制类的调用(即实例化)的过程
class Mymeta(type): #继承默认元类的一堆属性
def __init__(self,class_name,class_bases,class_dic):
if not class_name.istitle():
raise TypeError('类名首字母必须大写')
super(Mymeta,self).__init__(class_name,class_bases,class_dic)
def __call__(self, *args, **kwargs):
#self=People
print(self,args,kwargs) # ('egon', 18) {}
#1、实例化People,产生空对象obj
obj=object.__new__(self)
#2、调用People下的函数__init__,初始化obj
self.__init__(obj,*args,**kwargs)
#3、返回初始化好了的obj
return obj
class People(object,metaclass=Mymeta):
country='China'
def __init__(self,name,age):
self.name=name
self.age=age
def talk(self):
print('%s is talking' %self.name)
obj=People('egon',18)
print(obj.__dict__) #{'name': 'egon', 'age': 18}
#步骤四:
class Mymeta(type): #继承默认元类的一堆属性
def __init__(self,class_name,class_bases,class_dic):
if not class_name.istitle():
raise TypeError('类名首字母必须大写')
super(Mymeta,self).__init__(class_name,class_bases,class_dic)
def __call__(self, *args, **kwargs):
#self=People
print(self,args,kwargs) # ('egon', 18) {}
#1、调用self,即People下的函数__new__,在该函数内完成:1、产生空对象obj 2、初始化 3、返回obj
obj=self.__new__(self,*args,**kwargs)
#2、一定记得返回obj,因为实例化People(...)取得就是__call__的返回值
return obj
class People(object,metaclass=Mymeta):
country='China'
def __init__(self,name,age):
self.name=name
self.age=age
def talk(self):
print('%s is talking' %self.name)
def __new__(cls, *args, **kwargs):
obj=object.__new__(cls)
cls.__init__(obj,*args,**kwargs)
return obj
obj=People('egon',18)
print(obj.__dict__) #{'name': 'egon', 'age': 18}
#步骤五:基于元类实现单例模式,比如数据库对象,实例化时参数都一样,就没必要重复产生对象,浪费内存
class Mysql:
__instance=None
def __init__(self,host='127.0.0.1',port='3306'):
self.host=host
self.port=port
@classmethod
def singleton(cls,*args,**kwargs):
if not cls.__instance:
cls.__instance=cls(*args,**kwargs)
return cls.__instance
obj1=Mysql()
obj2=Mysql()
print(obj1 is obj2) #False
obj3=Mysql.singleton()
obj4=Mysql.singleton()
print(obj3 is obj4) #True
#应用:定制元类实现单例模式
class Mymeta(type):
def __init__(self,name,bases,dic): #定义类Mysql时就触发
self.__instance=None
super().__init__(name,bases,dic)
def __call__(self, *args, **kwargs): #Mysql(...)时触发
if not self.__instance:
self.__instance=object.__new__(self) #产生对象
self.__init__(self.__instance,*args,**kwargs) #初始化对象
#上述两步可以合成下面一步
# self.__instance=super().__call__(*args,**kwargs)
return self.__instance
class Mysql(metaclass=Mymeta):
def __init__(self,host='127.0.0.1',port='3306'):
self.host=host
self.port=port
obj1=Mysql()
obj2=Mysql()
print(obj1 is obj2)
练习一:在元类中控制把自定义类的数据属性都变成大写
class Mymetaclass(type):
def __new__(cls,name,bases,attrs):
update_attrs={}
for k,v in attrs.items():
if not callable(v) and not k.startswith('__'):
update_attrs[k.upper()]=v
else:
update_attrs[k]=v
return type.__new__(cls,name,bases,update_attrs)
class Chinese(metaclass=Mymetaclass):
country='China'
tag='Legend of the Dragon' #龙的传人
def walk(self):
print('%s is walking' %self.name)
print(Chinese.__dict__)
'''
{'__module__': '__main__',
'COUNTRY': 'China',
'TAG': 'Legend of the Dragon',
'walk': ,
'__dict__': ,
'__weakref__': ,
'__doc__': None}
'''
练习二:在元类中控制自定义的类无需__init__方法
1.元类帮其完成创建对象,以及初始化操作;
2.要求实例化时传参必须为关键字形式,否则抛出异常TypeError: must use keyword argument
3.key作为用户自定义类产生对象的属性,且所有属性变成大写
class Mymetaclass(type):
# def __new__(cls,name,bases,attrs):
# update_attrs={}
# for k,v in attrs.items():
# if not callable(v) and not k.startswith('__'):
# update_attrs[k.upper()]=v
# else:
# update_attrs[k]=v
# return type.__new__(cls,name,bases,update_attrs)
def __call__(self, *args, **kwargs):
if args:
raise TypeError('must use keyword argument for key function')
obj = object.__new__(self) #创建对象,self为类Foo
for k,v in kwargs.items():
obj.__dict__[k.upper()]=v
return obj
class Chinese(metaclass=Mymetaclass):
country='China'
tag='Legend of the Dragon' #龙的传人
def walk(self):
print('%s is walking' %self.name)
p=Chinese(name='egon',age=18,sex='male')
print(p.__dict__)
免责声明: 一切资料仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。资料来自网络,版权争议与本人无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我联系处理。
更===多===课程====请====加===v===信=== a518958666 基于SpringCloud 微服务架构 广告系统设计与实现 系统学习docker docker前后端分离实战 Docker+Kubernetes(k8s)微服务容器化实战 Go语言实战抽奖系统 Go语言开发分布式任务调度 轻松搞定高性能Crontab 20小时快速入门go语言 Java从零到企业级电商项目实战 SSM主流框架入门与综合项目实战 Socket网络编程进阶与实战
0. 基于Python玩转人工智能最火框架 TensorFlow应用实践 1. webapp书城开发 2. 组件方式开发 Web App全站 3. 前端到后台ThinkPHP开发整站 4. MySQL性能管理及架构设计 5. 响应式开发一招致胜 6. 掌握React Native技术转型随意切换 7. Yii 2.0开发一个仿京东商城平台 8. Python高效编程技巧实战 9. 快速开发轻量级App 10. 6小时 jQuery开发一个前端应用 11. Android架构师之路 网络层架构设计与实战 12. 程序猿的内功修炼,学好算法与数据结构 13. Vue.js高仿饿了么外卖App 1.0到2.0版本完美升级 14. Android 专项测试 Python篇 15. 微信小程序入门与实战 常用组件API开发技巧项目实战 16. Android 5.0+高级动画开发 矢量图动画 轨迹动画路径变换 17. Android自动化测试实战 Java篇 主流工具 框架 脚本 18. Python升级3.6 强力Django+杀手级Xadmin打造在线教育平台 19. 高性能可扩展MySQL数据库设计及架构优化 电商项目 20. 带领新手快速开发Android App 21. Angular JS 仿拉勾网 WebApp 开发移动端单页应用 22. 组件化封装思想实战Android App 23. React.js入门基础与案例开发 24. Yii 2.0进阶版 高级组件 优化京东平台 25. 双平台真实开发GitHub App React Native技术全面掌握 26. 玩转算法面试 leetcode题库分门别类详细解析 27. Thinkphp 5.0 仿百度糯米开发多商家电商平台 28. ThinkPHP5.0正式版第二季:实战开发企业站【完结】 29. 最容易上手的Vue 2.0入门实战教程 30. 聚焦Python分布式爬虫必学框架Scrapy 打造搜索引擎 31. Angular 4.0从入门到实战 打造股票管理网站 32. Java Spring带前后端开发完整电商平台 33. Node.js项目线上服务器部署与发布 34. Java大牛 带你从0到上线开发企业级电商项目 35. ThinkPHP 5.0开发微信小程序商场打通全栈项目架构 36. ES6零基础教学 解析彩票项目 37. React高级实战 打造大众点评 WebApp 38. BAT大咖助力 全面升级Android面试 39. 全程MVP手把手 打造IM即时通讯Android APP 40. 微信服务号+Yii 2.0构建商城系统全栈应用 41. 机器学习入门 Scikit-learn实现经典小案例 42. 腾讯大牛亲授 Web 前后端漏洞分析与防御技巧 43. IT段子手详解MyBatis遇到Spring 秒学Java SSM开发大众点评 难度中级 44. Vue 2.0 高级实战-开发移动端音乐 WebApp 45. 全新升级 Kotlin系统入门与进阶 46. 对接真实数据 从0开发前后端分离企业级上线项目 47. Android应用发展趋势必备武器 热修复与插件化 48. Laravel 快速开发简书 49. 以慕课网日志分析为例 进入大数据 Spark SQL 的世界 50. Get全栈技能点 Vue2.0/Node.js/MongoDB 打造商城系统 51. Python操作三大主流数据库 52. 前端JavaScript面试技巧 53. Java SSM快速开发仿慕课网在线教育平台 54. Android通用框架设计与完整电商APP开发 55. Spring Boot企业微信点餐系统 56. 开发微信全家桶项目 Vue/Node/MongoDB高级技术栈全覆盖 57. Web自动化测试 Selenium基础到企业应用 58. 高性能的 PHP API 接口开发 59. 企业级刚需Nginx入门,全面掌握Nginx配置+快速搭建高可用架构 60. Angular 打造企业级协作平台 61. Python Flask 构建微电影视频网站 62. Spring Boot带前后端 渐进式开发企业级博客系统 63. 从零开发Android视频点播APP 64. 前端跳槽面试必备技巧 65. 10小时入门大数据 66. 让你页面速度飞起来 Web前端性能优化 67. Google面试官亲授 升级Java面试 68. LoadRunner 工具使用 企业级性能测试实战 69. 360大牛带你横扫PHP职场 全面解读PHP面试 70. Python前后端分离开发Vue+Django REST framework实战 71. Spring Security技术栈开发企业级认证与授权 72. PHP开发高可用高安全App后端 73. 看得见的算法 7个经典应用诠释算法精髓 74. 全网最热Python3入门+进阶 更快上手实际开发 75. Android互动直播APP开发 76. JMeter 深入进阶性能测试体系 各领域企业实战 77. Node.js入门到企业Web开发中的应用 78. SSM到Spring Boot 从零开发校园商铺平台 79. 深度学习之神经网络核心原理与算法 80. BAT大厂APP架构演进实践与优化之路 81. PHP秒杀系统 高并发高性能的极致挑战 82. Java开发企业级权限管理系统 83. Redux+React Router+Node.js全栈开发 84. Redis从入门到高可用,分布式实践 85. ES6+ 开发电商网站的账号体系 JS SDK 86. Spark Streaming实时流处理项目实战 87. 快速上手Linux 玩转典型应用 88. Python接口测试框架实战与自动化进阶 89. Python3数据科学入门与实战 90. Android高级面试 10大开源框架源码解析 91. 移动端App UI 设计入门与实战 92. 精通高级RxJava 2响应式编程思想 93. Java企业级电商项目架构演进之路 Tomcat集群与Redis分布式 94. Webpack + React全栈工程架构项目实战精讲 95. 快速上手Ionic3 多平台开发企业级问答社区 96. 全面系统讲解CSS 工作应用+面试一步搞定 97. 跨平台混编框架 MUI 仿豆瓣电影 APP 98. Kotlin打造完整电商APP 模块化+MVP+主流框架 99. BAT大牛亲授 基于ElasticSearch的搜房网实战 100. Python3入门机器学习 经典算法与应用 101. Java秒杀系统方案优化 高性能高并发实战 102. 四大维度解锁 Webpack3.0 工具全技能 103. 手工测试企业项目实践及面试提升 104. 基于Storm构建实时热力分布项目实战 105. Java深入微服务原理改造房产销售平台 106. 全网稀缺Python自动化运维项目实战 107. 前端成长必经之路-组件化思维与技巧 108. 基于Python玩转人工智能最火框架 TensorFlow应用实践 109. Koa2框架从0开始构建预告片网站 110. React16+React-Router4 从零打造企业级电商后台管理系统 111. Google资深工程师深度讲解Go语言 112. 微信小游戏入门与实战 刷爆朋友圈 113. Elastic Stack从入门到实践 114. Python移动自动化测试面试 115. Python3数据分析与挖掘建模实战 116. Tomcat+Memcached/Redis集群 构建高可用解决方案 117. 系统学习Docker 践行DevOps理念 118. Spring Cloud微服务实战 119. 揭秘一线互联网企业 前端JavaScript高级面试 120. OpenCV+TensorFlow 入门人工智能图像处理 121. 基于Golang协程实现流量统计系统 122. 移动端自动化测试Appium 从入门到项目实战Python版 123. UI动效设计从入门到实战 PC与移动界面设计必学 124. Java并发编程与高并发解决方案 125. Vue核心技术 Vue+Vue-Router+Vuex+SSR实战精讲 126. 韩天峰力荐 Swoole入门到实战打造高性能赛事直播平台 127. Docker+Kubernetes(k8s)微服务容器化实践 128. Python Flask高级编程 129. ZooKeeper分布式专题与Dubbo微服务入门 130. App界面设计利器Sketch 精选案例合集 131. Python高级编程和异步IO并发编程 132. 新浪微博资深大牛全方位剖析 iOS 高级面试 133. Vue2.5开发去哪儿网App 从零基础入门到实战项目 134. 最全面的Java接口自动化测试实战 135. HBase+SpringBoot实战分布式文件存储 136. Gradle3.0自动化项目构建技术精讲+实战 137. 玩转数据结构 从入门到进阶 138. MyCAT+MySQL 搭建高可用企业级数据库集群 139. 验证码图像识别,快速掌握TensorFlow模型构建与开发 140. SpringBoot2.0不容错过的新特性 WebFlux响应式编程 141. 响应式开发一招致胜 142. jquery源码分析 143. AngularJS全栈开发知乎 144. 揭秘一线互联网企业 前端JavaScript高级面试 145. JavaScript版 数据结构与算法 146. Koa2 实现电影微信公众号前后端开发 147. Koa2+Nodejs+MongoDb 入门实战视频教程 148. Node.js 从零开发 web server博客项目 前端晋升全栈工程师必备 149. Vue.js 源码全方位深入解析 150. Vue核心技术 Vue+Vue-Router+Vuex+SSR实战精讲 151. Vue全家桶+SSR+Koa2全栈开发美团网 152. 飞速上手的跨平台App开发 153. 前端JS基础面试技巧 154. 前端跳槽面试必备技巧 155. 让你页面速度飞起来 Web前端性能优化 156. 微信小程序商城构建全栈应用 157. 移动Web APP开发之实战美团外卖 158. Thinkphp 5.0 仿百度糯米开发多商家电商平台 159. ThinkPHP5.0正式版第二季:实战开发企业站 160. ThinkPHP 5.0开发微信小程序商场打通全栈项目架构 161. 前端到后台ThinkPHP开发整站 162. PHP从基础语法到原生项目开发 163. PHP高性能 高价值的PHP API 164. 360大牛全面解读PHP面试 165. PHP开发高可用高安全App后端 166. PHP秒杀系统 高并发高性能的极致挑战 167. Swoole入门到实战打造高性能赛事直播平台 168. YII 2.0开发一个仿京东商城平台
...... ...... 更===多===课程====请====加===v===信=== a518958666 ╭══════════════════════════════════════════╮ ║ ║ 说明:教程版权归原作者所有,本人只是负责搜集整理,本人 ║ ║ 不承担任何技术及版权问题。本人分享的任何教程仅提 ║ ║ 供学习参考,不得用于商业用途,请在下载后在24小时 ║ ║ 内删除。 ║ ║ ║ ║ 1.请遵守中华人民共和国相关法律、条例 ║ ║ 2.本人提供的各类视频教程仅供研究学习,本人不承担观看 ║ ║ 本教程后造成的一切后果 ║ ║ 3.本人不保证提供的教程十分安全或是完全可用,请下载后 ║ ║ 自行检查 ║ ║ 4.本人提供的教程均为网上搜集,如果该程序涉及 ║ ║ 或侵害到您的版权请立即写信通知我们。 ║ ║ 5.如不同意以上声明,请立即删除,不要使用,谢谢合作 ║ ║ ║ ╰═════════════════════════════════════════╯