zoukankan      html  css  js  c++  java
  • 面向对象之高级篇 反射,元类

    今日内容

    1.反射

    2.元类

    3.单列模式

     

    一 反射(反省)

    什么是反省:
      通过字符串来反射,映射到对象,类的属性上,英文中叫反省(自省)

    面向对象中的反省,指的是一个对象必须具备,发现自身属性,以及修改自身属性的能力:

    一个对象在设计初期,可能考虑不够周全,后期需要删除或者修改已经存在的属性,和增加属性

    反省就是通过字符串啦操控对象属性

    涉及到的有四种方法:

       hasattr:判断是否存在某个属性

       getattr:获取某个属性的值

       setattr:新增或者修改某个属性

       delattr:删除某个属性

    注意:只要点能访问的属性,以上四个方法都能操作

    案例:四个方法

     1 class People:
     2     def __init__(self,name,age):
     3         self.name = name
     4         self.age = age
     5 
     6     def run(self):
     7         print('%s is running'%self.name)
     8 
     9 pe = People('zy',19)
    10 
    11 print(pe.__dict__)#{'name': 'zy', 'age': 19}
    12 
    13 print(pe.name) # pe.__dict__['name']
    14 
    15 pe.name = 'zhangyu' # pe.__dict__['name] = 'zhangyu'
    16 
    17 del pe.name # del pe.__dict__['name']
    18 
    19 四个方法
    20 查看是否在里面
    21 print(hasattr(pe,'name')) # 'name' in pe.__dict__
    22 
    23 获取值
    24 print(getattr(pe,'name')) # pe.__dict__['name']
    25 
    26 通过键获取值要是键不存在的话,会报错,但你也可以加上一个None让他不报错,打印None
    27 print(getattr(pe,'xxx',None)) # pe.__dict__['xxx']
    28 
    29 可以修改值
    30 setattr(pe,'name','zhangyu') # pe.__dict__['name']='zhnagyu'
    31 print(pe.name)
    32 print(pe.__dict__)# {'name': 'zhangyu', 'age': 19}
    33 
    34 删除
    35 把name这个键值对删除了
    36 delattr(pe,'name')
    37 print(pe.__dict__)
    View Code

    反射的案例:

     1 class Ftp:
     2     def get(self):
     3         print('get')
     4 
     5     def put(self):
     6         print('put')
     7 
     8     def login(self):
     9         print('login')
    10 
    11     def run(self):
    12         while True:
    13             cmd = input('>>>').strip()
    14             if hasattr(self,cmd):
    15                 method = getattr(self,cmd)
    16                 method()
    17             else:
    18                 print('输入的方法不存在')
    19 
    20 obj = Ftp()
    21 
    22 obj.run()
    View Code

    二 元类

    元类简介:
      元类是什么,用于创建类的类,万物皆对象,类也是对象,

      对象是通过类实例化产生的,如果类也是对象的话,必然类对象也是列一个类

      实例化产生的,默认情况下所有类的元类都是type

    案例:

      

    class OldboyTeacher:
        def __init__(self,name,age,sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        def score(self):
            print('%s is scoring'%self.name)
    
    t = OldboyTeacher('zy',19,'male')
    print(type(t))
    print(type(OldboyTeacher))
    
    
    对象t 是调用OldboyTeacher类得到的,如果说一切皆对象的话,
    那么OldboyTeacher也是一个对象,只要是对象,都是调用一个类
    实例化得到的,即OldboyTeacher = 元类,内置的元类是type

    为什么要学习元类:

      高度的自定义一个类,列如控制类的名字必须以大驼峰的方式来书写,

      类也是对象,也有自己的类,我们的需求是创建类对象做一些限制

      想到了初始化方法,我们只要找到类对象的类(元类)覆盖其中init方法就能实现需求

      但是我们不能修改源代码,所以应该继承type来编写自己的元类,同时覆盖init来完成需求

     案例:

     1 """
     2 只要继承了type 那么这个类就变成了一个元类
     3 """
     4 # 定义了一个元类
     5 class MyType(type):
     6     def __init__(self,clss_name,bases,dict):
     7         super().__init__(clss_name,bases,dict)
     8         print(clss_name,bases,dict)
     9         if not clss_name.istitle():
    10             raise Exception("你丫的 类名不会写...")
    11 
    12 # 为pig类指定了元类为MyType
    13 class Pig(metaclass=MyType):
    14     pass
    15 
    16 class Duck(metaclass=MyType):
    17     pass
    View Code

    元类中的call方法:

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

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

    使用场景: 

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

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

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

     1 class MyType(type):
     2     def __call__(self, *args, **kwargs):
     3         new_args = []
     4         for a in args:
     5             new_args.append(a.upper())
     6 
     7         print(new_args)
     8         print(kwargs)
     9         return super().__call__(*new_args,**kwargs)
    10 
    11 
    12 class Person(metaclass=MyType):
    13     def __init__(self,name,gender):
    14         self.name = name
    15         self.gender = gender
    16 
    17 p = Person(name="jack",gender="woman")
    18 print(p.name)
    19 print(p.gender)
    View Code

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

    元类中的new方法:

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

    案例:

     1 class Meta(type):
     2 
     3     def __new__(cls, *args, **kwargs):
     4         print(cls) # 元类自己
     5         print(args) # 创建类需要的几个参数  类名,基类,名称空间
     6         print(kwargs) #空的 
     7         print("new run")
     8         # return super().__new__(cls,*args,**kwargs)
     9         obj = type.__new__(cls,*args,**kwargs)
    10         return obj
    11     def __init__(self,a,b,c):
    12         super().__init__(a,b,c)
    13         print("init run")
    14 class A(metaclass=Meta):
    15     pass
    16 print(A)
    View Code

    总结:

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

    元类总结:owen版

     1 # 元类:所有自定义的类本身也是对象,是元类的对象,所有自定义的类本质上是由元类实例化出来了
     2 Student = type('Student', (object, ), namespace)
     3 
     4 class MyMeta(type):
     5     # 在class Student时调用:Student类的创建 => 来控制类的创建
     6     
     7     # 自定义元类,重写init方法的目的:
     8     # 1.该方法是从type中继承来的,所以参数同type的init
     9     # 2.最终的工作(如果开辟空间,如果操作内存)还是要借助type
    10     # 3.在交给type最终完成工作之前,可以对类的创建加以限制 *****
    11     def __init__(cls, class_name, bases, namespace):
    12         # 目的:对class_name | bases | namespace加以限制 **********************
    13         super().__init__(class_name, bases, namespace)
    14     
    15     # 在Student()时调用:Student类的对象的创建 => 来控制对象的创建
    16     
    17     # 自定义元类,重写call方法的目的:
    18     # 1.被该元类控制的类生成对象,会调用元类的call方法
    19     # 2.在call中的返回值就是创建的对象
    20     # 3.在call中
    21     #       -- 通过object开辟空间产生对象
    22     #       -- 用被控制的类回调到自己的init方法完成名称空间的赋值
    23     #       -- 将修饰好的对象反馈给外界
    24     def __call__(cls, *args, **kwargs):
    25         # 目的:创建对象,就可以对对象加以限制 **********************
    26         obj = object.__new__(cls)  # 通过object为哪个类开辟空间
    27         cls.__init__(obj, *args, **kwargs)  # 调回当前被控制的类自身的init方法,完成名称空间的赋值
    28         return obj
    29 
    30 # 问题:
    31 # 1.继承是想获得父级的属性和方法,元类是要将类的创建于对象的创建加以控制
    32 # 2.类的创建由元类的__init__方法控制
    33 #        -- 元类(class_name, bases, namespase) => 元类.__init__来完成实例化
    34 # 3.类的对象的创建由元类的__call__方法控制
    35 #         -- 对象产生是需要开辟空间,在__call__中用object.__new__()来完成的
    36 class Student(object, metaclass=MyMeta):
    37     pass
    38 
    39 # class Student:  <=>  type(class_name, bases, namespace)
    View Code

    元类总结:egon版

      1 '''
      2 元类介绍
      3 什么是元类:
      4     源自一句话:在Python中,一切皆对象,而对象都是由类实例化得到的
      5 
      6 '''
      7 
      8 # class OldboyTeacher:
      9 #     def __init__(self,name,age,sex):
     10 #         self.name = name
     11 #         self.age = age
     12 #         self.sex = sex
     13 #
     14 #     def score(self):
     15 #         print('%s is scoring'%self.name)
     16 #
     17 # t = OldboyTeacher('zy',19,'male')
     18 # print(type(t))
     19 # print(type(OldboyTeacher))
     20 '''
     21 对象t 是调用OldboyTeacher类得到的,如果说一切皆对象的话,
     22 那么OldboyTeacher也是一个对象,只要是对象,都是调用一个类
     23 实例化得到的,即OldboyTeacher = 元类,内置的元类是type
     24 
     25 关系
     26 1. 调用元类----->自定义的类
     27 2. 调用自定义的类---->自定义的对象
     28 '''
     29 
     30 
     31 
     32 '''
     33 class关键字创建自定义类的底层的工作原理,分为四步
     34 1.先拿到类名:'OldboyTeacher'
     35 2.再拿到类的基类们:(object)
     36 3.然后拿到类的名称空间(执行类体代码,将产生的名字放到类的名称空间,也就是一个字典里,补充一个exec)
     37 4. 调用元类实例化得到自定义的类: OldboyTeacher=type('OldboyTeacher',(object,),{...})
     38 '''
     39 # class OldboyTeacher:# OldboyTeacher=type(...)
     40 #     school = 'Oldboy'
     41 #     def __init__(self,name,age,sex):
     42 #         self.name = name
     43 #         self.age = age
     44 #         self.sex = sex
     45 #
     46 #     def score(self):
     47 #         print('%s is scoring'% self.name)
     48 '''
     49 自定义类的三个关键组成部分:
     50 1. 类名
     51 2. 类的基类们
     52 3. 类的名称空间
     53 '''
     54 
     55 
     56 '''
     57 案例:
     58     如何不依赖class关键字创建一个自定义类
     59 '''
     60 # # 1. 拿到类名
     61 # class_name='OldboyTeacher'
     62 # #2. 拿到类的基类们:(object,)
     63 # class_bases=(object,)
     64 # #3. 拿到类的名称空间
     65 # class_dic={}
     66 # class_body="""
     67 # school = 'Oldboy'
     68 #
     69 # def __init__(self,name,age,sex):
     70 #     self.name=name
     71 #     self.age=age
     72 #     self.sex=sex
     73 #
     74 # def score(self):
     75 #     print('%s is scoring' %self.name)
     76 # """
     77 # exec(class_body,{},class_dic)
     78 # print(class_dic)
     79 # #4. 调用type得到自定义的类
     80 # OldboyTeacher=type(class_name,class_bases,class_dic)
     81 #
     82 # print(OldboyTeacher)
     83 # # print(OldboyTeacher.school)
     84 # # print(OldboyTeacher.score)
     85 #
     86 # tea1=OldboyTeacher('egon',18,'male')
     87 # print(tea1.__dict__)
     88 #
     89 
     90 
     91 
     92 '''
     93 自定义元类来控制类的产生
     94 模板
     95 '''
     96 # class Mymeta(type):# 单反继承了type的类才能称之为自定义的元类,否则就是一个普通的类
     97 #     def __init__(self,class_name,class_bases,class_dic):
     98 #         print(self)
     99 #         print(class_name)
    100 #         print(class_bases)
    101 #         print(class_dic)
    102 #
    103 # class OldboyTeacher(object,metaclass=Mymeta):#OldboyTeacher=Mymeta('OldboyTeacher',(object,),{...})
    104 #     school = 'Oldboy'
    105 #
    106 #     def __init__(self,name,age,sex):
    107 #         self.name = name
    108 #         self.age = age
    109 #         self.sex = sex
    110 #
    111 #     def score(self):
    112 #         print('%s is scoring'%self.name)
    113 
    114 
    115 '''
    116 控制类的产生
    117 
    118 1. 类名必须用驼峰法
    119 2. 类体必须有文档注释,且文档注释不能为空
    120 '''
    121 # class Mymeta(type):  # 单反继承了type的类才能称之为自定义的元类,否则就是一个普通的类
    122 #     def __init__(self, class_name, class_bases, class_dic):
    123 #         if class_name.islower():
    124 #             raise TypeError ('类名必须使用驼峰体')
    125 #
    126 #         doc = class_dic.get('__doc__')
    127 #         if doc is None or len(doc) == 0 or len(doc.strip('
    ')) == 0:
    128 #             raise TypeError ('类体中必须有文档注释,且文档注释不能为空')
    129 #
    130 # class OldboyTeacher(object, metaclass=Mymeta):  # OldboyTeacher=Mymeta('OldboyTeacher',(object,),{...})
    131 #     school = 'Oldboy'
    132 #     def __init__(self, name, age, sex):
    133 #         self.name = name
    134 #         self.age = age
    135 #         self.sex = sex
    136 #
    137 #     def score(self):
    138 #         print('%s is scoring' % self.name)
    139 # print(OldboyTeacher.__dict__)
    140 
    141 
    142 
    143 '''
    144 自定义元类来控制类调用的过程
    145 #总结:对象之所以可以调用,是因为对象的类中有一个函数__call__
    146 #推导:如果一切皆对象,那么OldboyTeacher也是一个对象,该对象之所可以调用,肯定是这个对象的类中也定义了一个函数__call__
    147 '''
    148 
    149 # 实例化OldboyTeacher,或者说调用OldboyTeacher类
    150 #1.先产生一个空对象
    151 #2.执行__init__方法,完成对象的初始化属性操作
    152 #3.返回初始化好的那个对象
    153 #推导:调用OldboyTeacher(....)就是在调用OldboyTeacher的类中的__call__,那么在__call__中就腰做以上三件事
    154 
    155 # 自定义元类来控制类的调用(即类的实例化过程)
    156 
    157 class Mymeta(type):  # 单反继承了type的类才能称之为自定义的元类,否则就是一个普通的类
    158     def __call__(self,*args,**kwargs):#self=OldboyTeacher这个类,args=('egon',18,'male'),kwargs={}
    159         # 1.先产生一个空对象
    160         tea_obj = self.__new__(self)# tea_obj是OldboyTeacher这个类的对象
    161         # 2. 执行__init__方法,完成对象的初始属性操作
    162         self.__init__(tea_obj,*args,**kwargs)
    163         # 变为私有的
    164         tea_obj.__dict__ = {('_%s__%s' % (self.__name__, k)): v for k, v in tea_obj.__dict__.items()}
    165         # 3. 返回初始化好的那个对象
    166         return tea_obj
    167 
    168 class OldboyTeacher(object, metaclass=Mymeta):  # OldboyTeacher=Mymeta('OldboyTeacher',(object,),{...})
    169     school = 'Oldboy'
    170     def __init__(self, name, age, sex):
    171         self.name = name
    172         self.age = age
    173         self.sex = sex
    174 
    175     def score(self):
    176         print('%s is scoring' % self.name)
    177 
    178 tea1 = OldboyTeacher('egon',18,'male')# 会触发OldboyTeacher的类,即(元类)中的__call__函数
    179 print(tea1.__dict__)
    View Code

    三 单列模式

    什么是单列模式: 

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

    元类实现案例:

     1 # 单例n元类
     2 class Single(type):
     3     def __call__(self, *args, **kwargs):
     4         if hasattr(self,"obj"): #判断是否存在已经有的对象
     5             return getattr(self,"obj") # 有就返回
     6 
     7         obj = super().__call__(*args,**kwargs) # 没有则创建
     8         print("new 了")
     9         self.obj = obj # 并存入类中
    10         return obj
    11 
    12 
    13 class Student(metaclass=Single):
    14     def __init__(self,name):
    15         self.name = name
    16 
    17 
    18 class Person(metaclass=Single):
    19     pass
    20 
    21 # 只会创建一个对象
    22 Person()
    23 Person()
    View Code
  • 相关阅读:
    jquery easyui DataGrid
    easyui datagrid使用
    easyui中datagrid用法,加载table数据与标题
    目前已有的框架
    CSS 块级元素、内联元素概念
    设计中最常用的CSS选择器
    ASP.NET MVC 学习
    CSS边框-属性详解
    Boostrap入门级css样式学习
    Codeforces Round #261 (Div. 2)——Pashmak and Graph
  • 原文地址:https://www.cnblogs.com/zahngyu/p/11273112.html
Copyright © 2011-2022 走看看