24.反射,元类,call new 单例
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1.反射 2.元类 1.反射 reflect 什么是反射 ,其实是反省,自省的意思 反射指的是一个对象应该具备,可以检测,修改,增加自身属性的能力 反射就是通过字符串操作属性 涉及的四个函数,这四个函数就是普通的内置函数,没有双下划綫,与print 等等没有区别 hasattr #判断某个对象是否存在某个属性 getattr # 从对象中取出属性,第三个值位默认值 当属性不存在是返回默认值 setattr # 为对象添加新的属性 delattr # 从对象中删除属性 使用场景: 反射其实就是对属性的增删改查,但是如果直接使用内置的__dict__来操作,语法繁琐,不好理解 另一个最主要的问题是,如果对象不是我自己写的是另一方提供的,我就必须判断这个对象是否满足的要求,也就是是否我需要的属性和方法 反射的应用案例: # 2.反射的应用案例.py 4.元类 metaclass 元类是什么,用来创建类的类 万物皆是对象 ,类当然也是对象 对象是通过类实例化产生的,如果类也是对象的话,必然类对象也是有另一个类实例化产生的 默认情况下所有类的元类都是type """直接调用type类来产生类对象""" """ 一个类的三个基本组成 1.类的名字(字符类型) 2.类的父类们(是一个元组或者列表) 3.类的名称空间(字典类型) 验证:4.类的类是谁.py 5.学习元类的目的: 高度的自定义一个类,,例如控制类的名字必须以大驼峰的方式来书写 类也是对象,也有自己的类, 我们的需求是创建类对象做一些限制 想到了初始化方法 我们只要找到类对象的类(元类),覆盖其中 init方法就能实现需求 当然我们不能修改源代码,所以应该继承type来编写自己的元类,同时覆盖init来完成需求 代码: 5.自己来定义元类.py 6.元类中call 的方法 当你调用类对象时会自动执行元类中的__call__ 方法,并将这个类本身作为第一个参数传入,以及后面的一堆参数 覆盖元类 call 后 这个类就无法产生对象,必须调用 super().__call__来完成对象的创建 并返回其返回值 使用场景: 1.当你想要控制对象创建过程时,就覆盖call方法 2.当你想要控制类的创建过程时就覆盖init方法 案例:6.call方法的应用.py 7.元类中new方法 当你要创建类对象时,会首先执行元类中的__new__方法,拿到一个空对象,然后会自动调用__init__来对这个类进行初始化操作 注意:,如果你覆盖了该方法则必须保证,new方法必须有返回值且必须是,对应的类对象 测试:7.元类的new方法.py 总结new方法和init 都可以实现控制类的创建过程,init更简单 8.单例设计模式
lib/plugins.py
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 列出所有文件....")
settingss.py
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
"""""" """该文件作为框架的配置文件""" """作为框架使用者 在配置文件中指定你配合框架的类是哪个 """ CLASS_PATH = "libs.plugins.LinuxCMD"
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import importlib import settings """ 上述框架代码中 写死了必须使用某个类,这是不合理的,因为无法提前知道对方的类在什么地方 以及类叫什么 所以我们应该为框架的使用者提供一个配置文件,要求对方将累的信息写入配置文件 然后框架自己去加载需要的模块 最后的框架代码: """ # 框架已经实现的部分 def run(plugin): while True: cmd = input("请输入指令:").strip() if cmd == 'exit': break # 因为无法确定框架使用者是否传入正确的对象,所以需要使用反射来检测 # 判断对象是否具备处理这个指令的方法 if hasattr(plugin,cmd): # 取出对应方法 func = getattr(plugin,cmd) func() # 执行方法处理指令 else: print("该指令不受支持...") print("see you la la") # 创建一个插件对象 调用框架来使用它 # wincmd = settings.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) """ 如此一来,框架就与实现代码彻底解耦了,只剩下配置文件 """
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Person: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender p = Person("jack",18,"man") print(p.name) # jack "hasattr 判断某个对象是否存在某个属性" print(hasattr(p,"name")) # True "getattr 从对象中取出属性,第三个值为默认值.当属性不存在时返回默认值" if hasattr(p,"name"): print(getattr(p,"names",None)) # None print(getattr(p,"gender",None)) # man "setattr 为对象添加新的属性" setattr(p,"id_card","123") # (对象 ,k,v) print(p.__dict__) """ {'name': 'jack', 'age': 18, 'gender': 'man', 'id_card': '123'} """ "delattr 从对象中删除属性" delattr(p,"id_card") print(p.__dict__) # {'name': 'jack', 'age': 18, 'gender': 'man'}
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import importlib import settings """ 上述框架代码中 写死了必须使用某个类,这是不合理的,因为无法提前知道对方的类在什么地方 以及类叫什么 所以我们应该为框架的使用者提供一个配置文件,要求对方将累的信息写入配置文件 然后框架自己去加载需要的模块 最后的框架代码: """ # 框架已经实现的部分 def run(plugin): while True: cmd = input("请输入指令:").strip() if cmd == 'exit': break # 因为无法确定框架使用者是否传入正确的对象,所以需要使用反射来检测 # 判断对象是否具备处理这个指令的方法 if hasattr(plugin,cmd): # 取出对应方法 func = getattr(plugin,cmd) func() # 执行方法处理指令 else: print("该指令不受支持...") print("see you la la") # 创建一个插件对象 调用框架来使用它 # wincmd = settings.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) """ 如此一来,框架就与实现代码彻底解耦了,只剩下配置文件 """
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
"""""" """ 在框架设计中 我们不可能提前知道 框架的用户要提供类相关的信息 """ import importlib import abc "拿到模块 根据模块的路径" p1 = importlib.import_module("libs.plugins") print(p1) "从模块中取出来" cls = getattr(p1,"WinCMD") print(cls) "实例化产生对象" obj = cls() obj.cd() """ <module 'libs.plugins' from 'D:\\面试整理\\重新开始\\6.面向对象(20-24)\\24.反射,元类,call new 单例\\libs\\plugins.py'> <class 'libs.plugins.WinCMD'> wincmd 切换目录.... """
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# # # class Person(object): # name = "123" # pass # # # p = Person() # # # print(type(p))# <class '__main__.Person'> # print(type(Person)) # <class 'type'> # class Student: # pass # print(type(Student)) """""" """直接调用type类来产生类对象""" """ 一个类的三个基本组成 1.类的名字(字符类型) 2.类的父类们(是一个元组或者列表) 3.类的名称空间(字典类型) """ cls_obj = type("dog",(),{}) print(cls_obj) # <class '__main__.dog'> class Person: pass
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
"""""" """ 只要继承了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): pass class Duck(metaclass=MyType): pass MyType('pig',(),{})
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
"""""" """ 想要把这个对象的所有属性变成大写 """ class MyMeta(type): def __init__(self,name,bases,dict): super().__init__(name,bases,dict) print("init run") def __call__(self, *args, **kwargs): print("元类 call run") print(self) print(args) print(kwargs) return super().__call__(*args,**kwargs) class Dog(metaclass=MyMeta): # Dog = MyMate("Dog",(),{}) def __init__(self,name): self.name = name def __call__(self, *args, **kwargs): print("call run") d = Dog("大黄") print(d.name) """ init run 元类 call run <class '__main__.Dog'> ('大黄',) {} 大黄 """ class 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 = name self.gender = gender p = Person(name="jack",gender="woman") print(p.name) print(p.gender) """ [] {'name': 'jack', 'gender': 'woman'} jack woman """ """ # 要求创建对象时必须以关键字参数形式来传参 # 覆盖元类的__call__ # 判断你有没有传非关键字参数 == 不能有位置参数 # 有就炸 """ class Mate(type): # def __call__(self, *args, **kwargs): # if args: # raise Exception("不好意思 不允许使用位置参数!") # return super().__call__(*args,**kwargs) # def __call__(self, *args, **kwargs): obj = object.__new__(self) # 创建一个空对象 self.__init__(obj,*args,**kwargs) # # 让对象去初始化 return obj class A(metaclass=Mate): def __init__(self,name): self.name = name a = A(name="jack") print(a.name)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 obj def __init__(self,a,b,c): super().__init__(a,b,c) print("init run") class A(metaclass=Meta): pass print(A) # a = A() """ <class '__main__.Meta'> ('A', (), {'__module__': '__main__', '__qualname__': 'A'}) {} new run init run <class '__main__.A'> """
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
"""""" """ 设计模式? 用于解决某种固定问题的套路 MVC MTV 单例:指的是一个类产生一个对象 为什么要使用单例: 单例是为了节省 资源,当一个类的所有对象属性全部相同时,则没有必要创建多个对象 """ class Person: def __init__(self,name,age): self.name = name self.age = age def say_hi(self): print("hello im %s" % self.name) # 用于获取对象的方法 @staticmethod def get_instance(): # 判断是否已经有了对象 if hasattr(Person,"obj"): return getattr(Person,"obj") obj = Person("jack",18) Person.obj = obj print("new 了") return obj p = Person.get_instance() p.say_hi() p2 = Person.get_instance() p2.say_hi() p3 = Person.get_instance() p3.say_hi() """ 单例元类 """ class Single(type): def __call__(self, *args, **kwargs): if hasattr(self,'obj'):# #判断是否存在已经有的对象 getattr(self,'obj')# 有就返回 obj = super().__call__(*args,**kwargs)# 没有则创建 print("new 了") self.obj = obj # 并存入类中 return obj class Student(metaclass=Single): def __init__(self,name): self.name = name class Person(metaclass=Single): pass # 只会创建一个对象 Person() Student("llx")
三层结构.png