本文讲述Python面向对象的高级知识------类的魔法方法。阅读本文有助于理解源码!
一、什么是魔法方法
魔法方法(Magic Methods)是 Python 类中以双下划线开头和结尾(如
__init__)的特殊方法,由 Python 解释器在特定语法或操作触发时自动调用。它们定义了对象在语言层面的行为协议(Protocol),使得自定义类能够模拟内置类型(如int、list、dict)的语义,从而支持运算符重载、容器行为、上下文管理、字符串表示等核心功能。
看完这个定义,你肯定可以想到 __init__方法 没错这就是最常见的一个魔法方法,在类实例化时才会执行。
所以只要是以 __func__这样格式的就是魔法方法。
由于魔法方法太多,本文只挑选了六个常用的进行讲解。
python
class Student:
def __init__(self):
self.name = '小白'
self.gender = '男'
self.age = 18
stu = Student()
二、四个魔法方法
【1】new()方法
new()方法是在 Python 中定义一个类的时候可以定义的一个特殊方法。
它被用来创建一个类的新实例(对象)。
你可能认为创建一个新的实例 一般是通过调用类的构造函数 init() 来完成的。
然而,通过类名()创建对象时,在自动执行 init() 方法前,会先执行 object.new 方法, 在内存中开辟对象空间并返回该对象 。然后,Python 才会调用 init() 方法来对这个新实例进行初始化。
小例子
运行这段代码,你会发现先打印__new__里面的语句,再打印__init__的语句。
**注意:**一定要返回 object.new(cls) 这一句。为什么呢? 因为上面提到过 new 要在内存开辟对象空间并返回该对象。如果不返回,那么init方法中拿不到这个对象就无法进行赋值,就不会执行该方法,读者可以将这句注释 再运行看看
python
class Student(object):
def __new__(cls, *args, **kwargs):
print("执行__new__方法")
return object.__new__(cls) # 如果没有这行回怎么样
def __init__(self):
print("执行__init__方法")
self.name = '小白'
self.gender = '男'
self.age = 18
stu = Student()
new_()方法的主要作用是创建实例对象,它可以被用来控制实例的创建过程。相比之下,init() 方法主要用于初始化实例对象。
new() 方法在设计模式中常常与单例模式结合使用,用于创建一个类的唯一实例。单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取该实例。
例子:
python
class Singleton:
_instance = None
# 通过注释这段函数 运行两次
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super().__new__(cls)
return cls._instance
# 创建实例
obj1 = Singleton()
obj2 = Singleton()
# 检查是否为同一个实例
print(obj1 is obj2) # 输出: True
【2】__str__方法
改变对象的字符串显示。默认打印一个对象是返回其内存地址
如果我们使用 __str__方法 可以自定义我们想返回的内容
触发时机 : str(对象 ) print(对象)
例子:
注:这个str方法经常使用!!!
python
class Student(object):
def __init__(self):
self.name = '小白'
self.gender = '男'
self.age = 18
def __str__(self):
return f"学生信息:姓名:{self.name},性别:{self.gender} 年龄:{self.age}"
stu = Student()
print(stu)
print(str(stu))
【3】eq 方法
用于比较两个类是否相等
触发时机 当对两个对象进行 == 运算时
重点理解:走谁的eq方法
python
class Student(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
self.age = 18
def __eq__(self, other):
print(f"走{self.name}的eq方法")
return self.name == other.name
stu1 = Student('小白', '男')
stu2 = Student('小灰','女')
stu3 = Student('小黑','女')
print(stu1 == stu2)
【4】__item__系列 (重点)
在没有item系列魔法方法前,我们操作对象只能通过 对象实例.xxx
那有没有一种办法可以让我们像操作字典一样操作对象呢
在__item__系列中一共有3个方法需要我们掌握
getitem、setitem、delitem 对应三种操作 取值 赋值 删除值
例子:
python
class Cache:
def __init__(self):
self.data = {}
def __getitem__(self, key):
return self.data[key]
def __setitem__(self, key, value):
self.data[key] = value
def __delitem__(self, key):
del self.data[key]
def __contains__(self, key):
return key in self.data
在上述例子中,我们创建了一个名为 Cache 的自定义类,并实现了 getitem、setitem、delitem 和 contains 这些特殊方法。
使用这个自定义的缓存类,我们可以像操作字典一样操作缓存数据,例如:
python
cache = Cache()
#存储数据
cache['key1'] = 'value1'
cache['key2'] = 'value2'
#获取数据
print(cache['key1'])
print(cache['key2'])
print("key1" in cache)
del cache['key1']
print("key1" in cache)
通过实现这一系列特殊方法,我们可以使用类似于字典的语法来访问和操作缓存对象。这样,我们可以更方便地存储、获取和删除缓存数据,同时也可以使用其他字典操作,如检查键是否存在。
三、总结
目前遇见最多的是str喝item系列魔法方法,后续这个文章还会继续更新我遇到的且有用的魔法方法。举个例子,我在研究simplejwt的源码发现底层就是使用了 str和item系列方法