面向对象-4

面向对象-4

目录

  • 反射实战案例

  • 面向对象的魔法方法

  • 魔法方法实战演练

  • 元类

  • 创建类的两种方式

  • 元类的实际应用

  • 元类——双下new方法

反射实战案例

  • 加载配置文件纯大写的配置

        import settings
        new_dict = {}
        # print(dir(settings))  # dir获取括号中对象可以调用的名字
        # ['AGE', 'INFO', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'desc', 'name']
        for i in dir(settings):
            if i.isupper():  # 如果名字是纯大写 那么获取该大写名字对应的值   'AGE'   'INFO'
                v = getattr(settings, i)
                new_dict[i] = v
        print(new_dict)
    
  • 模拟操作系统CMD终端执行用户命令

    	class WinCmd(object):
            def dir(self):
                print('dir获取当前目录下所有的文件名称')
    
            def ls(self):
                print('ls获取当前路径下所有的文件名称')
    
            def ipconfig(self):
                print('ipconfig获取当前计算机的网卡信息')
        obj = WinCmd()
        while True:
            cmd = input('请输入您的命令>>>:')
            if hasattr(obj, cmd):
                cmd_name = getattr(obj, cmd)
                cmd_name()
            else:
                print('%s 不是内部或外部命令,也不是可运行的程序或批处理文件' % cmd)
    

面向对象的魔法方法

  • 什么是魔法方法

    ​ 魔法方法其实就是类中定义的双下方法

    ​ 这些方法都是到达某个条件自动触发 无需调用 故被称之为魔法方法

  • 魔法方法和其触发条件

    魔法方法 触发条件
    __ init__ (self, name) 给对象设置独有数据的时候自动触发(实例化)

    __ str__ (self)
    对象被执行打印操作的时候会自动触发
    该方法必须返回一个字符串
    返回什么字符串打印对象之后就展示什么字符串
    __ call__ (self, *args, **kwargs) 对象加括号调用 自动触发该方法

    __ getattr__(self, item)
    当对象获取一个不存在的属性名 自动触发
    该方法返回什么 对象获取不存在的属性名就会得到什么
    形参item就是对象想要获取的不存在的属性名
    __ getattribute__(self, item) 对象获取属性的时候自动触发 (无论这个属性存不存在)
    当类中既有__ getattr__ 又有__ getattribute__的时候 只会走后者
    __ setattr__(self, key, value) 对象操作属性值的时候自动触发>>>: 对象.属性名=属性值
    __ del__(self) 对象在被删除(主动 被动)的时候自动触发
    __ enter__(self) 对象被with语法执行的时候自动触发
    该方法返回什么 as关键字后面的变量名就能得到什么
    __ exit__(self, exc_type, exc_val, exc_tb) 对象被with语法执行并运行完with子代码之后 自动触发
  • 具体触发情况

    1. __ init__ (self, name)方法

      class MyClass(object):
          def __init__(self, name):
              """实例化对象的时候自动触发"""
              # print('__init__方法')
              # pass
              self.name = name
      
    2. __ str__ (self)

      class MyClass(object):
           def __str__(self):
              """
              对象被执行打印操作的时候会自动触发
                  该方法必须返回一个字符串
                  返回什么字符串打印对象之后就展示什么字符串
              """
              # print('__str__方法')
              # print('这是类:%s 产生的一个对象')
              # return '对象:%s'%self
              return '对象:%s'%self.name
      
    3. __ call__ (self, *args, **kwargs)

      class MyClass(object):
          def __call__(self, *args, **kwargs):
              """对象加括号调用 自动触发该方法"""
              print('__call__方法')
              print(args)
              print(kwargs)
      
    4. __ getattr__(self, item)

      class MyClass(object):
           def __getattr__(self, item):
              """当对象获取一个不存在的属性名 自动触发
                  该方法返回什么 对象获取不存在的属性名就会得到什么
                  形参item就是对象想要获取的不存在的属性名
              """
              print('__getattr__', item)
              return '您想要获取的属性名:%s不存在'%item
      
    5. __ getattribute__(self, item)

      class MyClass(object):
           """对象获取属性的时候自动触发 无论这个属性存不存在
                  当类中既有__getattr__又有__getattribute__的时候 只会走后者
              """
              # print('__getattribute__')
              # return super(MyClass, self).__getattribute__(item)  复杂写法
              return super().__getattribute__(item)  # 简便写法
      
    6. setattr(self, key, value)

      class MyClass(object):
              def __setattr__(self, key, value):
              """对象操作属性值的时候自动触发>>>:  对象.属性名=属性值"""
              # print("__setattr__")
              # print(key)
              # print(value)
              super().__setattr__(key, value)
      
    7. del(self)

      class MyClass(object):
          def __del__(self):
              """对象在被删除(主动 被动)的时候自动触发"""
              # print('__del__')
              pass
      
    8. __ enter__(self)

      class MyClass(object):
           def __enter__(self):
              """对象被with语法执行的时候自动触发 该方法返回什么 as关键字后面的变量名就能得到什么"""
              print('__enter__')
      
    9. __ exit__(self, exc_type, exc_val, exc_tb)

      class MyClass(object):
            def __exit__(self, exc_type, exc_val, exc_tb):
              """对象被with语法执行并运行完with子代码之后 自动触发"""
              print('__exit__')
      

    元类

    • 元类的简介

      1. 元类前瞻

        ​ 在接触面向对象之前我们认为所使用的type来查看数据的数据类型

        ​ 学过面向对象之后,type查看的并不是数据类型,而是数据所属的类

      2. 数据类型的本质

        ​ 数据类型的本质 还是通过各个类产生了对象

        也可以理解为type用于查看产生当前对象的类是谁

      3. 元类是如何产生

        class MyClass:
            pass
        obj = MyClass()
        print(type(obj))  # 查看产生对象obj的类:<class '__main__.MyClass'>
        print(type(MyClass))  # 查看产生对象MyClass的类:<class 'type'>
        

        自定义的类都是由type类产生的 , 我们将产生类的类称之为 '元类'

    • 产生类的两种方式

      1. 使用class关键字

        class MyClass:
            pass
        
      2. 利用元类type

        type(类名,类的父类,类的名称空间)
        

        学习元类其实就是掌握了类的产生过程 我们就可以在类的产生过程中高度定制化类的行为
        eg:
        类名必须首字母大写
        上述需求就需要使用元类来控制类的产生过程 在过程中校验

    • 元类基本使用

      class MyMetaClass(type):
          pass
      """只有继承了type的类才可以称之为是元类"""
      class MyClass(metaclass=MyMetaClass):
          pass
      """如果想要切换产生类的元类不能使用继承 必须使用关键字metaclass声明"""
      
      '''
      思考
      	类中的__init__用于实例化对象
      	元类中__init__用于实例化类
      '''
      
      class MyMetaClass(type):
          def __init__(self,what, bases=None, dict=None):
              # print('别晕')
              # print('what', what)  类名
              # print('bases', bases) 类的父类
              # print('dict', dict) 类的名称空间
              if not what.istitle():
                  # print('首字母必须大写 你会不会写python 面向对象学过吗 lowB')
                  raise Exception('首字母必须大写 你会不会写python 面向对象学过吗 lowB')
              super().__init__(what, bases, dict)
      """只有继承了type的类才可以称之为是元类"""
      
      
      # class Myclass(metaclass=MyMetaClass):
      #     pass
      
      
      """如果想要切换产生类的元类不能使用继承 必须使用关键字metaclass声明"""
      class aaa(metaclass=MyMetaClass):
          pass
      
    • 元类进阶

      元类不单单可以控制类的产生过程 其实也可以控制对象的

      1. 对象加括号执行产生该对象类中的双下call

        class MyMetaClass(type):
            def __call__(self, *args, **kwargs):
                print('__call__')
                if args:
                    raise Exception('必须用关键字参数传参')
                super().__call__(*args, **kwargs)
        
        
      2. 类加括号执行产生该类的元类中的双下call

        class MyClass(metaclass=MyMetaClass):
            def __init__(self, name, age):
                self.name = name
                self.age = age
                print('__init__')
        
      3. 实例化对象 所有的参数都必须采用关键字参数的形式

        eg : obj = MyClass(name='jason', age=18)

      4. 总结:

        如果我们想高度定制对象的产生过程
        可以操作元类里面的__ call__
        如果我们想高度定制类的产生过程
        可以操作元类里面的__ init__

    • 双下new方法

      类产生对象的步骤
      1.产生一个空对象
      2.自动触发__ init__方法实例化对象
      3.返回实例化好的对象

      __ new__ 方法专门用于产生空对象
      __ init__ 方法专门用于给对象添加属性

posted @ 2022-07-30 15:49  Nirvana*  阅读(26)  评论(0)    收藏  举报