选择了哈利波特里的这张图,但可惜没找到带蛇的 haha。
没怎么用过 Python 的魔法方法,只用过几个 __init__ 和上下文管理器的几个,今天记录一下。
magic method
An informal synonym for special method.
一个非正式的同义词,指的是特殊方法。
官方的名称是 special method.
special method
A method that is called implicitly by Python to execute a certain operation on a type, such as addition. Such methods have names starting and ending with double underscores. Special methods are documented in Special method names.
特殊方法是 Python 隐式调用的,用于执行某种操作(如加法)的类型方法。这些方法的名称以双下划线开头和结尾。特殊方法在特殊方法名称中有文档说明。
比如 __add__ 用于实现加法操作,__len__ 用于实现 len() 函数。
假如自定义一个 CustomList 类,想让它支持 len() 函数,但是要返回负数,就可以实现 __len__ 方法:
1 | class CustomList: |
在这个例子中,CustomList 类实现了 __len__ 方法,当调用 len(my_list) 时,实际上是调用了 my_list.__len__() 方法,返回了负数的长度。
魔法方法有时候被函数调用,有时候被运算符调用,还有时候被内置语句调用。
魔法方法还有很多,在这里列出一些常见的:
-
__init__(self, ...):对象初始化方法,在初始化对象时调用。 -
__new__(cls, ...):对象创建方法,返回一个实例。注意:它不需要self参数,因为它是一个静态方法。 -
__str__(self):定义对象的字符串表示形式,当使用str()或print()时调用。 -
__repr__(self):定义对象的官方字符串表示形式,通常用于调试。 -
__add__(self, other):定义加法操作符+的行为。当然也有__sub__、__mul__、__truediv__、等,这类运算符相关的内容,详见 Emulating numeric types -
__eq__(self, other):定义相等操作符==的行为。还有__ne__、__lt__、__gt__等比较相关的方法,详见 Emulating container types -
__hash__(self):定义对象的哈希值,用于提供一个对象的唯一标识,通常用于字典的键或集合的元素的去重。 -
__del__(self):对象销毁方法,或称析构函数,在对象被垃圾回收时调用。
其中重点说说上下文管理器要用的几个:
-
__enter__:进入上下文管理器时调用的函数,将它的返回值绑定到 target 上面,后续则可以在代码块中使用这个 target。 -
__exit__:退出上下文管理器时调用的函数。在上下文有异常的情况下,会传入exc_type,exc_value,traceback三个包含异常信息的参数
在异步调用的情况下,则是 __aenter__ 和 __aexit__,和同步的没什么区别,只是返回的是可等待对象(awaitable)。
在这里补充一下 with、上下文管理器的用法:
A context manager is an object that defines the runtime context to be established when executing a with statement. The context manager handles the entry into, and the exit from, the desired runtime context for the execution of the block of code. Context managers are normally invoked using the with statement (described in section The with statement), but can also be used by directly invoking their methods.
上下文管理器是一个定义在执行 with 语句时需要建立的运行时上下文的对象。上下文管理器处理代码块执行时进入和退出所需运行时上下文的过程。上下文管理器通常使用 with 语句(在 The with statement 部分中描述)来调用,但也可以通过直接调用其方法来使用。
1 | with EXPRESSION as TARGET: |
上下文管理器设计出来,是为了简化程序的。如果没有它,就必须显式的在执行要执行的语句前,手动调用 __enter__ 的语句,在调用完之后手动调用 __exit__ 里面的语句,这会很繁琐且容易遗漏。
1 | cm = ContextManager() |
很多情况下,构造上下文管理器是为了资源的获取和释放,比如文件操作、数据库连接等。这种情况下,__enter__ 方法通常用于获取资源,而 __exit__ 方法则用于释放资源。手动处理的话,很容易忘记释放资源,导致资源泄漏。
1 | with open('file.txt', 'r') as file: |
除此之外,还有一些魔法方法是和容器类型相关的,比如:
-
__getitem__(self, key):定义获取容器中元素的行为,比如obj[key]。 -
__setitem__(self, key, value):定义设置容器中元素的行为,比如obj[key] = value。 -
__delitem__(self, key):定义删除容器中元素的行为,比如del obj[key]。 -
__iter__(self):定义返回一个迭代器对象,用于迭代容器中的元素。 -
__contains__(self, item):定义检查容器中是否包含某个元素的行为,比如item in obj。
还有的是关于类的,比如:
-
__getattr__(self, name):定义当访问不存在的属性时的行为。首先会尝试__getattribute__正常获取属性,如果找不到才会调用__getattr__。 -
__setattr__(self, name, value):定义设置属性的行为。 -
__delattr__(self, name):定义删除属性的行为。 -
__call__(self, ...):定义对象被调用时的行为,使实例可以像函数一样被调用。
魔法方法还有很多,具体可以参考官方文档的 Special method names 一节。