Python双下方法全解析:从运算符重载到对象生命周期

程一诺
程一诺
发布时间:2026-10-12| 3人浏览过
原创

本文深入解析Python中的双下方法(Dunder Methods),涵盖__init__初始化、各类运算符重载(比较、算术、位运算)、字符串与数值转换、集合与迭代协议,以及对象创建销毁和属性管理。通过尺子与二进制字符串等实例,展示如何自定义类行为,提升代码灵活性与可维护性。

前言

在编写Python代码时,你是否曾对以下现象感到困惑?

为什么数学中的+号在字符串运算中变成了拼接功能,例如'ab' + 'cd'的结果是abcd;而*号却变成了重复功能,例如'ab' * 2的结果是abab?

为什么某些对象print能直接输出数据,而print自定义的类对象却输出一堆难以理解的代码<__main__.MyCls object at 0x105732250>?

这并非系统进行了特殊定制,而是因为Python中存在一类特殊的方法,它们在特定场景下会被自动调用。例如,在字符串类str中定义了__add__方法后,当代码执行字符串相加'ab' + 'cd'时,就会自动调用__add__方法来完成字符串拼接。

由于这类特殊方法的方法名均以双下划线开始和结束,因此它们被称为双下方法(Dunder Methods)。

Python中的双下方法种类繁多,今天我们将对其进行详细解析。

Python中的双下方法

1. __init__方法

__init__是许多人接触的第一个双下方法。

class A:
    def __init__(self, a):
        self.a = a

当调用A()实例化对象时,__init__方法会被自动调用,从而完成对象的初始化。

2. 运算符的双下方法

在类中定义与运算符相关的双下方法,可以直接对类对象执行加减乘除、比较等操作。

这里,我们定义一个尺子类Rule,它包含一个属性r_len,用于代表尺子的长度。

class Rule:
    def __init__(self, r_len):
        self.r_len = r_len

2.1 比较运算符

如果希望按照尺子的长度对不同尺子进行比较,需要在Rule类中定义比较运算符。

class Rule:
    def __init__(self, r_len):
        self.r_len = r_len

    # < 运算符
    def __lt__(self, other):
        return self.r_len < other.r_len

    # <= 运算符
    def __le__(self, other):
        return self.r_len <= other.r_len

    # > 运算符
    def __gt__(self, other):
        return self.r_len > other.r_len

    # >= 运算符
    def __ge__(self, other):
        return self.r_len >= other.r_len

这里定义了<、<=、>和>=四个比较运算符,这样就可以使用下面的代码来比较Rule对象了。

rule1 = Rule(10)
rule2 = Rule(5)
print(rule1 > rule2)  # True
print(rule1 >= rule2)  # True
print(rule1 < rule2)  # False
print(rule1 <= rule2)  # False

当使用>比较rule1和rule2时,rule1对象会自动调用__gt__方法,并将rule2对象传给other参数,从而完成比较。

下面是比较运算符的双下方法

比较运算符双下方法

2.2 算术运算符

可以支持类对象的加减乘除运算。

def __add__(self, other):
    return Rule(self.r_len + other.r_len)

这里定义了__add__方法,对应的是+运算符,它会将两个尺子的长度相加,并生成一个新的尺子。

rule1 = Rule(10)
rule2 = Rule(5)
rule3 = rule1 + rule2

下面是算术运算符的双下方法

2.3 反向算术运算符

它支持其他类型的变量与Rule类相加。以__radd__方法为例

def __radd__(self, other):
    return self.r_len + other
rule1 = Rule(10)
rule2 = 10 + rule1

程序执行10 + rule1时,会尝试调用int类的__add__,但int类没有定义与Rule类对象相加的方法,所以程序会调用+号右边对象rule1的__radd__方法,并把10传给other参数。

因此这种运算符又称为右加运算符。它所支持的运算符与上面的算术运算符相同,方法名前加r即可。

2.4 增量赋值运算符

增量赋值运算符包括+=、-=、*=、/=等。

def __iadd__(self, other):
    self.r_len += other
    return self
rule1 = Rule(10)
rule1 += 5

除了__divmod__方法外,其他的跟算术运算符一样,方法名前都加i。

2.4 位运算符

这部分支持按二进制进行取反、移位和与或非等运算。由于Rule类不涉及位运算,所以我们换一个例子。

定义二进制字符串的类BinStr,包含bin_str属性,表示二进制字符串。

class BinStr:
    def __init__(self, bin_str):
        self.bin_str = bin_str
x = BinStr('1010')  #创建二进制字符串对象
print(x.bin_str) # 1010

给BinStr定义一个取反运算符~

# ~ 运算符
def __invert__(self):
    inverted_bin_str = ''.join(['1' if i == '0' else '0' for i in self.bin_str])
    return BinStr(inverted_bin_str)

__invert__方法中,遍历bin_str字符串,将每位取反,并返回一个新的BinStr类对象。

x = BinStr('1011')

invert_x = ~x
print(invert_x.bin_str) # 0100

下面是位运算符的双下方法

这部分也支持反向位运算符和增量赋值位运算符,规则跟算术运算符一样,这里就不再赘述。

3.字符串表示

这部分涉及两个双下方法__repr__和__format__,在某些特殊场景,如print,会自动调用,将对象转成字符串。

还是以BinStr为例,先写__repr__方法。

def __repr__(self):
    decimal = int('0b'+self.bin_str, 2)
    return f'二进制字符串:{self.bin_str},对应的十进制数字:{decimal}'
x = BinStr('1011')
print(x)
# 输出:二进制字符串:1011,对应的十进制数字:11

当程序执行print(x)时,会自动调用__repr__方法,获取对象x对应的字符串。

再写__format__方法,它也是将对象格式化为字符串。

def __format__(self, format_spec):
    return format_spec % self.bin_str
print('{0:二进制字符串:%s}'.format(x))
# 输出:二进制字符串:1011

当.format方法的前面字符串里包含0:时,就会自动调用__format__方法,并将字符串传给format_spec参数。

4.数值转换

调用int(obj)、float(obj)等方法,可以将对象转成相对应数据类型的数据。

def __int__(self):
    return int('0b'+self.bin_str, 2)
x = BinStr('1011')
print(int(x))

当调用int(x)时,会自动调用__int__方法,将二进制字符串转成十进制数字。

数值转换除了上面的两个外,还有__abs__、__bool__、__complex__、__hash__、__index__和__str__。

__str__和__repr__一样,在print时都会被自动调用,但__str__优先级更高。

5.集合相关的双下方法

这部分可以像集合那样,定义对象长度、获取某个位置元素、切片等方法。

以__len__和__getitem__为例

def __len__(self):
    return len(self.bin_str)

def __getitem__(self, item):
    return self.bin_str[item]
x = BinStr('1011')

print(len(x))  # 4
print(x[0])  # 1
print(x[0:3])  # 101

len(x)会自动调用__len__返回对象的长度。

通过[]方式获取对象的元素时,会自动调用__getitem__方法,并将切片对象传给item参数,即可以获取单个元素,还可以获取切片。

集合相关的双下方法还包括__setitem__、__delitem__和__contains__。

6.迭代相关的双下方法

可以在对象上使用for-in遍历。

def __iter__(self):
    self.cur_i = -1
    return self

def __next__(self):
    self.cur_i += 1
    if self.cur_i >= len(self.bin_str):
        raise StopIteration()  # 退出迭代
    return self.bin_str[self.cur_i]
x = BinStr('1011')
for i in x:
    print(i)

当在x上使用for-in循环时,会先调用__iter__方法将游标cur_i置为初始值-1,然后不断调用__next__方法遍历self.bin_str中的每一位。

这部分还有一个__reversed__方法用来反转对象。

def __reversed__(self):
    return BinStr(''.join(list(reversed(self.bin_str))))
x = BinStr('1011')
reversed_x = reversed(x)
print(reversed_x)
# 输出:二进制字符串:1101,对应的十进制数字:13

7.类相关的双下方法

做web开发的朋友,用类相关的双下方法会更多一些。

7.1 实例的创建和销毁

实例的创建是__new__和__init__方法,实例的销毁是__del__方法。

__new__的调用早于__init__,它的作用是创建对象的实例(内存开辟一段空间),而后才将该实例传给__init__方法,完成实例的初始化。

由于__new__是类静态方法,因此它可以控制对象的创建,从而实现单例模式。

__del__方法在实例销毁时,被自动调用,可以用来做一些清理工作和资源释放的工作。

7.2 属性管理

类属性的访问和设置。包括__getattr__、__getattribute__、__setattr__和__delattr__方法。

__getattr__和__getattribute__的区别是,当访问类属性时,无论属性存不存在都会调用__getattribute__方法,只有当属性不存在时才会调用__getattr__方法。

7.3 属性描述符

控制属性的访问,一般用于把属性的取值控制在合理范围内。包括__get__、__set__和__delete__方法。

class XValidation:
    def __get__(self, instance, owner):
        return self.x

    def __set__(self, instance, value):
        if 0 <= value <= 100:
            self.x = value
        else:
            raise Exception('x不能小于0,不能大于100')

    def __delete__(self, instance):
        print('删除属性')


class MyCls:
    x = XValidation()

    def __init__(self, n):
        self.x = n

obj = MyCls(10)
obj.x = 101
print(obj.x) # 抛异常:Exception: x不能小于0,不能大于100

上述例子,通过类属性描述符,可以将属性x的取值控制在[0, 100]之前,防止不合法的取值。

8.总结

虽然上面介绍的不是所有的双下方法,但也算是绝大多数了。

虽然双下方法里可以编写任意代码,但大家尽量编写与方法要求一样的代码。例如,在__add__方法实现的不是对象相加而是相减,虽然也能运行,但这样会造成很大困惑,不利于代码维护。

到此这篇关于一文带你了解Python中的双下方法的文章就介绍到这了,更多相关Python双下方法内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。