别院牧志知识库 别院牧志知识库
首页
  • 基础

    • 全栈之路
    • 😎Awesome资源
  • 进阶

    • Python 工匠系列
    • 高阶知识点
  • 指南教程

    • Socket 编程
    • 异步编程
    • PEP 系列
  • 面试

    • Python 面试题
    • 2025 面试记录
    • 2022 面试记录
    • 2021 面试记录
    • 2020 面试记录
    • 2019 面试记录
    • 数据库索引原理
  • 基金

    • 基金知识
    • 基金经理
  • 细读经典

    • 德隆-三个知道
    • 孔曼子-摊大饼理论
    • 配置者说-躺赢之路
    • 资水-建立自己的投资体系
    • 反脆弱
  • Git 参考手册
  • 提问的智慧
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
首页
  • 基础

    • 全栈之路
    • 😎Awesome资源
  • 进阶

    • Python 工匠系列
    • 高阶知识点
  • 指南教程

    • Socket 编程
    • 异步编程
    • PEP 系列
  • 面试

    • Python 面试题
    • 2025 面试记录
    • 2022 面试记录
    • 2021 面试记录
    • 2020 面试记录
    • 2019 面试记录
    • 数据库索引原理
  • 基金

    • 基金知识
    • 基金经理
  • 细读经典

    • 德隆-三个知道
    • 孔曼子-摊大饼理论
    • 配置者说-躺赢之路
    • 资水-建立自己的投资体系
    • 反脆弱
  • Git 参考手册
  • 提问的智慧
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 辨析

  • Sockets编程

  • Django

  • stackoverflow

  • Flask

  • 全栈之路

    • 基础篇

    • 进阶篇

    • 面向对象

      • Python 全栈之路系列之面向对象类成员特性
      • Python 全栈之路系列之面向对象成员修饰符
      • Python 全栈之路系列之面向对象运算符重载
        • 常见的运算符重载方法
          • 构造函数和表达式:__init__和__sub__
          • 索引和分片: __getitem__和__setitem__
          • 索引迭代:__getitem__
          • 迭代器对象:__iter__和__next__
          • 成员关系:__contains__、__iter__和__getitem__
          • 属性引用:__getattr__和__setattr__
          • __repr__和__str__会返回字符串表达式
          • 右侧加法和原处加法: __radd__和__iadd__
          • Call 表达式:__call__
          • 比较:__lt__,__gt__和其他方法
          • 布尔值测试:_bool和len_
          • 对象解析函数:__del__
      • Python 全栈之路系列之面向对象进阶及类成员
      • Python 全栈之路系列之面向对象基础
      • Python 全栈之路系列之面向对象特殊成员
    • 网络编程

    • 操作系统

    • 标准库

    • 第三方库

    • Python 全栈之路
  • 面试

  • 代码片段

  • 异步编程

  • 😎Awesome资源

  • PEP

  • Python工匠系列

  • 高阶知识点

  • Python 学习资源待整理
  • 设计模式

  • 好“艹蛋”的 Python 呀!
  • FIFO | 待学清单📝
  • pip 安装及使用
  • 数据分析

  • 源码阅读计划

  • OOP

  • 关于 python 中的 setup.py
  • 并行分布式框架 Celery
  • 七种武器,让你的代码提高可维护性
  • 使用 pdb 调试 Python 代码
  • 每周一个 Python 标准库
  • 🐍Python
  • 全栈之路
  • 面向对象
佚名
2020-05-23
目录

Python 全栈之路系列之面向对象运算符重载

运算符重载的概念如下:

  1. 运算符重载让类拦截常规的 Python 运算;
  2. 类可重载所有 Python 表达式运算符;
  3. 类也可重载打印、函数调用、属性点号运算等内置运算;
  4. 重载是类实例的行为想内置类型;
  5. 重载是通过提供特殊名称的类方法来实现的;

# 常见的运算符重载方法

方法 重载 调用
__init__ 构造函数 对象建立:X = Class(args)
__del__ 解析函数 X 对象收回
__add__ 运算符+ 如果没有__iadd__,X+Y,X+=Y
__or__ 运算符或 如果没有__ior__
__repr__,__str__ 打印、转换 print(X)、repr(X)、str(X)
__call__ 函数调用 X(*args, **kwargs)
__getattr__ 点号运算 X.undefined
__setattr__ 属性赋值语句 X.any = value
__delattr__ 属性删除 del X.any
__getattribute__ 属性获取 X.any
__getitem__ 索引运算 X[key],X[i:j],没__iter__时的 for 循环和其他迭代器
__setitem__ 索引赋值语句 X[key]=value,X[i:k]=sequence
__delitem__ 索引和分片删除 del X[key], del X[i:j]
__len__ 长度 len(X),如果没有__bool__,真值测试
__bool__ 布尔测试 bool(X),真测试
__lt__,__gt__,__le__,__ge__,__eq__,__ne__ 特定的比较 X<Y,X>Y...
__radd__ 右侧加法 Other + X
__iadd__ 增强的加法 X += Y
__iter__,__next__ 迭代环境 I=iter(X),next(I)
__contains__ 成员关系测试 item in X(任何可迭代对象)
__index__ 整数值 hex(X),bin(X),oct(X),o[X],O[X:]
__enter__,__exit__ 环境管理器 with obj as var:
__get__,__set__,__delete__ 描述符属性 X.attr,X.attr=Value,del X.attr
__new__ 创建 在__init__之前创建对象

所有重载方法的名称前后都有两个下划线字符,以便把同类中定义的变量名区别开来。

# 构造函数和表达式:__init__和__sub__

>>> class Number:
...   def __init__(self, start):
...     self.data = start
...   def __sub__(self, other):
...     return Number(self.data - other)
...
>>> X = Number(5)
>>> Y = X - 2
>>> Y
<__main__.Number object at 0x10224d550>
>>> Y.data
3
1
2
3
4
5
6
7
8
9
10
11
12

# 索引和分片: __getitem__和__setitem__

基本索引

>>> class Index:
...     def __getitem__(self, item):
...         return item ** 2
...
>>>
>>> for i in range(5):
...     I = Index()
...     print(I[i], end=' ')
...
0 1 4 9 16
1
2
3
4
5
6
7
8
9
10

切片索引

>>> class Index:
...   data = [5, 6, 7, 8, 9]
...   def __getitem__(self, item):
...     print('getitem: ', item)
...     return self.data[item]
...   def __setitem__(self, key, value):
...     self.data[key] = value
...
>>> X = Index()
>>> print(X[1:4])
getitem:  slice(1, 4, None)
[6, 7, 8]
>>> X[1:4] = (1, 1, 1)
>>> print(X[1:4])
getitem:  slice(1, 4, None)
[1, 1, 1]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 索引迭代:__getitem__

如果重载了这个方法,for 循环每次循环时都会调用类的__getitem__方法;

>>> class stepper:
...     def __getitem__(self, item):
...         return self.data[item].upper()
...
>>>
>>> X = stepper()
>>> X.data = 'ansheng'
>>> for item in X:
...     print(item)
...
A
N
S
H
E
N
G
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 迭代器对象:__iter__和__next__

>>> class Squares:
...   def __init__(self, start, stop):
...         self.value = start - 1
...         self.stop = stop
...   def __iter__(self):
...         return self
...   def __next__(self):
...         if self.value == self.stop:
...             raise StopIteration
...         self.value += 1
...         return self.value ** 2
...
>>> for i in Squares(1, 5):
...   print(i)
...
1
4
9
16
25
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 成员关系:__contains__、__iter__和__getitem__

class Iters:
    def __init__(self, value):
        self.data = value

    def __getitem__(self, item):
        print('get[%s]' % item, end='')
        return self.data[item]

    def __iter__(self):
        print('iter>==', end='')
        self.ix = 0
        return self

    def __next__(self):
        print('next:', end='')
        if self.ix == len(self.data): raise StopIteration
        item = self.data[self.ix]
        self.ix += 1
        return item

    def __contains__(self, item):
        print('contains: ', end=' ')
        return item in self.data


X = Iters([1, 2, 3, 4, 5])
print(3 in X)
for i in X:
    print(i, end='|')

print([i ** 2 for i in X])
print(list(map(bin, X)))

I = iter(X)
while True:
    try:
        print(next(I), end=' @')
    except StopIteration as e:
        break
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

# 属性引用:__getattr__和__setattr__

当通过未定义的属性名称和实例通过点号进行访问时,就会用属性名称作为字符串调用这个方法,但如果类使用了继承,并且在超类中可以找到这个属性,那么就不会触发。

>>> class empty:
...     def __getattr__(self, item):
...         if item == 'age':
...             return 40
...         else:
...             raise AttributeError(item)
...
>>>
>>> x = empty()
>>> print(x.age)
40
>>> print(x.name)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in __getattr__
AttributeError: name
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> class accesscontrol:
...     def __setattr__(self, key, value):
...         if key == 'age':
...             self.__dict__[key] = value
...         else:
...             raise AttributeError(key + ' not allowed')
...
>>>
>>> x = accesscontrol()
>>> x.age = 40
>>> print(x.age)
40
>>> x.name = 'Hello'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in __setattr__
AttributeError: name not allowed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# __repr__和__str__会返回字符串表达式

__repr__和__str__都是为了更友好的显示,具体来说,如果在终端下 print(Class)则会调用__repr__,非终端下会调用__str__方法,且这两个方法只能返回字符串;

class adder:
    def __init__(self, value=0):
        self.data = value

    def __add__(self, other):
        self.data += other

    def __repr__(self):
        return 'addrepr(%s)' % self.data

    def __str__(self):
        return 'N: %s' % self.data


x = adder(2)
x + 1
print(x)
print((str(x), repr(x)))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 右侧加法和原处加法: __radd__和__iadd__

只有当+右侧的对象是类实例,而左边对象不是类实例的时候,Python 才会调用__radd__

class Commuter:
    def __init__(self, val):
        self.val = val

    def __add__(self, other):
        print('add', self.val, other)
        return self.val + other

    def __radd__(self, other):
        print('radd', self.val, other)
        return other + self.val


x = Commuter(88)
y = Commuter(99)
print(x + 1)
print('')
print(1 + y)
print('')
print(x + y)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

使用__iadd__进行原处加法

class Number:
    def __init__(self, val):
        self.val = val

    def __iadd__(self, other):
        self.val += other
        return self


x = Number(5)
x += 1
x += 1
print(x.val)


class Number:
    def __init__(self, val):
        self.val = val

    def __add__(self, other):
        return Number(self.val + other)


x = Number(5)
x += 1
x += 1
print(x.val)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# Call 表达式:__call__

当调用类实例时执行__call__方法

class Callee:
    def __call__(self, *args, **kwargs):
        print('Callee:', args, kwargs)


C = Callee()
C(1, 2, 3)
C(1, 2, 3, x=1, y=2, z=3)


class Prod:
    def __init__(self, value):
        self.value = value

    def __call__(self, other):
        return self.value * other


x = Prod(3)
print(x(3))
print(x(4))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 比较:__lt__,__gt__和其他方法

类可以定义方法来捕获所有的 6 种比较运算符:<、>、<=、>=、==和!=

class C:
    data = 'spam'

    def __gt__(self, other):
        return self.data > other

    def __lt__(self, other):
        return self.data < other

x = C()
print(x > 'han')
print(x < 'han')
1
2
3
4
5
6
7
8
9
10
11
12

# 布尔值测试:bool__和__len

class Truth:
    def __bool__(self):
        return True


X = Truth()
if X: print('yes')


class Truth:
    def __bool__(self):
        return False

X = Truth()
print(bool(X))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

如果没有这个方法,Python 退而求其次的求长度,因为一个非空对象看作是真:

>>> class Truth:
...   def __len__(self): return 0
...
>>> X = Truth()
>>> if not X: print('no')
...
no
1
2
3
4
5
6
7

如果两个方法都有,__bool__会胜过__len__:

>>> class Truth:
...   def __bool__(self): return True
...   def __len__(self): return 0
...
>>> X = Truth()
>>> bool(X)
True
1
2
3
4
5
6
7

如果两个方法都没有定义,对象毫无疑义的看作为真:

>>> class Truth: pass
...
>>> bool(Truth)
True
1
2
3
4

# 对象解析函数:__del__

每当实例产生时,就会调用__init__构造函数,每当实例空间被收回时,它的对立面__del__,也就是解析函数,就会自动执行;

class Life:
    def __init__(self, name='unknown'):
        print('Hello, ', name)
        self.name = name

    def __del__(self):
        print('Goodbye', self.name)


brian = Life('Brian')
brian = 'loretta'
1
2
3
4
5
6
7
8
9
10
11
编辑 (opens new window)
#编码#面向对象#魔法属性#dunder
上次更新: 2024-07-23, 01:00:43
Python 全栈之路系列之面向对象成员修饰符
Python 全栈之路系列之面向对象进阶及类成员

← Python 全栈之路系列之面向对象成员修饰符 Python 全栈之路系列之面向对象进阶及类成员→

最近更新
01
2025 面试记录
05-28
02
提升沟通亲和力的实用策略
03-26
03
工作
07-15
更多文章>
Theme by Vdoing | Copyright © 2019-2025 IMOYAO | 别院牧志
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式