python基础12-多态/封装/反射/继承包装/getattr授权

  • 多态

  • 定义:由不同的类实例化得到的对象,调用同一个方法,执行的逻辑不同
  • 面向对象的类叫工厂,来生产实例的。所以工厂函数str就是生成字符串对象的函数
  • len(str1)本质上就是str.__len__()。即不同类,可以调用同一个方法len
  • 多态是动态时的绑定状态,调用不同对象的方法时。多态反应在执行时候
  • 面向对象,就是不要强迫自己去做事情,定义类
  • 多态是继承的一种体现。继承的目的是实现代码的重用,多态让这种重用目标的以体现
  • 封装

  • 是特性,是种思想,不是具体的技术
  • 封装提供接口,封是隐藏的意思
  • _author_='xiansuo '
    
    class People:
        _star='earth'#单下划线开头,就是隐藏,不应该在外部使用该属性
        __star='earth'#python给重命名了,_People__star
        
        def get_star(self):#访问函数,或者接口函数,为外部提供访问隐藏属性的接口
            print(self._star)
  • 封装三层意思
  1. 类就是麻袋,这本身就是一种封装
  2. 类中定义私有的,只在类的内部使用,外部无法访问。但这也只是约定,python并没有实际限制访问
  3. 明确区分内外,内部的实现逻辑,外部无法知晓,并且为封装到内部的逻辑提供一个访问接口给外部使用
  • 面向对象的优点
  1. 通过封装明确了内外,上帝造物的逻辑你无需知道,上帝想让你知道的你才能知道,明确了划分等级
  2. 继承+多态在语言层面支持了归一化设计,即一切皆对象,按照统一的格式去调用即可,归一化
  • 泛化:所有子类和父类有一样的特点。特化:描述子类与父类的不同
  • 反射/自省

  • class BlackMedium:
        feture='Ugly'
        def __init__(self,name,addr):
            self.name=name
            self.addr=addr
    
        def sell_house(self):
            print('[%s]正在卖房子,傻逼才买呢'%self.name)
    
        def rent_hourse(self):
            print('[%s]正在租房子,傻逼才租呢'%self.name)
    
    
    b1=BlackMedium('万成置地','天露园')#生成实例
    
    print(hasattr(b1,'name'))#检测实例b1能否调用name的数据属性
    
    print(getattr(b1,'name'))#获取实例b1中的name属性的value
    func=getattr(b1,'rent_hourse')#获取实例b1中的函数的地址,等价于b1.rent_hourse
    func()#执行上述函数
    print(getattr(b1,'rent_hoursesdfsdaf','没有这个属性'))#匹配不到,则返回后边的值
    
    setattr(b1,'sb',True)#给实例b1的字典加个值,key和value
    print(b1.__dict__)
    setattr(b1,'name','SB')
    setattr(b1,'func',lambda x:x+1)#可以实例加函数属性
    print(b1.__dict__)
    print(b1.func(10))
    
    delattr(b1,'sb')
    print(b1.__dict__)

     

  • 反射就是自己找自己,应用场景:适用于团队合作,彼此分工,一人休假,不影响其他人的代码工作。可插拔程序。
  • 动态导入模块

  • 动态导入的底层就是基于反射做的
  • 一切皆对象,模块也是对象
  • m=__import__('dic')#以字符串的形式导入模块。无论dic.套多少层,m只拿到dic
    print(m)
    
    m.t.test()#执行m下边t模块的test函数
    
    #m1.t中_test2()函数,在此种*的情况下,不能被导入。
    from m1.t import *
    from m1.t import test1,_test2#如此方可导入
    test1()
    test2()
    
    #import importlib
    m=importlib.import_module('m1.t')
    print(m)
    m.test1()#也是以字符串的形式导入上述内容
  • 类的内置attr属性

  • 类本质上也是一个对象,上述的反射方法同样适用于类
  • 双下划线开头的attr方法
  • class Foo:
        x=1
        def __init__(self,y):
            self.y=y
        
        #这三个方法是给实例用的,类不能调用
        #以下三个方法系统都有内置,如果用户不定义,则在适当条件下触发系统内置的
        def __getattr__(self, item):
            print('执行_getattr_')
        #__getattr__是python给类的内置方法,如果用户不定义,则执行系统默认的,就是报错。
        #如果用户定义,则不报错,执行自定义的函数
        
        #以下两种操作很多余,系统默认__delattr和__setattr_就是在执行这种操作
        def __delattr__(self, item):
            print('删除操作_delattr_')
            #del self.item#无限递归了
            self.__dict__pop(item):#操作底层字典进行删除
    
        def __setattr__(self, key, value):#可以加上if判断,实现符合某种条件再设置
            print('_setatter_执行')
            # self.key=value#这种操作属于设置操作,就会触发_setattr_操作,陷入递归
            self.__dict__[key]=value#操作底层字典进行设置
    
    f1=Foo(10)
    print(f1.y)
    print(getattr(f1,'y'))
    
    f1.ssssss#调用f1没有的属性,则执行getattr函数
    del f1.y#删除操作时,会触发__delattr_操作
  • 二次加工标准类型的两种方式

  • 继承+派生

  • str,list,tuple都是类
  • class List(list),List继承list类
  • class List(list):
        def append(self, p_object):
            if type(p_object) is str:
                # self.append(p_object)    #如此调用,又陷入递归陷阱
                # list.append(self,p_object) #调用父类append本身的,建议用super的方法
                super().append(p_object)
            else:
                print('只能添加字符串类型')
    
        def show_midlle(self):  # 继承列表的类,并进一步加工,取得字符串得中值
            mid_index = int(len(self) / 2)
            return self[mid_index]
    
    
    l1 = List('helloworld')
    # print(l1.show_midlle())
    l1.append('SB')
    print(l1)
    l1.append(1212)
  • 组合的方式完成授权,效果等价于继承加工

  • 授权:授权是包装的一个特性,包装一个类型通常是对已经存在的类型的一些定制,这种做法可以新建,修改或者删除原有产品的功能。其他的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。实现授权的关键点就是覆盖__getattr__方法
  • 授权的步骤
  1. 基于标准类型来定制自己的类型
  2. 跟继承没关系,通过getattr实现
  • class FileHandle:#在系统内置的文件上,新增方法,其余的授权给系统内置的文件对象即可,用getattr实现了继承的操作
        def __init__(self,filename,mode='r',encoding='utf-8'):
            # self.filename=filename
            self.file=open(filename,mode,encoding=encoding)#系统提供的
            self.mode=mode
            self.encoding=encoding
    
        def __getattr__(self, item):
            # self.file.read
            return getattr(self.file,item)#返回系统的item方法
    
    f1=FileHandle('a.txt','w+')
    print(f1.__dict__)
    print('==>',f1.read)#触发__getattr__。看似执行自己的read方法,实则是执行open打开文件的read方法
posted @ 2022-01-17 12:31  线索  阅读(57)  评论(0编辑  收藏  举报