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
day24 反射\元类相关推荐
- python 元类的call_python3 全栈开发 - 内置函数补充, 反射, 元类,__str__,__del__,exec,type,__call__方法...
python3 全栈开发 - 内置函数补充, 反射, 元类,__str__,__del__,exec,type,__call__方法 一, 内置函数补充 1,isinstance(obj,cls)检查 ...
- python元类、反射及双线方法
元类 print(type('abc')) print(type(True)) print(type(100)) print(type([1, 2, 3])) print(type({'name': ...
- python面试题~反射,元类,单例
1 什么是反射?以及应用场景? test.py def f1():print('f1') def f2():print('f2') def f3():print('f3') def f4():prin ...
- delstr函数python_python3全栈开发-内置函数补充,反射,元类,__str__,__del__,exec,type,__call__方法详解...
一.内置函数补充 1.isinstance(obj,cls)检查是否obj是否是类 cls 的对象 classFoo(object):passobj=Foo()print(isinstance(obj ...
- 面向对象之反射,元类
一.反射 1.什么是反射 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问,检测和修改它本身状态或行为的一种能能力(自省). 2.python中的反射 反射是所有面向对象编程语言都 ...
- Python 第二十六章 面向对象 元类+反射+双下方法
元类 class A:pass obj = A() print(type('abc')) print(type([1,2,3])) print(type((22,33)))# type 获取对象从属于 ...
- Python学习,元类type 反射 函数与方法 双下方法
1.元类type type 获取对象从属于的类 python 中 一切皆对象, 类在某种意义上也是一个对象, python中自己定义的类, 以及大部分内置类, 都是由type元类(构建类)实例化得来的 ...
- 29 反射 内置方法 元类
反射 内置方法 元类 1 反射 1.1 什么是反射机制 Python属于动态语言,即程序执行变量定义语句时才确定变量的类型. 反射机制指的是在程序的运行过程中能够动态地获取对象信息以及动态地调用对象功 ...
- python:改良廖雪峰的使用元类自定义ORM
概要 本文仅仅是对廖雪峰老师的使用元类自定义ORM进行改进,并不是要创建一个ORM框架 编写field class Field(object):def __init__(self, column_ty ...
最新文章
- Linux 忘记密码如何登陆—续篇2救援模式
- android: 发送自定义广播
- ArrayBlockingQueue中的方法
- windows下使用cpanm进行模块安装
- LeetCode 572. 另一个树的子树 思考分析
- 【操作系统复习】操作系统的发展与分类
- C语言/C++编程的起源与能力学习
- @程序员们,公司 2 年不涨薪我究竟该怎么办?
- 如何截取滚动的页面,窗口
- sass函数:@function
- JPA、JTA、XA相关索引
- app源码+php+l,android商城APP全套源码(服务端+客户端)
- 一篇文章彻底搞懂什么是电厂智能巡检系统?
- 终端上网_TP-Link企业路由器IPv6上网配置指导
- 来成都旅游,千万不要做的22件事!
- 中国遥感数据查询网址
- LeetCode久不久来一题系列之Add Two Numbers
- hdwiki v5.1存在SQL注入导致可下载任意文件
- P01914100尹自杨
- golang lint
热门文章
- 小程序背景图满屏_竞赛答题小程序
- java jstack 工具_java命令之jstack工具
- 二十二、PHP框架Laravel学习笔记——集合的使用
- python的GUI编程和tkinter学习笔记——第一个GUI程序
- LeetCode 1955. 统计特殊子序列的数目
- 天池 在线编程 最长AB子串(哈希)
- LeetCode 254. 因子的组合(回溯)*
- 剑指Offer - 面试题65. 不用加减乘除做加法(位运算,要看哦)
- LeetCode 42. 接雨水(双指针、单调栈)
- LeetCode 33. 搜索旋转排序数组(二分查找)