双下划线开头的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__的更多相关文章

  1. 十五. Python基础(15)--内置函数-1

    十五. Python基础(15)--内置函数-1 1 ● eval(), exec(), compile() 执行字符串数据类型的python代码 检测#import os 'import' in c ...

  2. Android UI开发第三十五篇——AppCompat实现Action Bar

    每一位Android开发者对Action Bar这种设计都不陌生了,毕竟它已经发布了至少两年了.Android团队发布Action Bar设计规范时同时放出了ActionBar的Api来支持这种设计. ...

  3. 第三十九节,python内置全局变量

    vars()查看内置全局变量 以字典方式返回内置全局变量 #!/usr/bin/env python # -*- coding:utf8 -*- print(vars()) #输出 # {'__bui ...

  4. Python之路(第三十五篇) 并发编程:操作系统的发展史、操作系统的作用

    一.操作系统发展史 第一阶段:手工操作 —— 真空管和穿孔卡片 ​ 第一代之前人类是想用机械取代人力,第一代计算机的产生是计算机由机械时代进入电子时代的标志,从Babbage失败之后一直到第二次世界大 ...

  5. Python学习第十五篇——类继承和类实例化

    学习Python类时,我们明白了类的本质,以及所谓的面向对象编程思想强调的对事物本身的属性,我们对某一类事物进行描述——采用了很多方法,这些方法描述了类的属性(比如猫科动物的眼睛,四肢,是否哺乳类等等 ...

  6. 第三十五篇-AppBarLayout的使用

    效果图: 添加appbarlayout到xml文件中,然后在toolbar下面添加一个imageview并设置居中放置,我放置的是上面那个安卓的图标. 根据之前学过的toolbar那一节,结合view ...

  7. 第三十五篇 入门机器学习——Juptyer Notebook中的常用快捷键

        1.运行当前Cell:Ctrl + Enter   2.运行当前Cell并在其下方插入一个新的Cell:Alt + Enter   3.运行当前Cell并选中其下方的Cell:Shift + ...

  8. C++第三十五篇 -- 写第一个驱动开发程序

    VS2017+WDK+VMware12+Win10环境配置完毕,接下来写第一个驱动程序. 1.新建一个KMDF的程序. 2.配置项目属性. 3.编译项目.一般这里应该成功,我一台电脑成功了,另一台电脑 ...

  9. 第三十五篇:vue3,(组合式api的初步理解)

    好家伙, 来一波核心概念:数据劫持是响应式的核心 1.由set up开始 (1)vue3中的一个新的配置项,值为一个函数. (2)组件中所用的到的:数据,方法,计算属性均要配置在set up中. (3 ...

随机推荐

  1. likelihood(似然) and likelihood function(似然函数)

    知乎上关于似然的一个问题:https://www.zhihu.com/question/54082000 概率(密度)表达给定下样本随机向量的可能性,而似然表达了给定样本下参数(相对于另外的参数)为真 ...

  2. Softmax vs. Softmax-Loss: Numerical Stability

    http://freemind.pluskid.org/machine-learning/softmax-vs-softmax-loss-numerical-stability/ softmax 在 ...

  3. 【洛谷P2607】[ZJOI2008]骑士

    骑士 题目链接 这道题一看,似乎和舞会是一样的,然而它并没有保证是一棵树 但是,对于每个连通块,必有相同的点数和边数,这样的图一定是一棵树上加一条边 这条边一定回使图中形成一个环,这种图貌似叫“基环树 ...

  4. 【luogu P3369 【模板】普通平衡树(Treap/SBT)】 题解 pb_ds

    我永远都爱STL ! 我爱PB_DS ! #include <iostream> #include <cstdio> #include <ext/pb_ds/tree_p ...

  5. autofac 注册

    1 注册的概念和方式 使用autofac 的ContainerBuilder 来注册组件(components---通常指实现类),并把它的服务(service---通常指接口,抽象类,类实例)暴露给 ...

  6. LinQ 简介

    LinQ是3.0新加的语法.用起来比较方便,我们可以使用较简单的方法来过滤数据和处理数据. 使用场景: 可以看到LINQ使用场景还是很多的.现在写项目基本都会用到. 在出现委托之前,我们来查找对象 在 ...

  7. swiper插件使用技巧

    1.加载插件: <!DOCTYPE html> <html> <head> ... <link rel="stylesheet" href ...

  8. 还在占用存储的进程lsof grep deleted;

    查看僵尸进程 lsof grep deleted; 用于查看已经停止但还在占用存储的进程

  9. Showing All Messages : error: open /Users/apple/Library/Developer/Xcode/DerivedData/xxx-dkhmpttmnuppvbcxijlcxacfpzcl/Build/Products/Debug-iphoneos/xxx.app/EaseUIResource.bundle/arrow@2x.png: N

    2报错 Showing All Messages : error: open /Users/apple/Library/Developer/Xcode/DerivedData/xxx-dkhmpttm ...

  10. hdu 3966 Aragorn's Story : 树链剖分 O(nlogn)建树 O((logn)²)修改与查询

    /** problem: http://acm.hdu.edu.cn/showproblem.php?pid=3966 裸板 **/ #include<stdio.h> #include& ...