目录:
一、构造和初始化
二、属性访问控制
三、描述符协议
四、自定义容器(Container)
五、上下文管理器
六、可调用对象(__call__方法)
Python魔法方法(魔术方法)
在Python中,所有以双下划线包起来的方法,都统称为"魔法方法"。
一、构造和初始化
- __new__是在实例创建之前被调用的。因为它的任务就是创建实例然后返回该实例,是个静态方法。
- __init__是在实例对象创建完成后被调用的。然后设置对象属性的一些初始值。
二、属性访问控制
- __getattr__(self, name): 访问不存在的属性时调用。
- __getattribute__(self, name):访问存在的属性时调用(先调用该方法,查看是否存在该属性,若不存在,接着去调用__getattr__)。
- __setattr__(self, name, value):设置实例对象的一个新的属性时调用。
- __delattr__(self, name):删除一个实例对象的属性时调用 。
三、描述符协议
描述符是一个类,定义了访问另一个类属性的方式。提高属性访问控制代码可复用性。
实现了__get__()、__set__()、__delete__() 其中至少一个方法的类,就是一个描述符:
- 实现了__get__()和__set__()的描述符称为数据描述符。
- 只实现了__get__()的描述符称为非数据描述符。
- __get__: 用于访问属性。它返回属性的值,若属性不存在、不合法等都可以抛出对应的异常。
- __set__:将在属性分配操作中调用。不会返回任何内容。
- __delete__:控制删除操作。不会返回内容。
四、自定义容器(Container)
在Python中,如果我们想实现创建类似于序列和映射的类(可以迭代以及通过[下标]返回元素),可以通过重写魔法方法__getitem__、__setitem__、__delitem__、__len__方法去模拟。
- __getitem__(self,key):返回键对应的值。
- __setitem__(self,key,value):设置给定键的值。
- __delitem__(self,key):删除给定键对应的元素。
- __len__():返回元素的数量。
五、上下文管理器
1.使用类
在一个类里,如果实现了__enter__和__exit__方法,这个类的实例就是一个上下文管理器。
在编写代码时,可以将资源的连接或者获取放在__enter__中,而将资源的关闭写在__exit__ 中。__enter__中需要返回当前实例对象。
上下文管理器的作用:
- 可以以一种更加优雅的方式,操作(创建/获取/释放)资源,如文件操作、数据库连接。
- 可以以一种更加优雅的方式,处理异常。(处理异常通常都是使用 try...execept... 来捕获处理的。这样做一个不好的地方是,在代码的主逻辑里,会有大量的异常处理代理,这会很大的影响我们的可读性。)
- __enter__:进入方法。
- __exit__:退出方法。
class ContextManager:
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""
:param exc_type: 异常类型
:param exc_val: 异常实例
:param exc_tb: 堆栈信息(traceback对象)
:return: 如果返回True则代表已经正确处理异常。如果返回True以外其他值,则代表异常未处理,则将异常层层上报。
"""
return True
示例1:
class Resource:
def __enter__(self):
print('===connect to resource===')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('===close resource connection===')
def operate(self):
print('===in operation===')
with Resource() as res:
res.operate()
2.使用contextlib
以yield为分界点:
- yield之前的代码相当于__enter__中的代码。
- yield之后的值相当于__enter__的返回值。
- yield之后的代码相当于__exit__中的代码。
import contextlib
@contextlib.contextmanager
def context_manager():
# __enter__方法
print('===connect to resource===')
try:
yield __enter__方法的返回值
except Exception:
print("抛出异常!")
# __exit__方法
print('===close resource connection===')
六、可调用对象(__call__方法)
所有的函数都是可调用对象。
一个类实例也可以变成一个可调用对象,只需要实现一个特殊方法__call__()。
示例:斐波那契数列
class Fib:
def __init__(self):
pass
def __call__(self, num):
a, b = 1, 1\_\_call\_\_方法
self.list = []
for i in range(num):
self.list.append(a)
a, b = b, a+b
return self.list
def __str__(self):
return str(self.list)
f = Fib()
print(f(10))