• 23、面向对象(包装)



    23.1、包装介绍:

    1、什么是包装(继承+派生):

    python为大家提供了标准数据类型以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,

    新增/改写方法,这就用到了继承/派生知识,标准类型均可以通过包装的方式进行二次加工。


    2、授权:

    授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建、修改或删除原有产品的功能,其它的则

    保持原样。授权的过程即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。

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


    3、包装时用到的类方法:

    (1)__getattr__

    在调用对象属性且对象属性不存在的时候才会触发它的执行

    (2)__setattr__

    在添加或修改对象属性的时候会触发它的执行

    (3)__delattr__

    在删除对象属性的时候会触发它的执行

    (4)补充:已上函数方法默认在类中是自带的,如果在类中声明会自动覆盖类中默认设置;


    23.2、__getattr__、setattr、__delattr__ 示例:

    1、基础:

    class Foo:

    x=1

    def __init__(self,y):

    self.y=y


    # 在调用对象属性且对象属性不存在的时候才会触发它的执行

    def __getattr__(self, item):

    print('----> from getattr:你找的属性不存在')


    # 在添加或修改对象属性的时候会触发它的执行

    def __setattr__(self, key, value):

    print('----> from setattr')

    # self.key=value

    # 这样赋值会无限递归,因为每当对象赋值时都会调用该函数,这样实际上又是

    # 在为对象赋值,又会调用该函数,所以会无限的递归下去。

    self.__dict__[key]=value

    # 正确的赋值方法是直接操作对象的属性字典。

    # 因为重写了 __setattr__ 如果不写,那么对象就会无法赋值;


    # 在删除对象属性的时候会触发它的执行

    def __delattr__(self, item):

    print('----> from delattr')

    # del self.item

    # 这样赋值会无限递归,和 __setattr__ 原理一致。

    self.__dict__.pop(item)

    # 正确的赋值方法是直接操作对象的属性字典。


    #__setattr__

    f1=Foo(10)

    # ----> from setattr

    f1.z=3

    # ----> from setattr

    print(f1.__dict__)

    # {'y': 10, 'z': 3}


    # __delattr__

    del f1.z

    # ----> from delattr

    print(f1.__dict__)

    # {'y': 10}


    # __getattr__

    print(f1.x)

    # 1

    f1.xxxxxx

    # ----> from getattr:你找的属性不存在


    2、限制对象输入的类型:

    class Foo:

    def __init__(self, name,age):

    self.name = name

    self.age=age


    def __getattr__(self, item):

    print('你找的属性【%s】不存在' % item)


    def __setattr__(self, key, value):

    if type(value) is str:

    self.__dict__[key] = value.upper()

    else:

    print('[%s]属性必须是字符串类型' %key)


    def __delattr__(self, item):

    print('不允许删除属性【%s】' % item)


    f1 = Foo('lc','19')


    # __setattr__

    f1.age=22

    # [age]属性必须是字符串类型

    print(f1.__dict__)

    # {'name': 'LC', 'age': '19'}


    # __getattr__

    f1.slary

    # 你找的属性【slary】不存在

    print(f1.__dict__)

    # {'name': 'LC', 'age': '19'}


    # __delattr__

    del f1.age

    # 不允许删除属性【age】

    print(f1.__dict__)

    # {'name': 'LC', 'age': '19'}


    23.3、包装示例:

    1、包装:

    class List(list):

    # 继承list所有的属性,也可以派生出自己新的,比如append和mid

    def append(self, p_object):

    '派生自己的append:加上类型检查'

    if isinstance(p_object, int):

    super(List,self).append(p_object)

    else:

    print(TypeError('must be int'))


    @property

    def mid(self):

    '新增自己的属性'

    index = len(self) // 2

    return self[index]


    l = List([1,2,3,4])

    # 因为新定义的List类继承了list类,所以可以使用List类直接进行初始化

    print(l)

    # [1, 2, 3, 4]

    l.append(5)

    print(l)

    # [1, 2, 3, 4, 5]

    l.append('1')

    # must be int


    print(l.mid)

    # 3


    # 其余的方法都继承list的

    l.insert(0, 'lc')

    print(l)

    # ['lc', 1, 2, 3, 4, 5]

    l.clear()

    print(l)

    # []


    2、授权:

    import time

    class FileHandle:

    def __init__(self,filename,mode='r',encoding='utf-8'):

    self.file=open(filename,mode,encoding=encoding)

    def write(self,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('b.txt','w+')

    f1.write('你好啊')

    f1.seek(0)

    print(f1.read())

    f1.close()









  • 相关阅读:
    P2257 YY的GCD(莫比乌斯反演)
    P2522 [HAOI2011]Problem b(莫比乌斯反演)
    HAProxy 配置文件
    Android5.1 默认主launcher、强制主launcher
    【Spring 从0开始】IOC容器的Bean管理
    【Spring 从0开始】IOC容器的Bean管理
    【Spring 从0开始】IOC容器的Bean管理
    Linux 命令里两个连续的减号(--)是表示什么?
    从k8s集群中删除节点后重新加入的方法
    下载外网docker镜像的方法
  • 原文地址:https://www.cnblogs.com/LiuChang-blog/p/12320489.html
Copyright © 2020-2023  润新知