博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python 反射 元类 单例 冒泡
阅读量:4658 次
发布时间:2019-06-09

本文共 6826 字,大约阅读时间需要 22 分钟。

一 反射

1.什么反射:面向对象编程中反省,指的是一个对象具备发现和修改自身属性的能力。

2.反射中常用的四个内置函数:

class Student():    gender = 'man'    def __init__(self,name,age):        self.name = name        self.age = age    def say(self):        print('你好')s1 = Student('jack',18)#hasattr(对象,字符串属性名) 判断对象是否存在某个属性和方法(包括类中的)print(hasattr(s1,'say')) # Trueprint(hasattr(s1,'gender')) # Trueprint(hasattr(s1,'say')) # Trueprint(hasattr(s1,'run')) # False# getattr(对象,字符串属性名,默认值)    获取对象某个属性的值(方法是地址),如果不存在返回默认值(也可不设置)print(getattr(s1,'say')) # 
>print(getattr(s1,'name')) # jackprint(getattr(s1,'na',1)) # 1# setattr(对象,字符串属性名,属性值) 对象新增或修改某个属性(方法忽略)setattr(s1,'name','rose')setattr(s1,'classes',11)print(getattr(s1,'name')) # roseprint(getattr(s1,'classes')) # 11# delattr对象,字符串属性名) 对象删除某个属性(方法忽略)delattr(s1,'name')print(getattr(s1,'name',1)) # 1
View Code

3.使用场景:

  1)反射其实就是对属性的增删改查,但是如果直接使用内置的dict来操作,语法繁琐,不好理解

  2)另外一个最主要的问题是,如果对象不是我自己写的是另一方提供的,我就必须判断这个对象是否满足的要求,也就是是否我需要的属性和方法

"""反射被称为框架的基石,为什么因为框架的设计者,不可能提前知道你的对象到底是怎么设计的所以你提供给框架的对象 必须通过判断验证之后才能正常使用判断验证就是反射要做的事情,当然通过__dict__也是可以实现的, 其实这些方法也就是对__dict__的操作进行了封装需求:要实现一个用于处理用户的终端指令的小框架框架就是已经实现了最基础的构架,就是所有项目都一样的部分"""import plugins # Py文件# 框架已经实现的部分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 列出所有文件....")
View Code
# settings文件内容"""该文件作为框架的配置文件"""# 作为框架使用者 在配置文件中指定你配合框架的类是哪个CLASS_PATH = "libs.plugins.LinuxCMD"import importlibimport 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)
View Code

二 动态导入

1.什么是静态导入:直接写import称之为静态导入,建立在一个基础上:提前已经知道有这个模块。

  什么是动态导入:指的是在需要的任何时候 通过指定字符串类型的包名称来导入需要的模块

2.

直接写import 称之为静态导入  建立在一个基础上:提前已经知道有这个模块 动态导入  指的是  在需要的任何时候 通过指定字符串类型的包名称来导入需要的模块 import importlibmk = importlib.import_module(m_name) # 模块名(一般为模块py文件的绝对路径)mk 即导入成功的模块"""该方式常用在框架中 因为框架设计者不可能提前预知后续需要的模块和类
View Code

 

三 元类 metaclass

1.什么是元类:指的是用于创建类的类。

       万物皆对象,类当然也是对象

      对象是通过类实例化产生的,如果类也是对象的话,必然类对象也是有另一个类实例化产生的,默认情况下所有类的元类都是type,类对      象 是由type实例化产生的

2.

class Person:    passp = Person()print(type(p)) # 
print(type(Person)) #
View Code

3.用type 来实例化产生一个类:

type(类名,父类元组,名称空间字典)  #返回一个新的类type(对象)  #将会返回这个对象的类型所以:我们可以总结出 当你定义一个class时,解释器会自动调用type来完成类的实例化
View Code

4.元类目的:

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

使用元类

 1.如何定义元类:

# 自定义元类class MyMetaClass(type):    pass# 绑定元类class Person(metaclass=MyMetaClass):    pass
View Code

 2.__new__():

元类中的new方法会在创建类对象时执行,并且先于init(准确的说是创建类对象后)方法  作用是创建一个类对象   class A(metaclass=MyMetaClass):    ​    pass1.执行MyMetaClass的`__new__`方法   拿到一个类对象 2.执行MyMetaClass的`__init__` 方法  传入类对象以及其他的属性 ,进行初始化注意:如果覆盖了`__new__` 一定也要调用type中的`__new__`并返回执行结果  且必须是 对应的类对象,不然无法触发__init__执行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):    passprint(A)
View Code

3.__init__()

实例化对象时会自动执行类中的`__init__`方法, 类也是对象 ,在实例化类对象时会自动执元类中的`__init__`方法(注意与new方法区分,先执行new方法在执行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类指定了元类为MyTypeclass Pig(metaclass=MyType):    passclass Duck(metaclass=MyType):    pass
View Code
案例: 限制类名必须首字母大写   控制类中方法名必须全部小写class MyMetaClass(type):    def __init__(self,class_name,bases,name_dict):        super().__init__(class_name,bases,name_dict)        # 类名必须首字母大写  否则直接抛出异常        if not class_name.istitle():            print("类名必须大写 傻x!")            raise Exception        # 控制类中方法名必须全部小写        for k in name_dict:            if str(type(name_dict[k])) == "
": if not k.islower(): raise Exception pass# 会自动调用其元类中的 __init__ 方法传入 类对象本身 类名称 父类们 名称空间class Student(object,metaclass=MyMetaClass): # MyMetaClass("Student",(object,),{}) NAME = 10 def say(self): print("SAY") pass
View Code

4.__call__()

当你调用类对象时会自动珍惜元类中的__call__方法 ,并将这个类本身作为第一个参数传入,以及后面的一堆参数(元类绑定的类加()执行元类中的call方法)覆盖元类中的call之后,这个类就无法产生对象,必须调用super().__call__来完成对象的创建  并返回其返回值 元类实现单例模式 什么是单例:​    某个类如果只有一个实例对象,那么该类成为单例类 单例的好处:​    当某个类的所有对象特征和行为完全一样时,避免重复创建对象,浪费资源案例:class SingletonMetaClass(type):    #创建类时会执init 在这为每个类设置一个obj属性 默认为None    def __init__(self,a,b,c):        super().__init__(a,b,c)        self.obj = None        # 当类要创建对象时会执行 该方法    def __call__(self, *args, **kwargs):         # 判断这个类 如果已经有实例了就直接返回 从而实现单例        if self.obj:            return self.obj        # 没有则创建新的实例并保存到类中        obj = type.__call__(self,*args,**kwargs)        self.obj = obj        return obj
View Code

 

# 单例元类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()
View Code

 

 

                              

转载于:https://www.cnblogs.com/tfzz/p/11272588.html

你可能感兴趣的文章
最近的几个任务
查看>>
去哪儿网2015校园招聘产品经理笔试(时间:2014-9-23)
查看>>
java默认继承
查看>>
关闭 禁用 Redis危险命令
查看>>
三年工作总结
查看>>
MySQL数据库实验:任务二 表数据的插入、修改及删除
查看>>
asp.net网站前台通过DataList展示信息的代码
查看>>
【SAS ADVANCE】Performing Queries Using PROC SQL
查看>>
Hive新功能 Cube, Rollup介绍
查看>>
webpack:(模块打包机)
查看>>
程序员不得不知的座右铭(世界篇)
查看>>
表格-鼠标经过单元格变色(暂不支持IE6)
查看>>
【每日一学】pandas_透视表函数&交叉表函数
查看>>
实时读取日志文件
查看>>
【寒假集训系列2.12】
查看>>
2018牛客多校第六场 I.Team Rocket
查看>>
Vuex了解
查看>>
c++初始化函数列表
查看>>
JS的this总结(上)-call()和apply()
查看>>
ADO.net 增删改查小练习
查看>>