zoukankan      html  css  js  c++  java
  • 第三十五篇 类的内置属性(attr属性),包装和授权,__getattr__

    双下划线开头的attr方法,都是类内置的方法。

    一. 如果没有在类里定义这三个方法,调用的时候就调用类内置的默认的方法

    class Too:
        pass
    
    # 类没有定义这三个属性,就用系统默认的方法
    t1 = Too()
    
    print(t1.x)  # 只有在属性不存在时, 会自动触发__getattr__
    # AttributeError: 'Too' object has no attribute 'x'
    
    del t1.x   # 删除属性时会触发 __delattr__
    # AttributeError: 'Too' object has no attribute 'x'
    
    t1.y = 10    # 设置属性的时候会触发 __setattr__

    二. 如果你在类里定义了这三个属性,当触发的时候,就会用你自己定义的方法,而不会再去调用Python内置的三个属性了。

    # 实例代码
    class Foo:
        x = 1
        def __init__(self,y):
            self.y = y
        # __getattr__用处是最大的
        def __getattr__(self, item):
            print("执行__getattr__")
    
        def __delattr__(self, item):
            print("删除操作__delattr__")
         # del self.item    # 无限递归了
         self.__dict__.pop(item)   
         # 1. 所以删除需要直接使用它,操作底层字典。
    # 2. 如果不允许删除,就需要注释掉这句话,就能控制你的所有属性都不被删除
    def __setattr__(self, key, value): print("__setattr__开始执行") # self.key = value # 这就无限递归了,不能这么用的哦 # 设置属性最根本的就是在操作最底层的字典属性,所以可以直接改__dict__, 所以应该用下面的方法 self.__dict__[key] = value # 实例化 f1 = Foo(10)

    __getattr__:是在调用的属性不存在的时候才会执行

    # 调用
    print(f1.y)   # 10
    print(getattr(f1, 'y'))  # 10
    
    # 调用不存在的属性
    f1.ssssss   # 执行__getattr__
    '''
    __getattr__:是在调用的属性不存在的时候才会执行
    '''

    __delattr__:执行删除属性操作的时候,会触发__delattr__方法

    del f1.y  # 删除操作__delattr__
    del f1.x  # 删除操作__delattr__

    __setattr__:添加或者修改属性,就会触发__setattr__方法

    # 实例化
    f1 = Foo(10)   # 实例化的时候,就是在设置字典属性,所以此时会调用一次__setattr__
    f1.z = 3       # 再次设置一个z,还会调用__setattr__。
    print(f1.__dict__)  # {'y': 10, 'z': 3}
    # 因为你重写了__setattr__,凡是赋值操作都会触发它的执行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值。

    二次加工标准类型(包装)

    __delattr__和 __setattr__作用不大,最有用的是__getattr__,看看它的牛逼之处。

    包装:Python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景,这些内置方法远远无法满足你的需求,所以我们都需要基于标准数据类型来定制我们自己的数据类型,新增、改写方法,这就用到了继承/派生知识(其他的标准类型均可以通过下面的方式进行二次加工).

    包装是通过继承加派生的方式实现的。

    class List(list):   # 继承了list类
        # 定制了List自己的append方法,只有字符串类型的才可以append到列表里
        def append(self, p_object):
            if type(p_object) is str:
                # self.append(p_object)  # 无限递归了
                super().append(p_object)   # 等价于 list.append(p_object),前面讲过可以用super().
            else:
                print('只能添加字符串类型')
    
        # 取中间值,自己定义了一个方法,派生
        def show_midlle(self):
            mid_index=int(len(self)/2)
            return self[mid_index]
    l1=List('helloworld')
    print(type(l1))   # <class '__main__.List'>
    print(l1.show_midlle())  # w
    l1.append(1111111111111111111111)    # 只能添加字符串类型
    
    l1.append('SB')
    print(l1)   # ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd', 'SB']
    调用

    授权:授权是包装的一个特性,包装一个类型通常是对已经存在的类型的一些定制,这种做法可以新建,修改,或者删除原有产品的功能。其他的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,单已存在的功能就授权给对象的默认属性。

    实现授权的关键点就是覆盖__getattr__方法

    (1)该示例相当于实现了包装的继承和派生

    class FileHandle:
        def __init__(self,filename,mode='r',encoding='utf-8'):
            self.file=open(filename, mode, encoding=encoding)  # 调用的是系统提供open打开文件方法
            self.mode=mode
            self.encoding=encoding
    
        # def write(self,line):
        #     print('------------>',line)
        #     t=time.strftime('%Y-%m-%d %X')
        #     self.file.write('%s %s' %(t,line))
    
        def __getattr__(self, item):
            # 这个方式,相当于是文件里有什么方法,我就提供什么
            return getattr(self.file,item)
    
    f1=FileHandle('a.txt','w+')
    print(f1.file)  # <_io.TextIOWrapper name='a.txt' mode='w+' encoding='utf-8'>
    print(f1.__dict__)
    # {'file': <_io.TextIOWrapper name='a.txt' mode='w+' encoding='utf-8'>, 'mode': 'w+', 'encoding': 'utf-8'}
    # <_io.TextIOWrapper name='a.txt' mode='w+' encoding='utf-8'>--->这是系统提供的
    
    # 先在f1里找是否有read,然后再类里找,也没有read,最后触发了__getattr__,
    # 就把f1传给self, read 传给item,最后用getattr的方式调用self.file,self.file就是f1实例调用自己的file属性
    # f1自己的file属性就是上面字典里file,这个file里有,就是系统提供的的open方法
    print('==>',f1.read) #触发__getattr__  
    #  ==> <built-in method read of _io.TextIOWrapper object at 0x0134BA30>
    
    # 先在自己f1的字典里找没有write方法,然后类FileHandle里也没有write方法,最后触发了__getattr__方法
    # 就把f1传给self,把write传给了item,就相当于是get的而是self.write下面的那个write方法,所以就能找到了。
    print(f1.write)
    # 通过这种方式,f1的write,read, seek,truck等方法都可以操作了
    
    # 牛逼的地方在于,f1是通过FileHandle类实现的,而FildHandle内部是通过__getattr__帮你做了一次中转。
    # 通过这种方式,相当于文件的所有属性都传递过来了。
    # 这相当于刚才包装的继承和派生。
    # 文件操作里有什么,我就给你提供什么
    f1.write('1111111111342311
    ')
    f1.seek(0)
    print('--->',f1.read())

    (2)上面的示例还没有实现修改的功能

    import time
    class FileHandle:
        def __init__(self,filename,mode='r',encoding='utf-8'):
            self.file=open(filename, mode, encoding=encoding)  # 调用的是系统提供open打开文件方法
            self.mode=mode
            self.encoding=encoding
    
        # 写的查找过程是:f1调用write方法,如果找到了就直接执行修改操作,不会再去管__getattr__了
        def write(self,line):  # f1传给self, 写入的内容11111等传给line去接
            # print('------------>',line)
            # 需求是:给写到文件里的内容,都要加上时间
            t=time.strftime('%Y-%m-%d %X')
            self.file.write('%s %s' %(t,line))
    
        def __getattr__(self, item):
            # 这个方式,相当于是文件里有什么方法,我就提供什么
            return getattr(self.file,item)
    
    f1=FileHandle('a.txt','w+')
    f1.write('1111111111342311
    ')
    f1.write('cpu负载过高
    ')
    f1.write('内存剩余不足
    ')
    f1.write('硬盘剩余不足
    ')
    
    # 上面写入了,就可以读出来了
    f1.seek(0)
    print('--->',f1.read())

    这个过程,为什么叫授权?哪一步实现了授权?

    import time
    class FileHandle:
        def __init__(self,filename,mode='r',encoding='utf-8'):
            # 1.self.file=open()类似于组合的方式,赋予了一个文件描述符
            self.file=open(filename, mode, encoding=encoding)
            self.mode=mode
            self.encoding=encoding
    
        # 3. 如果自己定制了方法,就可以重写原来的方法,实现项目所需要的需求。
        # 比如:写的时候剔除敏感词等
        # 原来的方法什么内容都可以写入,而现在去能够限制你不写入敏感词,这就类似实现了权限管理
        # 这就是授权(不要纠结于叫什么,理解意思)
        def write(self,line):
            t=time.strftime('%Y-%m-%d %X')
            self.file.write('%s %s' %(t,line))
    
        # 2.利用__getattr__的属性去找想要的属性;
        # 如果不定制,意味着所有的属性、方法都放开了。
        def __getattr__(self, item):
            return getattr(self.file,item)
  • 相关阅读:
    POX flow_stats2.py analysis by uestc_gremount
    C#基础知识点
    C++学了这么多年,你仍不知道的事
    VC7 HTML Dialog开发实例讲解
    VC与JavaScript交互(四) --- WebBrowser或CHtmlView中轻松屏蔽脚本错误(JavaScript)
    VC与JavaScript交互(三) --- CWebPage类调用javascript函数(给js函数传参,并取得返回值)
    VC与JavaScript交互(二) --- 调用JS函数
    VC与JavaScript交互(一) --- 如何实现
    动态链接库(VC_Win32)
    wcscpy wcscpy_s strcpy strcpy_s的区别
  • 原文地址:https://www.cnblogs.com/victorm/p/9346274.html
Copyright © 2011-2022 走看看