Pyhton——面向对象进阶一:反射、动态导入模块、类的内置attr属性
反射的四个方法
1、hasattr(object,name)——检测名字在不在这个对象里面
判断 object 中有没有一个 name 字符串对应的方法或属性
2、getattr(object,name,default=None)——找出名字所对应的属性的内容。默认值是none,如果不写,找不到的时候会报错;如果写了,找不到不会报错,会打印预置的内容
3、setattr(object,name,value)——给对象设置新属性(对象,名字,值)
上面代码中的 h1.name = Value 等价于 setattr()
4、delattr(object,name)——删除对象的属性
del h1.name
等价于上面的方法
以上的 name ,可以是类名!! 类的本质上也是一个对象
动态导入模块
一、普通导入模块
上面代码中,虽然导入的是m1文件夹里的 t.py ,但是拿到的依然是最顶层的 m1 ,如果要用到t.py里面的方法,还是要从最顶层的 点 下来
二、直接定位导入的模块
如果想要直接一步到位,直接定位想要导入的模块,可以使用 importlib 模块,使用里面的方法 importlib.import_module(),就可直接拿来用,不用像上面那么麻烦还要从最顶层 点 下来
动态导入底层就是基于反射来做的,可以发现这个导入模块的方法与上面的反射是有异曲同工之处。
类的内置attr属性
双下划线开头的attr方法
1、__getattr __ ——当调用类不存在的方法时,才会使用这个函数(这个方法最常用,其他的使用频率很少)
2、__delattr __ ——删除操作
至于为什么会进入无限递归,看下面
3、 __setattr __ ——设置操作
先来看原版的设置操作
此函数会把 value 赋给 key ,那么,我们手动设置此函数
但是这么设置以后,却会触发无限递归。我们来看看为什么会进入递归;首先一开始,实例化 h1 ,会触发__init __ 函数,设置 name 的时候就会触发 __setattr __ 函数,接着就是执行 self.key = value ,执行这一句又会触发__setattr __ 函数,因此进入无限递归。
那么该如何才能实现我们的目的呢? 答案是通过 属性字典 ,操作这个设置函数,本质是通过字典来设置,所以:
这样子,就能实现设置函数。通过上面的结果可以看到,实例化对象时,因为有两个参数需要赋值,所以触发了两次设置函数(这样印证了上面无限递归的结果)
总结一下:
print(h1.qqq) #只有属性不存在时,会自动触发__getattr__
def h1.qqq #删除属性时,会触发__delattr__
f1 h1 = 10 #设置属性的时候会触发__setattr__
但是,__setattr __ 跟 __delattr __ 这样使用更多的是在做多余的事情,本质上直接调用就是在做同样的事情,所以说这两种用法十分少。
包装——二次加工标准类型
例如常用的方法:
l = str()
这是在产生字符串,str 就可以看作是一个类, l 就是一个对象,其他的诸如元组,列表之类的都一样。只要是类,就可以封装多态继承。
包装主要是通过继承派生的概念做的。可以通过包装,改造原本就有的内置函数方法(比如append() 方法),或者增加方法。
授权——用组合的方式来完成
授权可以理解成,一个已经有的类,它允许给另外一个类使用某些功能,并且还能对这些功能进行修改,增加,删除等;而原有的类的其他没有改动过的功能,也能使用。(我把xx授权了给你,你有版权了,想干嘛就干嘛)
上面代码中,引入了 open 操作文件(把其看作一个类,通过了组合方式使用),使 Filehandle 这个类也能使用 open 里面的功能,这里就是授权了;接着要试着改写里面原有的 write 功能,原功能是写什么内容就出现什么内容,现在改写成写的内容前面出现时间,看下图红框部分:
这样一来,write 的原有功能就被改写了,而如果要调用原有的 read 功能或者其他,则还是能调用。