Python魔法方法

目录:
一、构造和初始化
二、属性访问控制
三、描述符协议
四、自定义容器(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()
运行结果1

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))
运行结果

你可能感兴趣的:(Python魔法方法)