文章目录
Python魔法方法
一、 概述
1、 魔法方法
从入门到进阶,一个很重要的点就是Python中的魔法方法,魔法方法就是可以给你的类增加魔力的特殊方法,如果你的对象实现了这些方法中的某一个,那么这个方法就会在特殊的情况下被 Python 所调用,你可以定义自己想要的行为,而这一切都是自动发生的。它们经常是两个下划线包围来命名的(比如 __init__
/__new__
等等),Python的魔法方法是非常强大的。
如果你学习过Java,那你会发现Python中的魔法方法像是Java中的重载,Python中的魔法方法可以理解为:对类中的内置方法的重载,注意这里不是重写。
举个例子,Python中有个比较操作符==用来比较两个变量的大小,而这个操作符是通过内置函数__eq__来实现的,所以我们只需要通过改变这个内置函数代码,就可以改变重新定义这个操作符的行为。
如,我们需要比较一个字符串的长度是否相同,我们可以这么做:
class MyStr(str):
def __eq__(self, __x: object) -> bool:
return len(self) == len(__x)
a, b = MyStr("123"), MyStr("abc")
print(a == b) # 返回True
再举个例子,Python中的__new__
方法是对象实例化时调用的第一个方法,该方法仅读取一个cls参数后再把其他参数都传给用于指明对象初始化行为的__init__
方法,也就是说我们可以在一个对象初始化之前进行其他操作,比如检查是否合法等;而另一个方法__del__
可以用来销毁对象,定义了对象被垃圾回收的行为,我们可以利用该方法进行资源回收等操作。
我们可以通过重写__new__
方法实现一个单例模式,在每次实例化之前检查该对象是否有已有实例。
class Singleton:
def __new__(cls, *args, **kwargs):
if not hasattr(cls, "_instance"):
print("这个类没有创建")
cls._instance = super().__new__(cls, *args, **kwargs) # 使用父类的方法来创建类
print("这个类已经创建")
return cls._instance
s = Singleton()
s2 = Singleton() # s 和 s2 是同一个类,其共用一个内存地址
2、 常用的魔法方法
通过这两个例子相信你已经对Python的魔法方法比较理解了,但是Python中的魔法方法远不止两三个,这里有一些比较常用的魔法方法,供我们学习。
二、 构造方法
我们最为熟知的基本的魔法方法就是 __init__
,我们可以用它来指明一个对象初始化的行为。然而,当我们调用 x = SomeClass()
的时候, __init__
并不是第一个被调用的方法。事实上,第一个被调用的是__new__
,这个方法才真正地创建了实例。当这个对象的生命周期结束的时候,__del__
会被调用。让我们近一步理解这三个方法:
1、 __new__
__new__
是对象实例化时第一个调用的方法,它只取下 cls 参数,并把其他参数传给 __init__
。__new__
很少使用,但是也有它适合的场景,尤其是当类继承自一个像元组或者字符串这样不经常改变的类型的时候。 Python文档 中 有详细的说明。
比如,我们可以使用__new__
方法来实现单例模式,只创建一个类。
2、 __init__
类的初始化方法。它获取任何传给构造器的参数(比如我们调用 x = SomeClass(10, 'foo')
, __init__
就会接到参数 10 和 ‘foo’ 。 __init__
在Python的类定义中用的最多。
3、 __del__
__new__
和__init__
是对象的构造器, __del__
是对象的销毁器。它并非实现了语句 del x
(因此该语句不等同于 x.__del__()
)。而是定义了当对象被垃圾回收时的行为。 当对象需要在销毁时做一些处理的时候这个方法很有用,比如 socket 对象、文件对象。但是需要注意的是,当Python解释器退出但对象仍然存活的时候,__del__
并不会 执行。 所以养成一个手工清理的好习惯是很重要的,比如及时关闭连接。
使用案例:
from httpx import Client
class Crawl:
def __init__(self) -> None:
"""初始化类,有点像C++里面的构造函数"""
print("正在开启连接")
self.client = Client()
def use(self):
print("正在使用连接", self.client.is_closed)
def __del__(self) -> None:
"""在类关闭的时候,释放内存,有点像C++里面的析构函数"""
print("正在关闭连接")
if self.client.is_closed:
self.client.close()
del self.client
c = Crawl()
c.use()
三、 操作符
1、 简介
使用Python魔法方法的一个巨大优势就是可以构建一个拥有Python内置类型行为的对象。这意味着你可以避免使用非标准的、丑陋的方式来表达简单的操作。 在一些语言中,这样做很常见:
if instance.equals(other_instance):
# do something
你当然可以在Python也这么做,但是这样做让代码变得冗长而混乱。不同的类库可能对同一种比较操作采用不同的方法名称,这让使用者需要做很多没有必要的工作。运用魔法方法的魔力,我们可以定义方法 __eq__
if instance == other_instance:
# do something
这是魔法力