8.自省反射 和 类内置方法
反射四个方法的使用:
hasattr(result, "name")
getattr(result, "name", "bill")
setattr(result, "name", "bill")
delattr(result, "name")
反射的用处:
- 动态增加属性,包括数据属性和方法属性
# 声明方
class Dad(metaclass=abc.ABCMeta):
def __init__(self, name):
self.name = name
# 模拟外部使用方
dad1 = Dad("bill")
if hasattr(dad1, "eatFood"):
eatFood_func = getattr(dad1,"eatFood")
eatFood_func()
else:
pass
- 动态导入模块
方式1:__import__("sys")
方式2:
import importlib
m = importlib.import_module("m1.t")
m.test()
使用super
继承包装父类方法:
# 继承自系统类list 重写系统类的方法
class NewList(list):
def append(self, obj):
if type(obj) is str:
super().append(obj)
list1 = NewList()
list1.append("adf") # 添加成功
list1.append(123) # 添加失败
类内置方法:
🎈类内置__getattribute__
方法:
访问类属性,就是访问__getattribute__
方法,如果没有找到访问的属性,则抛出异常,执行__getattr__
方法
def __getattribute__(self, item):
raise AttributeError("抛出异常 去执行__getattr__")
def __getattr__(self, item):
pass
🎈类内置__getattr__
方法:
访问类属性的时候,如果有该属性,则不触发__getattr__
方法,如果没有该属性,则触发__getattr__
方法
🎈类内置__delattr__
方法:
只要访问属性就会触发
🎈类内置__setattr__
方法只要访问属性就会触发,可以使用设置属性字典__dict__
的方法来防止递归死循环
🎈类内置__getitem__
__setitem__
等方法,是通过字典resuslt["name"]
这种方式取、设置、删除属性等操作触发
🎈使用__str__
来改变对象的打印信息:
class Foo:
def __str__(self):
return "这是"
print(Foo())
🎈使用__repr__
来改变对象在解释器中的打印信息:
优先找__str__
,没有会找__repr__
🎈使用__format__
来格式化定制打印信息
🎈使用__slots__
来节省内存,只能使用声明的属性
class Foo:
__slots__ = ["name", "age"]
🎈使用__module__
和__class__
查看对象所在的模块和类
🎈__del__
析构方法
🎈使用__call__
定义call方法Foo()
迭代器:
🎈使用__next__
和__iter__
实现迭代器协议
迭代器协议:对象必须提供一个next
方法,执行该方法返回迭代中的下一项,或者 到最后一项后抛出StopIteration
异常,以终止迭代。
可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义了一个__iter__
方法)
调用for in
循环,实际就是调用对象的iter(obj)
方法,也即obj.__iter__
方法,装换成迭代器对象,然后执行对象的__next__
方法。
对于一个自定义类,想要实现迭代器协议,可以重写如下方法:
def __iter__(self):
return self
def __next__(self):
if xxx:
raise StopIteration("终止")
return xxx
访问优先级:
1. 类属性
2. 数据描述符
3. 实例属性
4. 非数据描述符
5. 找不到属性触发__getattr__()
上下文管理协议with as
使用__enter__
和__exit__
方法
如果执行with as
过程中程序异常,会直接执行__exit__
并抛出异常,如果__exit__
中返回True,则会忽略掉异常继续执行