Python中的特殊方法以及应用详解


Posted in Python onSeptember 20, 2020

前言

Python 中的特殊方法主要是为了被解释器调用的,因此应该尽量使用 len(my_object) 而不是 my_object.__len__() 这种写法。在执行 len(my_object) 时,Python 解释器会自行调用 my_object 中实现的 __len__ 方法。

除非有大量的元编程存在,直接调用特殊方法的频率应远小于实现它们的次数。

模拟数值类型

可以通过在自定义对象中实现 __add__ 和 __mul__ 等特殊方法 ,令其支持 +、* 等运算符。

如下面的模拟向量的 Vector 类:

# vector.py
from math import hypot

class Vector:
  def __init__(self, x=0, y=0):
    self.x = x
    self.y = y

  def __repr__(self):
    return f'Vector({self.x}, {self.y})'

  def __abs__(self):
    return hypot(self.x, self.y)

  def __bool__(self):
    return bool(self.x or self.y)

  def __add__(self, other):
    return Vector(self.x + other.x, self.y + other.y)

  def __mul__(self, scalar):
    return Vector(self.x * scalar, self.y * scalar)

运行效果如下:

>>> from vector import Vector
>>> v1 = Vector(2, 4)
>>> v2 = Vector(2, 1)
>>> v1 + v2
Vector(4, 5)
>>> v = Vector(3, 4)
>>> abs(v)
5.0
>>> v * 3
Vector(9, 12)

对象的字符串表示

Python 有一个 repr 内置函数,能把一个对象用字符串的形式表示出来。实际上这种字符串表达是通过对象内部的 __repr__ 特殊方法定义的。默认情况下,在控制台里查看某个对象时,输出的字符串一般是 <xxx object at 0x7fc99d6ab2e0> 这种形式。

__repr__ 返回的字符串应该准确、无歧义,并尽可能表示出该对象是如何创建的。比如前面的 Vector 对象,其 __repr__ 中定义的字符串形式类似于 Vector(3, 4),和对象初始化的语法非常近似。

__repr__ 和 __str__ 的区别在于,__str__ 是在向对象应用 str() 函数(或者用 print 函数打印某个对象)时被调用。其返回的字符串对终端用户更友好。

如果只想实现其中一个特殊方法,__repr__ 应该是更优的选择。在对象没有实现 __str__ 方法的情况下,Python 解释器会用 __repr__ 代替。

# myclass.py
class MyClass:
  def __repr__(self):
    return 'MyClass'

  def __str__(self):
    return 'This is an instance of MyClass'
>>> from myclass import MyClass
>>> my = MyClass()
>>> my
MyClass
>>> print(my)
This is an instance of MyClass

自定义布尔值

Python 里有 bool 类型,但实际上任何对象都可以用在需要 bool 类型的上下文(比如 if 或 while 语句)中。为了判断某个值 x 的真假,Python 会调用 bool(x) 返回 True 或 False。

默认情况下,自定义类的实例总是为真。除非这个类对于 __bool__ 或 __len__ 方法有自己的实现。
bool(x) 实际上调用了对象 x 中的 __bool__ 方法。如不存在 __bool__ 方法,则 bool(x) 会尝试调用 x.__len__(),返回 0 则为 False,否则为 True。

# boolclass.py
class BoolClass:
  def __init__(self):
    self.list = []

  def add(self, item):
    self.list.append(item)

  def __len__(self):
    return len(self.list)
>>> from boolclass import BoolClass
>>> b = BoolClass()
>>> len(b)
0
>>> bool(b)
False
>>> b.add(1)
>>> len(b)
1
>>> bool(b)
True
# boolclass.py
class BoolClass:
  def __init__(self):
    self.list = []

  def add(self, item):
    self.list.append(item)

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

  def __bool__(self):
    return bool(sum(self.list))
>>> from boolclass import BoolClass
>>> b = BoolClass()
>>> b.add(1)
>>> len(b)
1
>>> bool(b)
True
>>> b.add(-1)
>>> len(b)
2
>>> bool(b)
False

参考资料

Fluent Python

总结

到此这篇关于Python中特殊方法以及应用详解的文章就介绍到这了,更多相关Python特殊方法及应用内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python的Bottle框架中返回静态文件和JSON对象的方法
Apr 30 Python
Python中for循环控制语句用法实例
Jun 02 Python
Python中在for循环中嵌套使用if和else语句的技巧
Jun 20 Python
利用python解决mysql视图导入导出依赖的问题
Dec 17 Python
详解Python with/as使用说明
Dec 13 Python
Linux下Pycharm、Anaconda环境配置及使用踩坑
Dec 19 Python
Django框架ORM数据库操作实例详解
Nov 07 Python
Pytorch在dataloader类中设置shuffle的随机数种子方式
Jan 14 Python
Python chardet库识别编码原理解析
Feb 18 Python
2021年的Python 时间轴和即将推出的功能详解
Jul 27 Python
Python常用断言函数实例汇总
Nov 30 Python
PyQt5实现多张图片显示并滚动
Jun 11 Python
matplotlib 三维图表绘制方法简介
Sep 20 #Python
Python三维绘图之Matplotlib库的使用方法
Sep 20 #Python
scrapy利用selenium爬取豆瓣阅读的全步骤
Sep 20 #Python
Python操作dict时避免出现KeyError的几种解决方法
Sep 20 #Python
python中random.randint和random.randrange的区别详解
Sep 20 #Python
详解如何在pyqt中通过OpenCV实现对窗口的透视变换
Sep 20 #Python
Python Pillow(PIL)库的用法详解
Sep 19 #Python
You might like
php split汉字
2009/06/05 PHP
php array_pop 删除数组最后一个元素实例
2016/11/02 PHP
基于jquery的表格排序
2010/09/11 Javascript
精心挑选的15款优秀jQuery 本特效插件和教程
2012/08/06 Javascript
jquery 插件学习(二)
2012/08/06 Javascript
javascript 判断字符串是否包含某字符串及indexOf使用示例
2013/10/18 Javascript
简单介绍JavaScript数据类型之隐式类型转换
2015/12/28 Javascript
浅谈Cookie的生命周期问题
2016/08/02 Javascript
浅谈jquery的html方法里包含特殊字符的处理
2016/11/30 Javascript
js生成随机颜色方法代码分享(三种)
2016/12/29 Javascript
bootstrap table 数据表格行内修改的实现代码
2017/02/13 Javascript
Javascript防止图片拉伸的自适应处理方法
2017/12/26 Javascript
详谈js的变量提升以及使用方法
2018/10/06 Javascript
用js简单提供增删改查接口
2019/05/12 Javascript
解决在layer.open中使用时间控件laydate失败的问题
2019/09/11 Javascript
laravel实现中文和英语互相切换的例子
2019/09/30 Javascript
详解Vue的组件中data选项为什么必须是函数
2020/08/17 Javascript
[03:59]5分钟带你了解什么是DOTA2(第二期)
2017/02/07 DOTA
[04:05]TI9战队采访 - Natus Vincere
2019/08/22 DOTA
pymongo为mongodb数据库添加索引的方法
2015/05/11 Python
Python建立Map写Excel表实例解析
2018/01/17 Python
python重试装饰器的简单实现方法
2019/01/31 Python
Python3.7基于hashlib和Crypto实现加签验签功能(实例代码)
2019/12/04 Python
kmart凯马特官网:美国最大的打折零售商和全球最大的批发商之一
2016/11/17 全球购物
迪卡侬印度官网:购买所有体育用品
2017/06/24 全球购物
复古斯堪的纳维亚儿童服装:Baby go Retro
2017/09/09 全球购物
Windows和Linux动态库应用异同
2016/07/28 面试题
css animation配合SVG制作能量流动效果
2021/03/24 HTML / CSS
酒店开业策划方案
2014/06/02 职场文书
农业项目建议书
2014/08/25 职场文书
创先争优公开承诺书
2014/08/30 职场文书
2015年后备干部工作总结
2015/05/15 职场文书
雷锋观后感
2015/06/10 职场文书
go语言求任意类型切片的长度操作
2021/04/26 Golang
Window server 2012 R2 AD域的组策略相关设置
2022/04/28 Servers
Go gRPC进阶教程gRPC转换HTTP
2022/06/16 Golang