zoukankan      html  css  js  c++  java
  • 面向对象高级 1.反射 2.元类 # 24

    面向对象高级
    1.反射
    1 """"""
    2 """
    3 该文件作为框架的配置文件
    4 
    5     作为框架使用者 ,
    6     在配置文件中指定你配合框架的类是哪个
    7 """
    8 CLASS_PATH = "libs.plugins.LinuxCMD"
    conf/settings.py
     1 # window系统终端
     2 class WinCMD:
     3     def cd(self):
     4         print('wincmd   切换目录...')
     5     def delete(self):
     6         print('wincmd 要不要删库跑路')
     7     def dir(self):
     8         print("wincmd 列出所有文件")
     9 # Linux系统终端
    10 class LinuxCMD:
    11     def cd(self):
    12         print("Linuxcmd 切换目录")
    13     def rm(self):
    14         print("Linux 要不要删库跑路")
    15     def ls(self):
    16         print("Linuxcmd 列出所有文件")
    libs/plugins.py
     1 """"""
     2 """
     3 面向对象高级
     4 
     5 1.反射 reflect
     6     什么是反射,其实就是反省,自省的意思
     7     
     8     反射指的是一个对象应该具备,可以检测,修改增加自身属性的能力
     9     
    10     本质:反射就是通过字符串操作属性
    11     
    12     
    13 """
    14 """
    15 2.涉及的四个函数,
    16     这四个函数就是普通的内置函数,
    17     没有双下划綫,与print等等没有区别
    18 
    19     hasattr, 判断某个对象是否存在某个属性
    20     getattr,从对象中取出属性
    21     setattr,为对象添加新的属性
    22     delattr,从对象中删除属性
    23 """
    24 
    25 # 案例
    26 class Person:
    27     def __init__(self,name,age,money):
    28         self.name = name
    29         self.age = age
    30         self.money = money
    31 p = Person('llx','24','11111')
    32 # 1.hasattr, 判断某个对象是否存在某个属性
    33 print(hasattr(p,'name'))  # True
    34 # hasattr(对象,属性)
    35 # 2.getattr,从对象中取出属性 的值
    36 print(getattr(p,'name'))  # llx
    37 # getattr(对象,属性)
    38 # 3.setattr,为对象添加新的属性
    39 setattr(p,'number',20000)
    40 print(p.number)  # 20000
    41 # setattr(对象,属性,默认值)
    42 # 4.delattr,从对象中删除属性
    43 delattr(p,'name')
    44 print(p.name)  #  'Person' object has no attribute 'name'
    45 # delattr(对象,属性)
    46 
    47 """
    48 3.使用场景:
    49     反射其实就是对属性的增删改查,
    50     但是如果直接使用内置__dict__来操作,语法繁琐,不好理解
    51     
    52     另一个主要问题是:
    53         如果对象不是我自己写的,
    54         是另一方提供,
    55         我就必须判断这个对象是否满足要求,
    56         即:是否是我需要的属性和方法
    57 """
    1.反省即反射.py
     1 """"""
     2 """
     3 反射--框架的基石
     4 """
     5 """
     6 1.为什么?
     7     因为框架的设计者,不可能提前知道你的对象到底是怎么设计的
     8     所以你提供的框架对象必须经过判断验证之后才能正常使用
     9 
    10     判断验证就是反射要做的事情
    11     当然通过__dict__也是可以实现的,其实这些方法也就是对__dict__的操作进行了封装
    12 """
    13 """
    14 在框架设计中,我们不可能提前知道
    15 故:框架的用户要提供类相关的信息
    16 """
    17 # 代码如下
    18 # Python提供了importlib包作为标准库的一部分。目的就是提供Python中import语句的实现(以及__import__函数)。另外,importlib允许程序员创建他们自定义的对象,可用于引入过程(也称为importer)。
    19 
    20 # 1.写活代码框架
    21 # 导入库
    22 import importlib
    23 # 抽象类
    24 import abc
    25 
    26 # 1.拿到模块 根据模块的路径
    27 p1 = importlib.import_module("libs.plugins")  # plugins插件  # import_module 导入模块
    28 print(p1)
    29 """
    30 <module 'libs.plugins' from '
    31 E:\Python课堂内容整理\知识点框架
    32 \函数--装饰器--迭代器--生成器--常用模块--ATM
    33 \day24元类和反省\libs\plugins.py'>
    34 """
    35 # 2.从模块中取出类
    36 cls = getattr(p1,'WinCMD')
    37 print(cls)  # <class 'libs.plugins.WinCMD'>
    38 # 3.实例化产生对象
    39 obj = cls()
    40 obj.cd()  # wincmd   切换目录...
    41 """
    42 """
    2.反射--框架的基石.py
     1 """"""
     2 """
     3 2.案例
     4 需求:要实现一个用于处理用户的终端指令的小框架
     5 框架就是已经实现了最基础的构架,就是所有项目都一样的部分
     6 """
     7 # 插件
     8 from libs import plugins
     9 # 框架已经实现的部分
    10 def run(plugin):
    11     while True:
    12         cmd = input('请输入指令>>>:').strip()
    13         if cmd == "exit":
    14             break
    15         # 因为无法确认框架使用者是否传入正确对象,所以需要使用反射来检测
    16         if hasattr(plugin,cmd):
    17             # 取出对应方法
    18             func = getattr(plugin,cmd)
    19             func()  # 执行方法处理指令
    20         else:
    21             print("该指令不受支持")
    22     print("see you la la!")
    23 # 创建一个插件对象,调用框架来使用它
    24 wincmd = plugins.WinCMD()
    25 # 框架之外的部分就有自定义对象来完成
    26 linux = plugins.LinuxCMD()
    27 run(linux)
    28 """
    29 请输入指令>>>:12
    30 该指令不受支持
    31 请输入指令>>>:exit
    32 see you la la!
    33 """
    3.动态导入.应用-插件.py
     1 """"""
     2 """
     3 上述(指:3.应用-插件.py)框架代码中 写死了必须使用某个类,这是不合理的,因为无法提前知道对方的类在什么地方 以及类叫什么
     4 
     5 所以我们应该为框架的使用者提供一个配置文件,要求对方将累的信息写入配置文件 
     6 
     7 然后框架自己去加载需要的模块
     8 """
     9 """
    10 最后的框架代码:
    11 """
    12 # 导入库
    13 import importlib
    14 # 插件
    15 from libs import plugins
    16 # 配置文件
    17 from conf import settings
    18 # 框架实现的部分
    19 def run(plugin):
    20     while True:
    21         cmd = input("请输入指令>>>:").strip()
    22         if cmd == "exit":
    23             break
    24         # 因为无法确定框架使用者是否传入正确的对象所以需要使用反射来检测
    25         # 判断对象是否具备处理这个指令的方法
    26         if hasattr(plugin, cmd):
    27             # 取出对应方法方法
    28             func = getattr(plugin, cmd)
    29             func()  # 执行方法处理指令
    30         else:
    31             print("该指令不受支持...")
    32     print("see you la la!")
    33 # 1.创建一个插件对象
    34 wincmd = plugins.WinCMD()  # <module 'libs.plugins' from 'E:\Python课堂内容整理\知识点框架\函数--装饰器--迭代器--生成器--常用模块--ATM\day24元类和反省\libs\plugins.py'>
    35 # 框架之外的部分就有自定义对象来完成
    36 
    37 # 2.框架 得根据配置文件拿到需要的类
    38 path = settings.CLASS_PATH
    39 # print(path) # <class 'libs.plugins.WinCMD'>
    40 # 3.从配置中单独拿出来 模块路径和类名称
    41 module_path,class_name = path.rsplit(".",1)  # rsplit 拆分
    42 # print(module_path,'11111111')  # libs.plugins 11111111
    43 # print(class_name,'222222222222')  # LinuxCMD 222222222222
    44 # 4.拿到模块
    45 mk = importlib.import_module(module_path)
    46 # print(mk,'33333333333')  # <module 'libs.plugins' from 'E:\Python课堂内容整理\知识点框架\函数--装饰器--迭代器--生成器--常用模块--ATM\day24元类和反省\libs\plugins.py'> 33333333333
    47 # 5.拿到类
    48 cls = getattr(mk,class_name)
    49 # print(cls,'444444')  # <class 'libs.plugins.LinuxCMD'> 444444
    50 # 6.实例化对象
    51 obj = cls()
    52 # print(obj,'5')  # <libs.plugins.LinuxCMD object at 0x0000025531A432B0> 5
    53 # 7.调用框架
    54 run(obj)
    55 """
    56 wincmd   切换目录...
    57 libs.plugins.LinuxCMD
    58 请输入指令>>>:dir
    59 该指令不受支持...
    60 请输入指令>>>:cd
    61 Linuxcmd 切换目录
    62 请输入指令>>>:delete
    63 该指令不受支持...
    64 请输入指令>>>:dir
    65 该指令不受支持...
    66 请输入指令>>>:rm
    67 Linux 要不要删库跑路
    68 请输入指令>>>:ls
    69 Linuxcmd 列出所有文件
    70 请输入指令>>>:exit
    71 see you la la!
    72 """
    73 # 如此一来,框架就与实现代码彻底解耦了,只剩下配置文件
    4.动态导入-应用,配置文件.py
    2.元类
     1 """"""
     2 """
     3 1.元类 metaclass
     4     
     5     元类是什么?
     6         用于创建类的类
     7     
     8     万物皆对象,类当然也是对象
     9     
    10     对象是由类实例化产生的,
    11     如果类也是对象,
    12     必然类对象也是由另一个类实例化产生的
    13     
    14     默认情况下,所有类的元类都是type
    15 """
    16 # 2.验证
    17 class Person:
    18     pass
    19 p = Person()
    20 print(type(p))  # <class '__main__.Person'>
    21 print(type(Person))  # <class 'type'>
    22 
    23 # 结论:Person类是由type类实例化产生的
    24 """
    25 3.元类的三大属性
    26 """
    27 # 案例
    28 class Student(object):
    29     pass
    30 print(type(Student),'元类的三大属性')  # <class 'type'> 元类的三大属性
    31 # 结论:直接调用type类来产生对象
    32 """
    33 一个类的三个基本组成部分:
    34     1.类的名字(字符类型)
    35     2.类的父类们(是一个元组或列表(需要看具体情况))
    36     3.类的名称空间 (字典类型)
    37 """
    38 cls_obj = type('Dog',(),{})
    39 # 用元类生成一个类
    40 print(cls_obj)  # <class '__main__.Dog'>
    41 
    42 
    43 """
    44 4.学习元类的目的
    45 
    46     高度自定义的一个类,
    47     例如控制类的名字必须一大驼峰的形式来书写
    48     
    49     类也是对象,也有自己的类
    50     
    51     需求:创建类对象做一些限制
    52     由此想到初始化方法 我们需要找到类对象的类(元类),覆盖其中,init方法就能实现需求
    53     
    54     当然我们不能修改源代码,所以应该继承type来编写自己的元类,同时覆盖init来完成需求
    55 """
    56 """
    57 5.自定义元类
    58 """
    59 # 代码如下
    60 # 只要继承了type 那么这个类就变成了一个元类
    61 class MyType(type):
    62     # 元类 的三大属性:类名称(字符类型),父类(元组或列表),名称空间(字典)
    63     def __init__(self,clss_name,base,dict):
    64         super().__init__(clss_name,base,dict)
    65         print(clss_name,base,dict)
    66         if not clss_name.istitle():  # istitle 判断是否为字符串
    67             raise Exception('类名类型错误,应为字符串类型')  # Exception 例外的错误
    68 
    69 # 为下列类指定元类
    70 # 1
    71 class Pig(metaclass=MyType):
    72     pass
    73 # Pig () {'__module__': '__main__', '__qualname__': 'Pig'}
    74 MyType("Pig",(),{})  # Pig () {}
    75 
    76 # 2
    77 class A(metaclass=MyType):
    78     pass
    79 # A () {'__module__': '__main__', '__qualname__': 'A'}
    80 MyType("A",(),{})  # A () {}
    1.元类.py
     1 """"""
     2 """
     3 1.元类中call方法
     4 """
     5 """
     6 执行时机:
     7     当你调动类对象时会自动执行元类中的__call__方法
     8     并将这个类本身作为第一个参数传入,以及后面一堆参数
     9     
    10     覆盖元类中的call之后,这个类就无法产生对象,
    11     必须调用super().__call__()来完成对象的创建
    12     并返回其返回值
    13     
    14 2.使用场景
    15     当你想要控制对象的创建过程时,就覆盖call方法,
    16     当你想要控制类的创建过程时,就覆盖init方法
    17 """
    18 # 3.案例
    19 class MyType(type):
    20     # 执行时机:
    21     # 当你调动类对象时会自动执行元类中的__call__方法
    22     def __call__(self, *args, **kwargs):
    23         new_args = []
    24         for a in args:
    25             new_args.append(a.upper())  # upper 大写
    26         print(new_args)
    27         print(kwargs)
    28         return super().__call__(*new_args,**kwargs)
    29 
    30 class Pig(metaclass=MyType):
    31     def __init__(self,name,gender):
    32         self.name = name
    33         self.gender = gender
    34 
    35 p = Pig('llx',gender='nan')
    36 # print(new_args)  #['LLX']
    37 # print(kwargs)  # {'gender': 'nan'}
    38 print(p.name)  # LLX
    39 
    40 """
    41 ps:一旦覆盖了call必须调用父类call方法来产生对象,并返回这个对象
    42 """
    2.元类的call方法.py
     1 ''''''
     2 """
     3 元类的new方法
     4 """
     5 """
     6 执行时机:   
     7     创建类对象时,会首先执行元类中的__new__方法,拿到一个空对象,然后自动调用 __init__来对这个类进行初始化操作
     8 
     9 ps:
    10     如果你覆盖了该方法则必须保证,new方法必须有返回值.且必须是对应类对象
    11 """
    12 # 2.案例
    13 class Mete(type):
    14     # 创建类对象时,会首先执行元类中的__new__方法,拿到一个空对象,然后自动调用 __init__来对这个类进行初始化操作
    15     def __new__(cls, *args, **kwargs):
    16         print(cls)  # <class '__main__.Mete'> # 元类自己
    17         print(args)  # ('A', (), {'__module__': '__main__', '__qualname__': 'A'})  # # 创建类需要的几个参数  类名,基类,名称空间
    18         print(kwargs)  # {}
    19         print('new run')
    20         return super().__new__(cls,*args,**kwargs)
    21         # obj = type.__new__(cls, *args, **kwargs)
    22         # return obj
    23     def __init__(self,a,b,c):
    24         super().__init__(a,b,c)
    25         print('init run')
    26 
    27 class A(metaclass=Mete):
    28     pass
    29 print(A)
    30 """
    31 new run
    32 init run
    33 <class '__main__.A'>
    34 """
    35 """
    36 结论:总结new方法和init 都可以实现控制类的创建过程,new和init都存在.__new__优先级更高,init更简单
    37 """
    3.元类的new方法.py
     1 ''''''
     2 """
     3 1.单例设计模式
     4     设计模式用于解决某种固定问题的套路
     5     例如:MVC MTV等
     6     
     7     单例:指的是一个类产生一个对象
     8     
     9     为什么要使用单例?
    10         单例是为了节省资源 
    11         当一个类的所有对象属性全部相同时,则没有必要创建多个对象
    12 """
    13 # 2.案例
    14 class Person:
    15     def __init__(self,name,age):
    16         self.name = name
    17         self.age = age
    18     def say_hi(self):
    19         print("hello %s"%self.name)
    20     # 用于获取对象的方法
    21     @staticmethod
    22     def get_instance():
    23         # 判断是否有了对象(即:属性是否在类中)
    24         if hasattr(Person,'obj'):
    25             return getattr(Person,'obj')
    26         obj = Person('llx',24)
    27         Person.obj = obj
    28         print('new run')
    29         return obj
    30 p = Person.get_instance()
    31 p.say_hi()
    32 p2 = Person.get_instance()
    33 p2.say_hi()
    34 
    35 p3 = Person.get_instance()
    36 p3.say_hi()
    37 """
    38 new run
    39 hello llx
    40 hello llx
    41 hello llx
    42 """
    43 # 单例模式 -- 优化
    44 class Single(type):
    45     def __call__(self, *args, **kwargs):
    46         # 判断是否有了对象(即:属性是否在类中)
    47         if hasattr(self,"onj"):
    48             return getattr(self,"onj")
    49         # onj = type.__call__(self, *args, **kwargs)  #
    50         onj = super().__call__(self,*args, **kwargs) # 没有则创建
    51         print('new onj')
    52         self.onj = onj  # 并存入类中
    53         return onj
    54 class Student(metaclass=Single):
    55     def __init__(self,name):
    56         self.name = name
    57 class Teacher(metaclass=Single):
    58     pass
    59 # 单例只会创建一个对象
    60 Student()  # new onj  # super
    61 # Teacher()  # new onj  # type
    4.单例模式.py
  • 相关阅读:
    HDU 3949 XOR
    [JXOI2018]游戏
    树状数组 Binary Indexed Tree/Fenwick Tree
    Java 多线程编程
    概率算法
    最长回文子串 Manacher算法
    动态规划-最长上升子序列 LIS
    流水作业调度
    多机调度问题
    A*搜索算法
  • 原文地址:https://www.cnblogs.com/llx--20190411/p/11273155.html
Copyright © 2011-2022 走看看