第三十五篇 类的内置属性(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) #
print(getattr(f1, 'y')) # # 调用不存在的属性
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\n')
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\n')
f1.write('cpu负载过高\n')
f1.write('内存剩余不足\n')
f1.write('硬盘剩余不足\n') # 上面写入了,就可以读出来了
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)
第三十五篇 类的内置属性(attr属性),包装和授权,__getattr__的更多相关文章
- 十五. Python基础(15)--内置函数-1
十五. Python基础(15)--内置函数-1 1 ● eval(), exec(), compile() 执行字符串数据类型的python代码 检测#import os 'import' in c ...
- Android UI开发第三十五篇——AppCompat实现Action Bar
每一位Android开发者对Action Bar这种设计都不陌生了,毕竟它已经发布了至少两年了.Android团队发布Action Bar设计规范时同时放出了ActionBar的Api来支持这种设计. ...
- 第三十九节,python内置全局变量
vars()查看内置全局变量 以字典方式返回内置全局变量 #!/usr/bin/env python # -*- coding:utf8 -*- print(vars()) #输出 # {'__bui ...
- Python之路(第三十五篇) 并发编程:操作系统的发展史、操作系统的作用
一.操作系统发展史 第一阶段:手工操作 —— 真空管和穿孔卡片 第一代之前人类是想用机械取代人力,第一代计算机的产生是计算机由机械时代进入电子时代的标志,从Babbage失败之后一直到第二次世界大 ...
- Python学习第十五篇——类继承和类实例化
学习Python类时,我们明白了类的本质,以及所谓的面向对象编程思想强调的对事物本身的属性,我们对某一类事物进行描述——采用了很多方法,这些方法描述了类的属性(比如猫科动物的眼睛,四肢,是否哺乳类等等 ...
- 第三十五篇-AppBarLayout的使用
效果图: 添加appbarlayout到xml文件中,然后在toolbar下面添加一个imageview并设置居中放置,我放置的是上面那个安卓的图标. 根据之前学过的toolbar那一节,结合view ...
- 第三十五篇 入门机器学习——Juptyer Notebook中的常用快捷键
1.运行当前Cell:Ctrl + Enter 2.运行当前Cell并在其下方插入一个新的Cell:Alt + Enter 3.运行当前Cell并选中其下方的Cell:Shift + ...
- C++第三十五篇 -- 写第一个驱动开发程序
VS2017+WDK+VMware12+Win10环境配置完毕,接下来写第一个驱动程序. 1.新建一个KMDF的程序. 2.配置项目属性. 3.编译项目.一般这里应该成功,我一台电脑成功了,另一台电脑 ...
- 第三十五篇:vue3,(组合式api的初步理解)
好家伙, 来一波核心概念:数据劫持是响应式的核心 1.由set up开始 (1)vue3中的一个新的配置项,值为一个函数. (2)组件中所用的到的:数据,方法,计算属性均要配置在set up中. (3 ...
随机推荐
- 一篇博客:分类模型的 Loss 为什么使用 cross entropy 而不是 classification error 或 squared error
https://zhuanlan.zhihu.com/p/26268559 分类问题的目标变量是离散的,而回归是连续的数值. 分类问题,都用 onehot + cross entropy traini ...
- CentOS6.6上进程挂起的诡异问题和处理
由于新的服务器不再支持CentOS5.4系统了,我们在新装机器上安装CentOS6.6.随着CentOS6.6机器的增多,我们逐渐注意到一个诡异问题:运行在这些机器上的某些进程,容易莫名其妙地挂起(举 ...
- 使用intellij idea创建JSP和引入Tomecat包
首先我们需要按照好intellij idea 如果没有安装好,这里有下载按照教程:https://www.cnblogs.com/weibanggang/p/9395702.html 首先我们创建一个 ...
- 【题解】洛谷P1463 [POI2002][HAOI2007] 反素数(约数个数公式+搜索)
洛谷P1463:https://www.luogu.org/problemnew/show/P1463 思路 约数个数公式 ai为质因数分解的质数的指数 定理: 设m=2a1*3a2*...*pak ...
- tracking
https://reid-mct.github.io/ 1st Workshop on Target Re-Identification and Multi-Target Multi-Camera ...
- JavaScript 表单处理
表单对象的属性 name action method encoding target elements 表单对象的方法 submit reset 表单元素事件 文本域事件:onFocus(获得焦点) ...
- 转载:EJB到底是什么
这篇博客用通俗易懂的语言对EJB进行了介绍,写得很好,笔者在这里转载一下. 链接:https://www.cnblogs.com/strugglion/p/6027318.html
- TCP回话劫持原理和利用
由于 TCP 协议并没有对 TCP 的传输包进行身份验证,所以在我们知道一个 TCP 连接中的 seq 和 ack 的信息后就可以很容易的伪造传输包,假装任意一方与另一方进行通信,我们将这一过程称为 ...
- web3.js_1.x.x--API(二)/合约部署与事件调用
web3.js_1.x.x的使用和网上查到的官方文档有些不同,我对经常使用到的API进行一些整理,希望能帮到大家 转载博客:http://www.cnblogs.com/baizx/p/7474774 ...
- MySQL单表数据查询(DQL)
数据准备工作: CREATE TABLE student( sid INT PRIMARY KEY AUTO_INCREMENT, sname ), age TINYINT, city ), scor ...