面向对象的反射和一些魔法方法

  1. 类相关的内置函数
    # 类相关的内置函数
    # 1.isinstance 用于判断,对象是否是对应类型,返回True或者False 接收两个参数,(实例化的对象,类型) 如果存在继承关系也会返回True
    isinstance(1,int)
    # 2.issubclass 用于判断类于类之间的继承关系 例:issubclass(B,A)判断B是否继承与A 参数只能传入类
    class A:pass
    class B(A):pass
    a = A()
    b = B()
    issubclass(A,A)
    # == 跟 is 的区别 (== 判断值是否相等,is判断内存地址是否相同)

     

  2. 反射
    # 反射
    # 用字符串数据类型的变量名来访问,这个变量的值
    '''
    getattr:
        使用字符串来访问变量,或者执行方法
        
        # 访问变量
            getattr(对象|类|模块,'变量名')
        # 执行方法
            getattr(对象|类|模块,'方法名')(参数)
        
    hasattr:
        用于判断,该属性或者方法在该对象中是否存在
        hasattr(对象|类|模块,'方法名|属性名')
        
    setattr:
        用于修改对象属性
        
        setattr(对象|类|模块,'属性名','新值')
    
    delattr:
        用于删除对象属性
        delattr(对象|类|模块,'属性名')
    
    '''
    class A:
        name = '777'
        def func(self,arg):
            print(arg)
    a = A()
    
    import sys
    print(sys.modules.get('__main__'))

     

  3. __call__方法
    # __call__ 实例化对象加() 就会调用 __call__ 方法
    class A:
        def __call__(self,*args,**kwargs):
            print('args:',args)
            print('kwargs:',kwargs)
            print('A 的__call__方法被调用了')
    # 第一种使用方法
    # a = A()
    # a()
    
    class B:
        def __init__(self,cls):
            self.a = cls()
            self.a()
    # 第二种使用方法
    # b = B(A)

     

  4. __len__方法
    # __len__ 在执行内置函数len()的时候回调用这个方法,该方法必须返回一个整数类型,否者会报错
    # __len__ return 的值就是len()函数计算出的长度
    class MyObj:
        def __init__(self,*args):
            self.args =args
        def __len__(self):
            print('MyObj的__len__方法被调用了')
            
            return 1       
    obj = MyObj()
    print(len(obj))
    
    # 练习
    class MyStr:
        def __init__(self,args):
            self.string = args
        def __len__(self):
            return len(self.string)
    s = MyStr('asc')
    print(len(s))

     

  5. __new__方法
    # __new__ 构造方法,在类名+()的时候调用,然后会开辟一块内存。返回给__init__(初始化方法)中的self
    class A:
        def __new__(cls,*args,**kwargs):
            # 由于Python语言无法开辟空间,我们得调用父类(object)的__new__方法来开辟空间(下面两种方法都可以)
            # obj = object.__new__(cls)
            obj = super().__new__(cls)
            print(obj)
            return obj
        
        def __init__(self):
            print('在初始化方法中',self)
                  
    A()
    # 使用场景  单例类
    class B:
        __ISINCTANCE = None
        def __new__(cls,*args,**kwargs):
            if not cls.__ISINCTANCE:
                cls.__ISINCTANCE = super().__new__(cls)
            return cls.__ISINCTANCE
        
        def __init__(self,name):
            print(self)
            self.name = name
            
    a = B(1)
    b = B(2) 
    c = B(3)
    print(a,b,c)
    print(a.name,b.name,c.name)

     

  6. __str__方法
    # __str__ 在执行print|str|'%s'% obj 的时候 调用
    class A:
        def __init__(self,name):
            self.name = name
        
        def __str__(self):
            return self.name
        
    a = A('444')
    print(a)
    print(str(a))
    print('字符串格式化:%s'%a)

     

  7. __repr__方法
    # __repr__
    # 内置函数 repr()       原样输出,在打印输出的时候,原样显示\n \t等特殊字符,输出的字符串也会被""包括(但是%s占位符还是可以正常使用)
    # 如果没有__str__,那么调用 __str__方法的操作会找__repr__方法来取值
    class A:
        def __init__(self,name):
            self.name = name
    #     def __str__(self):
    #         return self.name
        def __repr__(self):
            return '\'%s\''%self.name
    
    class B(A):
        def __repr__(self):
            return '\'%s\''%self.name
        
    
    a = B('aaa')
    print(a)
      
    print(repr(a))

     

  8.  __del__ 方法
    # __del__  析构方法 释放一个空间
    # 跟构造方法相反 __new__ 构造方法 申请一个空间
    class A:
        def __del__(self,*args,**kwargs):
            '''
            执行 del key 的时候触发
            就算这里没有写 del相关语法,照样可以删除元素
            '''
            print('被删除了...')
            
            
            
    a = A()
    import time
    time.sleep(10)

     

  9. item系列
    # item 系列
    # __getitem__ 、__setitem__
    
    class B:
        def __getitem__(self,item):
            '''
            b = B()
            在执行 b['key'] 的时候调用此方法 item 会接收到key
            '''
            return getattr(self,item)
        def __setitem__(self,key,value):
            '''
            b = B()
            在执行 b['key']=123 的时候调用此方法 key 会接收到key ,value会接收到123
            '''
            setattr(self,key,value)
            
        def __delitem__(self,key):
            
            '''
            b = B()
            在执行 del b['key']的时候调用此方法 key 会接收到key 
            '''
            delattr(self,key)
    
            
    
    b = B()
    b['a123'] = 666
    b['a123']
    del b['a123']
    b['a123']

     

  10. __hash__,__eq__方法
    # 面试题 __hash__、__eq__
    '''
    员工管理系统类
        属性 姓名,性别,年龄,部门
        
    存在重复员工信息,但是部门不同(如果存在姓名相同,性别相同。我就认为这是同一个人)
    有1000的员工对象,筛选出重复的员工
    
    '''
    class Staff:
    
        def __init__(self,name,sex,age,department):
    
            self.name = name
            self.sex = sex
            self.age = age
            self.department = department
            
        def __hash__(self):
            # 自定义类的hash条件
            return hash('%s%s'%(self.name,self.age))
            
        def __eq__(self,other):
            # 使用 == 语法的时候,会触发这个方法,用于判断是否相等
            # 如果hash值相同,会触发这个方法,来判断值是否相同(True相同,False不同)
            if self.name == other.name and self.sex == other.sex:
                return True
    
    s1 = Staff('张三','',28,'运营')
    s2 = Staff('李四','',28,'人事')
    s3 = Staff('王五','',28,'财务')
    s4 = Staff('钱六','',78,'销售')
    s5 = Staff('王五','',28,'销售')
    staff_list =[s1,s2,s3,s4,s5]
    
    '''
    # 使用集合的去重机制 
    
    1.计算hash值(调用对象的__hash__方法)
    
        1.1 如果hash值不同,则存入hash对应的内存地址
        
        1.2 如果hash相同:判断值是否相同(调用对象的__eq__方法)
            
            1.2.1 如果值相同 :则存入hash对应的内存地址,替换之前的值
            1.2.3 如果值不同 :使用另外hash算法,进行二次寻址
    
    最后留下来的就是不相同的
            
    '''
    staff_set = set(staff_list)
    print(staff_set)

     

  11. __setattr__、__getattr__、__delattr__
    # 1 __ setattr__的使用
    # 2 递归现象的出现
        -通过反射赋值 setattr(obj,key,value)
        -self.key=value
    # 3 避免递归
        -self.__dict__[key] = value
        -object.__setattr__(self,key,value)
    # 4 object.__setattr__(f,'_Foo__size',178)的使用
    
    # 5 __getattr__
        -对象.属性 取值属性不存在就会触发它的执行
    
    # 6 __delattr__
            - 删除对象.属性的时候会触发执行
        
    # 7 应用场景(字典只支持中括号取值和赋值,让它支持 . 取值和赋值)

     

  12. __slots__
    class A:
        __slots__ = ['name', 'age']
    # 用于控制A类的对象只能点出那些属性
    a1 = A()
    # print(a1.__dict__)  # AttributeError: 'A' object has no attribute '__dict__'
    a1.name = '张三'
    a1.age = 24
    print(a1.age)
    # a1.hobby = '泡妞'  # AttributeError: 'A' object has no attribute 'hobby'
    a1.size=179
    print(a1.__slots__)

     

  13. __doc__
    class A:
        """我是A类的描述信息啊手动阀手动阀"""
        pass
    # 查看类的注释
    print(A.__doc__)

     

  14. __enter__、__exit__
    class B:
    
        def __enter__(self):
            # 在使用with 对象 as 变量名:
            # 语句的时候 会将这个魔法方法的返回值 赋值给变量名
            return self
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            """
            当with代码块执行结束之后,会执行这个魔法方法中的代码
            如果with是正常结束的,那么三个参数都是None
            如果with遇到了异常
            :param exc_type: 异常类型
            :param exc_val:  异常提示信息
            :param exc_tb:  traceback类,异常的一些信息,哪一行报的错误等
            :return:
            """
            print('with结束了')

     

posted on 2019-07-24 16:55  信奉上帝的小和尚  阅读(134)  评论(0编辑  收藏  举报

导航