python二次加工标准类型 | 包装与授权

news2024/7/4 5:32:12

在这里插入图片描述

欢迎关注博主 Mindtechnist 或加入【Linux C/C++/Python社区】一起学习和分享Linux、C、C++、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和技术。


包装与授权

    • 包装
    • 授权
    • \_\_setattr__,\_\_delattr\_\_,\_\_getattr\_\_
    • \_\_getattribute__


专栏:《python从入门到实战》


所有便准数据类型都可以通过两种方式产生,一种是直接定义,一种是使用相应的函数,比如要产生字符串,可以s=’hello’或s=str(hello)。像str这种函数都是工厂函数,实际上工厂函数都是类,我们可以通过继承这些类来定制自己的数据类型。(包装)

包装

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

二次加工标准类型(基于继承实现)

class List(list): #继承list所有的属性,也可以派生出自己新的,比如append和mid
    def append(self, p_object):
        ' 派生自己的append:加上类型检查'
        if not isinstance(p_object,int): #if type(p_object) is int:
            raise TypeError('must be int')
        #self.append(p_object) #死循环
        #list.append(self, p_object) #调用父类的方法
super().append(p_object) #调用父类的方法

    @property
    def mid(self):
        '新增自己的属性'
        index=len(self)//2
        return self[index]

l=List([1,2,3,4])
print(l)
l.append(5)
print(l)
# l.append('1111111') #报错,必须为int类型

print(l.mid)

#其余的方法都继承list的
l.insert(0,-123)
print(l)
l.clear()
print(l)

clear加权限限制

class List(list):
    def __init__(self,item,tag=False):
        super().__init__(item)
        self.tag=tag
    def append(self, p_object):
        if not isinstance(p_object,str):
            raise TypeError
        super().append(p_object)
    def clear(self):
        if not self.tag:
            raise PermissionError
        super().clear()

l=List([1,2,3],False)
print(l)
print(l.tag)

l.append('saf')
print(l)

# l.clear() #异常

l.tag=True
l.clear()

授权

授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能。其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。
授权是采用已存在的功能达到最大限度的代码重用。在包装中我们可以新建、修改或删除已有的功能,授权的过程就是将更新的功能交由新类来处理,已存在的功能就授权给对象的默认属性。
实现授权的关键点就是覆盖__getattr__方法 (包装是通过继承实现)。在代码里包含一个对getattr()内建函数的调用,调用getattr()得到默认对象的属性(数据属性或者方法)并返回它,以便于访问或者调用。
当引用一个属性时,解释器首先会在局部名称空间中查找那个名字,比如一个自定义的方法或局部实例属性。如果没有在局部字典中找到,则搜索类名称空间,以防一个类属性被访问。最后,如果两类搜索都失败了,搜索则对原对象开始授权请求,此时__getattr__()会被调用。

示例1

import time
class FileHandle:
    def __init__(self,filename,mode='r',encoding='utf-8'):
        self.file=open(filename,mode,encoding=encoding)
    def write(self,line): #定制自己的write方法 – 对写入的内容加上时间
        t=time.strftime('%Y-%m-%d %T')
        self.file.write('%s %s' %(t,line))

    def __getattr__(self, item):
        return getattr(self.file,item)# self.file是通过系统默认的open获取的,它包含了默认open的所有方法,item是一个字符串,getattr以字符串形式调用方法

f1=FileHandle('b.txt','w+')
f1.write('你好啊')
f1.seek(0)
print(f1.read()) 
f1.close()

在实例和类FileHandle中都没有找到该属性,所以触发__getattr__先找f1的属性字典,没有则找类FileHandle的属性字典,没有则触发__getattr__,__getattr__中调用的是系统open返回的文件描述符的方法,通过自己的类实例化,调用系统的方法。

示例2

#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
#我们来加上b模式支持
import time
class FileHandle:
    def __init__(self,filename,mode='r',encoding='utf-8'):
        if 'b' in mode:
            self.file=open(filename,mode)
        else:
            self.file=open(filename,mode,encoding=encoding)
        self.filename=filename
        self.mode=mode
        self.encoding=encoding

    def write(self,line):
        if 'b' in self.mode:
            if not isinstance(line,bytes):
                raise TypeError('must be bytes')
        self.file.write(line)

    def __getattr__(self, item):
        return getattr(self.file,item)

    def __str__(self):
        if 'b' in self.mode:
            res="<_io.BufferedReader name='%s'>" %self.filename
        else:
            res="<_io.TextIOWrapper name='%s' mode='%s' encoding='%s'>" %(self.filename,self.mode,self.encoding)
        return res
f1=FileHandle('b.txt','wb')
# f1.write('你好啊啊啊啊啊') #自定制的write,不用在进行encode转成二进制去写了
f1.write('你好啊'.encode('utf-8'))
print(f1)
f1.close()

示例3

class List:
    def __init__(self,seq):
        self.seq=seq

    def append(self, p_object):
        ' 派生自己的append加上类型检查,覆盖原有的append'
        if not isinstance(p_object,int):
            raise TypeError('must be int')
        self.seq.append(p_object)

    @property
    def mid(self):
        '新增自己的方法'
        index=len(self.seq)//2
        return self.seq[index]

    def __getattr__(self, item):
        return getattr(self.seq,item)

    def __str__(self):
        return str(self.seq)

l=List([1,2,3])
print(l)
l.append(4)
print(l)
# l.append('3333333') #报错,必须为int类型

print(l.mid)

#基于授权,获得insert方法
l.insert(0,-123)
print(l)

示例4

class List:
    def __init__(self,seq,permission=False):
        self.seq=seq
        self.permission=permission
    def clear(self):
        if not self.permission:
            raise PermissionError('not allow the operation')
        self.seq.clear()

    def __getattr__(self, item):
        return getattr(self.seq,item)

    def __str__(self):
        return str(self.seq)
l=List([1,2,3])
# l.clear() #此时没有权限,抛出异常


l.permission=True
print(l)
l.clear()
print(l)

#基于授权,获得insert方法
l.insert(0,-123)
print(l)

__setattr__,__delattr__,__getattr__

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 #这就无限递归了,因为设置属性会触发__setattr__
        # self.__dict__[key]=value #应该使用它,直接修改底层字典

    def __delattr__(self, item):
        print('----> from delattr')
        # del self.item #无限递归了
        self.__dict__.pop(item)# 直接在底层字典删除,就不会触发了

#__setattr__添加/修改属性会触发它的执行
f1=Foo(10)
print(f1.__dict__) # 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值
f1.z=3
print(f1.__dict__)

#__delattr__删除属性的时候会触发
f1.__dict__['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作
del f1.a
print(f1.__dict__)

#__getattr__只有在使用点调用属性且属性不存在的时候才会触发
f1.xxxxxx

getattr(obj)相当于obj.__getattr__()
setattr(obj)相当于obj.__setattr__()
delattr(obj)相当于obj.__delattr__()

  • 类的内置attr属性,你不定义的话会用默认的,如果定义了则用自己定义的。
  • class.at 调用时触发:如果类class中属性at不存在,则触发__getattr__
  • del class.at删除时触发:删除类class的属性at时,触发__delattr__
  • class.at=1设置时触发:设置类class的属性at时,触发__setattr__

自己定义这三个函数,在相应操作时,就可以触发自己想要的逻辑。

class MyClass:
def __init__(self, name)
    self.name = name #触发__setattr__
def __getattr__(self, item) #默认的__getattr__是属性不存在则报错,我们修改后不报错,仅打印提示
    print(“attr [%s] not found” %item)
def __setattr__(self, k, v) #默认的setattr会把设置的属性加在属性字典,但是我们自定义的setattr什么也没做,属性字典不会增加属性
    print(set attr’, k, v)
    if tyoe(v) is str: #限制value只能以字符串的形式设置
        print(set)
        #self.k = v #再次触发__setattr__,进入死循环
        self.__dict__[k] = v.upper() 
#真正的设置 – 直接操作底层数据结构,在属性字典中添加
    else:
        print(not str)
def __delattr__(self, item)
    """ #自己控制-所有属性不可删除
    print(‘can not delete [%s]’ %item)
    pass
    """
    print(‘delete attr[%s]%item)
    #del self.item #触发__delattr__ 进入死循环
    self.__dict__.pop(item) #真正的删除

mc = MyClass(‘hello’) #实例化的时候会触发__init__
print(mc.name) #hello
print(mc.hhh) #触发__getattr__  mcself  hhhitem(字符串的形式)
mc.age = 18
mc.age =18#触发__setattr__  mcself  agek  ‘18’v
del mc.name #触发__delattr__  mcself  name item(字符串的形式)

__getattribute__

#__getattr__
class Foo:
    def __init__(self,x):
        self.x=x

    def __getattr__(self, item):
        print('执行的是我')
        # return self.__dict__[item]

f1=Foo(10)
print(f1.x)
f1.xxxxxx #不存在的属性访问,触发__getattr__
#__getattribute__ - 不管属性是否存在,都会触发
class Foo:
    def __init__(self,x):
        self.x=x

    def __getattribute__(self, item):
        print('不管是否存在,我都会执行')

f1=Foo(10)
f1.x
f1.xxxxxx

如果二者同时出现

#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'

class Foo:
    def __init__(self,x):
        self.x=x

    def __getattr__(self, item):
        print('执行的是我')
        # return self.__dict__[item]
    def __getattribute__(self, item):
        print('不管是否存在,我都会执行')
        raise AttributeError('哈哈') #抛出AttributeError异常–跳转到__getattr__

f1=Foo(10)
f1.x
f1.xxxxxx

当__getattribute__与__getattr__同时存在,只会执行__getattribute__,除非__getattribute__在执行过程中抛出异常AttributeError,系统默认的__getattribute__,如果查找的属性不存在,当抛出异常AttributeError的时候,会跳转到__getattr__,也就是说,只有抛出异常AttributeError的时候,才会执行__getattr__,其他情况下只会执行__getattribute__。系统提供的默认__getattribute__,当要查找的属性存在时,会在当前属性字典中返回属性,如果要找的属性不存在会抛出异常AttributeError,转到__getattr__去执行,__getattr__接收异常来避免程序崩溃,并执行定义好的逻辑。

在这里插入图片描述


在这里插入图片描述
在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/517296.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

洽洽离年轻人更近了,陈先保离百亿KPI呢?

文|螳螂观察 作者|图霖 留给陈先保实现百亿营收的时间不多了。 过去几年&#xff0c;洽洽凭借着在产品端、市场端、供应端的绝对实力&#xff0c;守住了休闲零食行业龙头的地位。但最新发布的2023年第一季度业绩报告&#xff0c;却出现了6年来首次营收、净利双双下降。 报告…

Excel大数据量单元格快速填充

个人简介&#xff1a;一个从会计转行数据分析师的三旬老汉 擅长领域&#xff1a;数据分析、数据仓库、大数据 博客内容&#xff1a;平时会将自己工作中遇到的问题进行归纳总结&#xff0c;分享给各位小伙伴&#xff0c;意在帮助大家少加班、不掉发&#xff0c;让我们相互学习&a…

const/static修饰成员函数+初始化列表

一、const修饰成员函数 首先&#xff0c;我们知道&#xff0c;所有的成员函数&#xff08;除static修饰的&#xff09;&#xff0c;编译器都会隐式传递一个this指针。 它的默认类型为 Type* const this&#xff0c;即this指针只能指向最左边的第一个传入的对象。 const修饰成…

Docker容器体系结构及特点

Docker容器体系结构及特点 Docker是一个应用容器引擎&#xff0c;通过Docker&#xff0c;管理员可以非常方便地对容器进行管理。Docker基于Go语言开发&#xff0c;并且遵从Apache 2.0开源协议。 Docker提供了对容器镜像的打包封装功能。利用Docker&#xff0c;开发者可以将他…

2023 最新版IntelliJ IDEA 2023.1创建Java Web 项目详细步骤(图文详解)

文章目录 &#x1f9ed; 版本情况JavaIDEATomcatmaven &#x1f30f; 创建步骤&#x1f697; 1、依次点击File >> New >> Project&#x1f693; 2、选择New Project 输入自己的项目名&#xff0c;选择JDK版本&#xff0c;而后点击create进行创建&#x1f695; 3、鼠…

开新能源汽车有充电焦虑吗?2022年国内充电桩数量已达521万台

哈喽大家好&#xff0c;新能源汽车的不断普及使充电桩市场快速发展起来&#xff0c;同时充电桩的技术正在不断改进&#xff0c;包括充电速度、安全性、互联网功能等多个方面。相比与日渐壮大的新能源汽车用户规模&#xff0c;充电桩的建设相对发展速度较慢&#xff0c;近几年来…

网络编程代码实例:守护进程版

文章目录 前言代码仓库内容目录结构代码结果总结参考资料作者的话 前言 网络编程代码实例&#xff1a;守护进程版。 代码仓库 yezhening/Environment-and-network-programming-examples: 环境和网络编程实例 (github.com)Environment-and-network-programming-examples: 环境…

XShell配置以及使用教程

目录 1、XShell介绍 2、安装XShell 1. 双击运行XShell安装文件&#xff0c;并点击“下一步” 2. 点击“我接受许可证协议中的条款”&#xff0c;点击“下一步” 3. 点击“浏览”更改默认安装路径&#xff0c;点击“下一步” 4. 直接点击“安装” 5. 安装完成&#xff0…

C语言小游戏的实现——三子棋

前言 Hello&#xff01;友友们&#xff0c;前边我们已经学习了C语言的基础知识&#xff0c;但单纯的理论和简单的代码演示是无法真正做到巩固所学的知识的&#xff0c;那么今天我将会带领大家&#xff0c;根据之前所学的知识&#xff0c;来写一个三子棋小游戏。 目录 前言 总…

从C出发 31 --- 指针专题经典问题剖析

int a 0; int* p &a; //p作为指针指向了a, p 保存的是a 变量的内存地址&#xff0c;// p 这个指针本质是变量&#xff0c;这个变量有没有内存地址&#xff1f;// 有内存地址&#xff0c;为什么&#xff1f;// 因为它作为变量&#xff0c;肯定要占用内存空间的// p 这个变…

第十一章 使用Bind提供域名解析服务

文章目录 第十一章 使用Bind提供域名解析服务一、DNS域名解析服务1、DNS简介2、服务器类型3、13台根DNS服务器的具体信息 二、安装Bind服务程序1、Bind简介2、Bind安装3、关键配置文件4、修改主配置文件5、正向解析实验&#xff08;1&#xff09;、编辑区域配置文件&#xff08…

processing官方教程笔记(附加官网链接)更新中~

官方参考文档&#xff1a;https://processing.org/reference 官网视频&#xff1a;https://www.youtube.com/user/shiffman/playlists?view50&sortdd&shelf_id2 b站up主转载官方视频&#xff1a;https://www.bilibili.com/video/BV147411d7kY?p1&vd_source07ce5c…

【计算机三级网络技术】 第六篇 真题练习

文章目录 IPS&#xff08;入侵防护系统&#xff09;相关知识点蓝牙服务器技术DNS 服务器WWW 服务器FTP 服务器邮件&#xff08;Winmail 邮件服务器&#xff09;生成树协议IEEEVLAN 标识的描述DHCP 服务器 IPS&#xff08;入侵防护系统&#xff09;相关知识点 1、入侵防护系统&…

迪赛智慧数——柱状图(象形标识图):在选择另一半时,你更看重的是?

效果图 好看只排第六&#xff0c;第一确实众望所归&#xff01;当代男女择偶标准出炉&#xff0c;一张图带你看清。 女性挑选另一半时&#xff0c;她们更看重伴侣收入高、职业体面、工作能力强、受教育程度高&#xff0c;还得和自己有共同话题。 男性择偶观和女性恰恰相反&am…

第二届网刃部分WP

第二届网刃部分WP 玩坏的winxp 用VM打开附件时候打不开&#xff0c;后来用DiskGenius软件打开&#xff0c;发现桌面中存在有五张图片 在图片meiren.png中发现有隐藏压缩包 foremost分离文件&#xff0c;发现图片 010查看发现还有一层压缩包&#xff0c;再次分离发现压缩包…

自动售货机程序找零博图程序实现

1、操作界面 2、程序实现 REGION 找零确认 IF #找零确认 THEN //复位 #"50元张数" : 0.0; #"20元张数" : 0.0; #"10元张数" : 0.0; #"5元张数" : 0.0; #"1元张数…

Mysten Labs宣布推出积极贡献者和早期支持者ACES计划

Mysten Labs宣布推出积极贡献者和早期支持者&#xff08;ACES&#xff0c;Active Contributors & Early Supporters&#xff09;计划。这是对进入Sui主网的社区成员所做努力的巨大认可。 如果您在5月3日Sui主网启动之前就加入Sui Discord&#xff0c;请于5月18日凌晨2点&a…

JUC并发编程16 | CAS自旋锁

CAS自旋锁 是什么&#xff0c;干什么&#xff0c;解决了什么痛点&#xff1f;如何解决&#xff0c;如何使用。 原子类&#xff1a;java.util.concurrent.atomic 在没有CAS之前&#xff0c;多线程环境不使用原子类保证线程安全i等操作&#xff0c;会出现数据问题&#xff0c;…

LeetCode特训 -- Week3 (字符串)

目录 字符串基础 字符串基本操作 字符串匹配算法 字符串异位词问题 分组分类问题和快速查找数据结构之间存在一定的关系。 字符串回文串问题 留下悬念&#xff1a;高级字符串算法题目(字符串 dp) 字符串基础 字符串定义&#xff1a;n个字符顺次排列而成的序列. 子串&…

MySQL好玩新特性:离线模式

GreatSQL社区原创内容未经授权不得随意使用&#xff0c;转载请联系小编并注明来源。GreatSQL是MySQL的国产分支版本&#xff0c;使用上与MySQL一致。作者&#xff1a;Yejinrong/叶金荣文章来源&#xff1a;GreatSQL社区原创 继续吹MySQL 8.0~ 在以前&#xff0c;当需要对MySQL数…