day24 反射\元类

反射 reflect

# 什么是反射, 其实是反省,自省的意思,反射指的是一个对象应该具备,可以检测,修改,增加自身属性的能力.
# 反射就是通过字符串操作属性,涉及的四个函数,这四个函数就是普通的内置函数,没有双下划綫,与print等等没有区别.

案例

hasattr getattr setattr delattr p = Person("jack",18,"man")# if hasattr(p,"name"): # 1.判断某个对象是否存在某个属性
#     print(getattr(p,"names",None)) # 2.从对象中取出属性,第三个值位默认值 当属性不存在是返回默认值# 3.为对象添加新的属性
setattr(p,"id","123")
print(p.id)# 4.从对象中删除属性
delattr(p,"id")
print(p.id)

 使用场景:

# 反射其实就是对属性的增删改查,但是如果直接使用内置的__dict__来操作,语法繁琐,不好理解
# 另外一个最主要的问题是,如果对象不是我自己写的是另一方提供的,我就必须判断这个对象是否满足的要求,也就是是否我需要的属性和方法

 

框架设计方式:

框架代码:

# 反射被称为框架的基石,为什么?
因为框架的设计者,不可能提前知道你的对象到底是怎么设计的,所以你提供给框架的对象 必须通过判断验证之后才能正常使用,判断验证就是反射要做的事情,
当然通过__dict__也是可以实现的, 其实这些方法也就是对__dict__的操作进行了封装
需求:要实现一个用于处理用户的终端指令的小框架,框架就是已经实现了最基础的构架,就是所有项目都一样的部分

 

实例

import plugins# 框架已经实现的部分
def run(plugin):while True:cmd = input("请输入指令:")if cmd == "exit":break# 因为无法确定框架使用者是否传入正确的对象所以需要使用反射来检测# 判断对象是否具备处理这个指令的方法if hasattr(plugin,cmd):# 取出对应方法方法func = getattr(plugin,cmd)func() # 执行方法处理指令else:print("该指令不受支持...")print("see you la la!")# 创建一个插件对象 调用框架来使用它
# wincmd = plugins.WinCMD()
# 框架之外的部分就有自定义对象来完成
linux = plugins.LinuxCMD()
run(linux)

插件部分:

class WinCMD:def cd(self):print("wincmd 切换目录....")def delete(self):print("wincmd 要不要删库跑路?")def dir(self):print("wincmd 列出所有文件....")class LinuxCMD:def cd(self):print("Linuxcmd 切换目录....")def rm(self):print("Linuxcmd 要不要删库跑路?")def ls(self):print("Linuxcmd 列出所有文件....")

上述框架代码中,写死了必须使用某个类,这是不合理的,因为无法提前知道对方的类在什么地方,以及类叫什么

所以我们应该为框架的使用者提供一个配置文件,要求对方将累的信息写入配置文件,然后框架自己去加载需要的模块

框架代码:

import importlib
import settings# 框架已经实现的部分
def run(plugin):while True:cmd = input("请输入指令:")if cmd == "exit":break# 因为无法确定框架使用者是否传入正确的对象所以需要使用反射来检测# 判断对象是否具备处理这个指令的方法if hasattr(plugin,cmd):# 取出对应方法方法func = getattr(plugin,cmd)func() # 执行方法处理指令else:print("该指令不受支持...")print("see you la la!")# 创建一个插件对象 调用框架来使用它
# wincmd = plugins.WinCMD()
# 框架之外的部分就有自定义对象来完成# 框架 得根据配置文件拿到需要的类

path = settings.CLASS_PATH
# 从配置中单独拿出来 模块路径和 类名称
module_path,class_name = path.rsplit(".",1)
#拿到模块
mk = importlib.import_module(module_path)
# 拿到类
cls = getattr(mk,class_name)
# 实例化对象
obj = cls()
#调用框架
run(obj)

如此一来,框架就与实现代码彻底解耦了,只剩下配置文件

 

元类 metaclass 

# 元类是什么,用于创建类的类,万物皆对象,类当然也是对象 ,对象是通过类实例化产生的,如果类也是对象的话,必然类对象也是有另一个类实例化产生的,默认情况下所有类的元类都是type.

 

代码

class Person:pass
p = Person()print(type(p))
print(type(Person))Person类是通过type类实例化产生的 

学习元类的目的:

# 高度的自定义一个类,例如控制类的名字必须以大驼峰的方式来书写
类也是对象,也有自己的类,
我们的需求是创建类对象做一些限制
想到了初始化方法 我们只要找到类对象的类(元类),覆盖其中 init方法就能实现需求
当然我们不能修改源代码,所以应该继承type来编写自己的元类,同时覆盖init来完成需求

 

运用

"""
只要继承了type 那么这个类就变成了一个元类
"""
# 定义了一个元类
class MyType(type):def __init__(self,clss_name,bases,dict):super().__init__(clss_name,bases,dict)print(clss_name,bases,dict)if not clss_name.istitle():raise Exception("你丫的 类名不会写...")# 为pig类指定了元类为MyType
class Pig(metaclass=MyType):passclass Duck(metaclass=MyType):pass

元类中call方法

# 当你调用类对象时会自动珍惜元类中的__call__方法 ,并将这个类本身作为第一个参数传入,以及后面的一堆参数

覆盖元类中的call之后,这个类就无法产生对象,必须调用super().__call__来完成对象的创建 
并返回其返回值

使用场景:

当你想要控制对象的创建过程时,就覆盖call方法
当你想要控制类的创建过程时,就覆盖init方法

 

案例:

实现将对象的所有属性名称转为大写

lass MyType(type):def __call__(self, *args, **kwargs):new_args = []for a in args:new_args.append(a.upper())print(new_args)print(kwargs)return super().__call__(*new_args,**kwargs)class Person(metaclass=MyType):def __init__(self,name,gender):self.name = nameself.gender = genderp = Person(name="jack",gender="woman")
print(p.name)
print(p.gender)

注意:一旦覆盖了call必须调用父类的call方法来产生对象并返回这个对象 

补充new方法

# 当你要创建类对象时,会首先执行元类中的__new__方法,拿到一个空对象,然后会自动调用__init__来对这个类进行初始化操作 
注意:,如果你覆盖了该方法则必须保证,new方法必须有返回值且必须是,对应的类对象

 

测试

class Meta(type):def __new__(cls, *args, **kwargs):print(cls) # 元类自己print(args) # 创建类需要的几个参数  类名,基类,名称空间print(kwargs) #空的 print("new run")# return super().__new__(cls,*args,**kwargs)obj = type.__new__(cls,*args,**kwargs)return objdef __init__(self,a,b,c):super().__init__(a,b,c)print("init run")
class A(metaclass=Meta):pass
print(A)

 

总结new方法和init 都可以实现控制类的创建过程,init更简单

单例设计模式

```

设计模式?用于解决某种固定问题的套路
例如:MVCMTV等
单例:指的是一个类产生一个对象
为什么要使用单例:单例是为了节省 资源,当一个类的所有对象属性全部相同时,则没有必要创建多个对象

元类实现:

# 单例n元类
class Single(type):def __call__(self, *args, **kwargs):if hasattr(self,"obj"): #判断是否存在已经有的对象return getattr(self,"obj") # 有就返回
obj = super().__call__(*args,**kwargs) # 没有则创建print("new 了")self.obj = obj # 并存入类中return objclass Student(metaclass=Single):def __init__(self,name):self.name = nameclass Person(metaclass=Single):pass# 只会创建一个对象
Person()
Person()

 

 

 

aa

 

转载于:https://www.cnblogs.com/Ryan-Yuan/p/11272612.html

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

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

相关文章

212页PPT详解MEMS微传感器的工作原理(深入全面!)

来源:传感器专家网本文是关于MEMS微传感器的工作原理最全面的内容,分为两部分,共计212页PPT内容。主要讲解了MEMS微传感器的概念、分类,基本敏感原理介绍,MEMS微传感器实例、MEMS微执行器分类、基本致动方式介绍、微执…

C++开发WPF,开发环境配置

C开发WPF,开发环境配置 操作系统:Windows XP SP2, Windwos Vista开发工具:Visual Studio 2005,Expression BlendSDK:.NET Framework 3.0或以上不需要其它的了,比C#开发WPF少了一些。但是需要自己手工打造一些代码,也有不少乐趣在里…

Lucene-01 全文检索基本介绍

文章目录课程计划什么是全文检索数据分类结构化数据搜索非结构化数据查询方法如何实现全文检索全文检索的应用场景Lucene实现全文检索的流程索引和搜索流程图创建索引获得原始文档创建文档对象分析文档创建索引查询索引用户查询接口创建查询执行查询渲染结果全文检索技术Lucene…

为何生命进化的方向是衰老,而不是永生?

来源:科学的乐园永生似乎是全世界各种文化里都在追求的一种状态,为此古代的人们发展出了宗教,用来寄托死亡带来的遗憾。而人类也在想尽一切办法抑制衰老,各种护肤品、保养品相继问世。当然人类在这条追求永生的道路上也吃了很多苦…

NPOI “发现 中的部分内容有问题,是否要恢复此工作薄的内容?如果信任此工作薄的来源。。。”的问题的解决方法...

网上说的方法是调整Sheet可见和顺序:https://blog.csdn.net/hulihui/article/details/21196951 stackoverflow给出的解释是:单元格存储数字,字符串格式不对应造成的,https://stackoverflow.com/questions/15675710/opening-excel-…

vue-day02-vue常用特性

文章目录Vue常用特性表单基本操作表单修饰符自定义指令Vue.directive 注册全局指令Vue.directive 注册全局指令 带参数自定义指令局部指令计算属性 computed侦听器 watch过滤器过滤器中传递参数生命周期常用的 钩子函数数组变异方法替换数组动态数组响应式数据图书列表案例1、 …

2022年,哪些科技趋势将持续改变世界?这里有一份来自百度研究院的预测

来源:数学中国编辑部弹指之间,2021 年已经远去。这一年,新冠疫情全球经济和社会生活带来诸多挑战,同时,科学技术的力量得以持续显现。技术进步与产业发展的速度进一步加快,数字技术、智能技术为人们的生活带…

CSS每日学习笔记(1)

7.30.2019 1.CSS 文本属性 属性 描述 color 设置文本颜色 direction 设置文本方向。 line-height 设置行高。 letter-spacing 设置字符间距。 text-align 对齐元素中的文本。 text-decoration 向文本添加修饰。 text-indent 缩进元素中文本的首行。 text-shado…

vue-day03-vue组件化开发

文章目录组件组件注册全局注册组件基础用组件注意事项局部注册Vue 调试工具Vue组件之间传值父组件向子组件传值子组件向父组件传值兄弟之间的传递组件插槽匿名插槽具名插槽作用域插槽购物车案例1. 实现组件化布局2、实现 标题和结算功能组件3. 实现列表组件删除功能4. 实现组件…

智源发布《人工智能的认知神经基础白皮书》,一览“AI×脑科学”前沿

图. 智源研究院《人工智能的认知神经基础白皮书》(2021年)来源:智源研究院智源研究院发布 2021 年度《人工智能的认知神经基础白皮书》,兼具专业性与科普性,是人工智能学者探寻“AI脑科学”交叉学科研发创新的导览之作…

解决设置了display:none的元素,会先展示再隐藏

问题:元素明明设置了display:none,但是在刷新页面的时候却会先显示了出来,然后才会隐藏,实现display:none 原因:由于元素渲染的时候,样式还没有应用上去,导致的 解决办法:使用内联样…

Java : Hibernate 动态+分页+自定义字段+自定义实体类查询

// 组合查询public List<ListBookDTO> listSetDSL(PublishingHouse publishingHouse,Integer minDiscount, Integer maxDiscount, Integer minStocks, Integer maxStocks, Integer page, Integer pageSize) { CriteriaBuilder builder em.getCriteriaBuilder(); /…

VR视觉健康标准在穗发布 专家:VR使用不要超过45分钟

来源&#xff1a;VR每日必看近期&#xff0c;“元宇宙”新兴概念备受关注&#xff0c;虚拟现实&#xff08;下称“VR”&#xff09;技术也被国内外媒体评为“第四次工业革命的钥匙之一”。但是&#xff0c;有不少人对VR眼镜等设备感到担忧&#xff1a;使用它会损害视力吗&#…

vue-day04-vue前端交互

文章目录接口调用方式异步promise基于Promise发送Ajax请求Promise 基本API实例方法.then().catch().finally()静态方法.all().race()fetch概览fetch请求参数&#xff08;图片记录&#xff09;fetch API 中的 HTTP 请求fetchAPI 中 响应格式axiosaxios基础用法axios的响应结果ax…

系统上线日期被老外逼得延期了!

在我自己的印象中&#xff0c;一直以来&#xff0c;以为老外做事是比较严禁的&#xff0c;而且是比较高效的&#xff01;没有想到&#xff0c;居然完全不是这么回事&#xff01; a) 不听从中方任何建议&#xff0c;一意孤行&#xff01; b) 事实证明他们的错误之后&#xff0c;…

用数学范畴定义生命的尝试

来源&#xff1a;CreateAMind介绍一篇关于生命构建的论文Polynomial Life: the Structure of Adaptive Systems Toby St. Clere Smithe Topos Institute tobytopos.institute关键词&#xff1a;精确地形式化概念&#xff1b;是什么赋予了物理系统生命&#xff1b;贝叶斯、 信念…

git-从入门到熟悉

文章目录Git历史Git与svn对比SvnGitgit工作流程Git的安装软件下载软件安装安装git for windows安装TortoiseGit安装中文语言包使用git管理文件版本创建版本库使用GitBash使用TortoiseGit添加文件添加文件过程工作区和暂存区修改文件提交修改查看修改历史差异比较还原修改删除文…

java之spring mvc之拦截器

1. springmvc 中的拦截器是由实现 HandlerInterceptor 或者继承 HandlerInterceptorAdapter 来实现的。 2. 自定义实现一个拦截器的步骤&#xff1a; a). 定义一个实现 HandlerInterceptor 接口 的类 public class MyInterceptor implements HandlerInterceptor{/*** 在处理方法…

王飞跃谈正来临的第五次工业革命:“未来一定有多个平行的你”

来源&#xff1a;来源&#xff1a;南方周末王飞跃&#xff0c;中国自动化学会副理事长兼秘书长&#xff0c;中科院复杂系统管理与控制国家重点实验室主任。其主要研究领域为智能科学、社会计算、平行系统、知识自动化和复杂系统的建模、分析与管理&#xff0c;是智能控制方面的…

JS_01JavaScript基础笔记

文章目录JavaScript简介JavaScript简介JavaScript发展史JavaScript基础语法JavaScript_语法_与html结合方式JavaScript_语法_注释&数据类型JavaScript_语法_变量JavaScript_语法_变量_typeofJavaScript_语法_一元运算符JS-基本对象FunctionArrayDateMathRegExpGlobalJavaSc…