面向对象(四)

内容概要

  • 反射的实际案例
  • 面向对象的双下方法
  • 元类简介
  • 元类基本使用
  • 元类进阶操作
  • 双下new方法

反射实际案例

   """反射提供了一种不需要考虑代码的前提下 操作数据和功能"""
    
    class LinuxCmd(object):
        def ls(self):
            print('Linux系统正在执行ls命令...')

        def rm(self):
            print('Linux系统正在执行rm命令...')

        def cd(self):
            print('Linux系统正在执行cd命令...')

    obj = LinuxCmd()
    print(LinuxCmd.__dict__)  # 'ls':

    def run(obj):
        while True:
            cmd = input('请输入您的指令>>>:').strip()
            # 判断输入的cmd是否存在LinuxCmd.__dict__
            if hasattr(obj, cmd):
                # 类似于func_name = cmd 只是将字符串变成变量名
                func_name = getattr(obj, cmd)
                func_name()

            else:
                print('找不到指令')
    run(obj)

面向对象的双下方法

双下方法说明

    """
    面向对象中的双下方法也有一些人称之为是魔法方法
        有些双下方法不需要刻意调用 到达某个条件会自动触发
            __init__		对象实例化的时候自动触发
    """
    

1.双下str方法

    1.__str__
    '''
      对象被执行打印(print、前端展示)操作的时候自动触发
         该方法必须返回字符串类型的数据
      很多时候用来更加精准的描述对象
     '''
    class MyClass(object):
        def __init__(self,name,age):
            self.name = name
            self.age =age
        def __str__(self):
            return self.name #返回类型必须是字符串
    obj = MyClass('Tom',18)
    print(obj)  # Tom

2.双下del

    2.__del__
        '''对象被执行(被动、主动)删除操作之后自动执行'''
    class MyClass(object):
        def __init__(self,name):
            self.name = name
        def __del__(self):
            print('from __del__')
    obj = MyClass('Tom')
    del obj  # from __del__

3.双下getattr

    3.__getattr__
      '''对象查找不存在名字的时候自动触发'''
    class MyClass(object):
        def __init__(self,name,age):
            self.name = name
            self.age =age
	    def __getattr__(self, item):
            print('from __getattr__',item)
            return f'没有{item}'
	obj = MyClass('Tom',18)
    print(obj.name)   # Tom
    print(obj.Tony)  # 没有Tony

4.双下setattr

    4.__setattr__
        对象在执行添加属性操作的时候自动触发	>>>	obj.变量名=变量值

    class MyClass(object):
        def __init__(self,name,age,hobby):
            self.name = name
            self.age =age
            self.hobby = hobby
     
        def __setattr__(self, key, value):
            print('__setattr__方法')
            print(key, value)
            if key == 'hobby':
                # 主动报错
                raise Exception('你没有资格拥有hobby')
            if not key.islower():
                raise Exception('名字只能小写')
            super().__setattr__(key, value)

    obj = MyClass('Tom',18,'看视频')
    obj.Age = 20

5.双下call

    5.__call__
        '''对象被加括号调用的时候自动触发'''

    class MyClass(object):
        def __init__(self,name,age,hobby):
            self.name = name
            self.age =age
            self.hobby = hobby
        def __call__(self, *args, **kwargs):
            print('from __call_方法',args,kwargs)

    obj = MyClass('Tom',18,'看视频')
    obj(obj.name,obj.age,hobby='play')

6.双下enter与双下exit

    6.__enter__
        '''
        对象被执行with上下文管理语法开始自动触发 
        	在with上文执行
        该方法返回什么as后面的变量名就会得到什么
        '''
    __exit__
    """对象被执行with上下文管理语法结束之后自动触发"""
    
   class MyClass(object):
        def __init__(self):
          pass
    
        def __enter__(self):
            print('__enter__方法')
            return 'boy'
    
        def __exit__(self,type,val,td)
            print('__exit__方法')
            
   obj = MyClass()
   print('fly!!!')
   with obj as f:
        print('Tom nice!!!')
        print(f)
    print('good!!!')

7.双下getattribute

    7.__getattribute__
        '''
          只要对象查找名字无论名字是否存在都会执行该方法
          如果类中有__getattribute__方法 那么就不会去执行__getattr__方法
         '''
    class MyClass(object):
        def __init__(self,name,age,hobby):
            self.name = name
            self.age =age
            self.hobby = hobby
       def __getattr__(self, item):
            print('from __getattr__',item)
            return f'没有{item}'
        def __getattribute__(self, item):
            print('__getattribute__方法', item)
            return item
    obj = MyClass('Tom',18,'运动')
    print(obj.name)
    print(obj.jiji)

元类简介

    # 元类
        即产生类的类
	'''
        print(type(123))  # <class 'int'>
        print(type([12, 33, 44]))  # <class 'list'>
        print(type({'name':'jason','pwd':123}))  # <class 'dict'>
        type查看的其实是当前对象所属的类名称
       '''
    class MyClass(object):
        pass
    obj = MyClass()
    print(type(obj))
    print(type(MyClass))  # <class 'type'>

    class Student:
        pass
    print(type(Student))  # <class 'type'>

    class Teacher(MyClass):
        pass
    print(type(Teacher))  # <class 'type'>
    '''type就是所有类默认的元类!!!'''
    
    # 元类的两种表现形式
    1.class关键字
	class C1(object):
        pass
     print(C1)  # <class '__main__.C1'>
	
    2.type元类
        type(类名,父类,类的名称空间)
        res = type('C1', (), {})
        print(res)  # <class '__main__.C1'>	
    

元类的基本使用

    """元类是不能通过继承的方式直接指定的"""
    需要通过关键字'metaclass'参数的形式修改
    class C1(metaclass=MyTypeClass):
        pass

    class MyTypeClass(type):
        def __init__(cls, cls_name, cls_bases, cls_dict):
            if not cls_name.istitle():  # 判断类名是否大写
                raise Exception("类名的首字母必须大写 你个SD")
            super().__init__(cls_name, cls_bases, cls_dict)

    # 在元类中必须使用关键字metaclass继承父类
    class School_name(metaclass=MyTypeClass):  # 类名首字母大写
        school = '清华大学'

    class school_name(metaclass=MyTypeClass):
        school = '清华大学'
    # 使用小写时 Exception: 类名的首字母必须大写 你个SD

元类进阶操作

    1.回想__call__方法
        对象加括号会自动执行产生该对象的类里面的__call__,并且该方法返回什么对象加括号就会得到什么
      推导:类加括号会执行元类的里面的__call__该方法返回什么其实类加括号就会得到什么
      """类里面的__init__方法和元类里面的__call__方法执行的先后顺序"""
        class MyTypeClass(type):
        def __call__(self, *args, **kwargs):
            print('__call__ run')
            super().__call__(*args, **kwargs)
      class MyClass(metaclass=MyTypeClass):
          def __init__(self, name):
              print('__init__ run')
              self.name = name
      obj = MyClass('jason')

    # 定制对象的产生过程
        class MyTypeClass(type):
        def __call__(self, *args, **kwargs):
            # print('__call__ run')
            # print(args,kwargs)
            if args:
                raise Exception('必须全部采用关键字参数')
            super().__call__(*args, **kwargs)

      class MyClass(metaclass=MyTypeClass):
          def __init__(self, name):
              # print('__init__ run')
              self.name = name

        """强制规定:类在实例化产生对象的时候 对象的独有数据必须采用关键字参数"""
      # obj1 = MyClass('jason')
      obj2 = MyClass(name='jason')
    """
    如果你想高度定制类的产生过程
        那么编写元类里面的__init__方法
    如果你想高度定制对象的产生过程
        那么编写元类里面的__call__方法
    """

双下new方法

    __new__用于产生空对象(类)			骨架
    __init__用于实例化对象(类)		血肉

    """
    注意:并不是所有的地方都可以直接调用__new__ 该方法过于底层
        如果是在元类的__new__里面 可以直接调用
    """
        class Meta(type):
            def __new__(cls, *args, **kwargs):
                # 1.产生一个空对象
                obj = type.__new__(cls, *args, **kwargs)
                # 2.调用init方法实例化
                return obj

        class MyClass(metaclass=Meta):
            def __init__(self,name):
                self.name = name
        obj = MyClass('Tom')
        print(obj)

       """如果是在元类的__call__里面 需要间接调用""" 
        class Mate(type):
            def __call__(self, *args, **kwargs):
                obj = object.__new__(self)  # 创建一个空对象
                self.__init__(obj, *args, **kwargs)  # 让对象去初始化
                return obj

        class MyClass(metaclass=Mate):
            def __init__(self,name):
                self.name = name
        obj = MyClass('Tom')
        print(obj)  
             
    

posted @ 2022-04-11 21:46  Mr_胡萝卜须  阅读(17)  评论(0编辑  收藏  举报