Python部落(python.freelycode.com)组织翻译,禁止转载,欢迎转发。

如果你对 Python 中的str对象使用过 + 或 * 运算符,你一定注意到了它的操作与 int 或 float 类型的区别:

你可能想知道同一内置运算符或函数如何对不同类对象进行不同操作的。这分别称为运算符重载和函数重载。本文将帮助你了解此机制,以便你可以在自己的 Python 类中执行相同的过程,使对象更 Pythonic。

你将了解以下内容:处理 Python 中的运算符和内置函数的 API

len() 和其他内置函数背后的 "秘密"

如何使你的类能够使用运算符

如何使你的类与 Python 的内置函数兼容

除此之外你还能看到一个示例类,其中的对象与许多运算符和函数兼容。我们开始吧!

Python 数据模型

假设有一个表示在线订单的类,具有购物车 (列表) 和顾客 (代表顾客的str或其他类的实例)两种数据。

在这种情况下,要获得购物车列表的长度是很自然的。新接触 Python 的人可能会选择在他们的类中实现一个叫get_cart_len()的方法来执行此项。但是,你也可以配置内置函数 len(),以便在给定对象时返回购物车列表的长度。

在另一种情况下, 我们可能需要添加一些东西到购物车。再次,新接触 Python 的人会想到实现一个 append_to_cart() 方法,以添加东西到购物车列表。但是你也可以配置运算符 + ,用它来将新内容添加到购物车中。

Python 使用特殊的方法来做这些。这些特殊方法具有命名约定,其中名称以两个下划线开头, 后跟一个标识符, 并以另一对下划线结尾。

本质上, 每个内置函数或运算符都有一个与之对应的特殊方法。例如,对应于 len() 有 __len__() ,对应于运算符 + 有__add__()。

默认情况下, 大多数内置函数和运算符都不能与自定义类的对象一起使用。必须在类定义中添加相应的特殊方法,才能使对象与内置和运算符兼容。

执行此操作时,与其关联的函数或运算符的行为将根据方法中定义的方式进行更改。

这正是数据模型(Python 文档的3节) 帮助你完成的内容。它列出了所有可用的特殊方法,并为你提供了重载内置函数和运算符的方法, 以便你可以在自己的对象上使用它们。

让我们看看这意味着什么。

有趣的事实:由于这些方法使用的命名约定, 它们也被称为dunder 方法,这是对double underscore的缩写。有时它们也被称为特殊方法或魔术方法。不过,我们更喜欢叫它dunder 方法!

像 len () 和 [] 这样的内部操作

Python 中的每个类对内置函数和方法都进行了重新定义。将某个类的实例传递给内置函数或在实例上使用运算符时,实际上等效于调用具有相关参数的特殊方法。

如果有内置函数func(),且这个函数的相应特殊方法是__func__(),Python 对函数的调用是obj.__func__(),其中obj即对象。在运算符的情况下, 如果有一个运算符 opr 和相应的特殊方法__opr__(), Python 会将类似于obj1 obj2的解释为obj1.__opr__(obj2)。

因此,当你对对象调用 len() 时,Python 会将调用以 obj.__len__() 处理。当你对可迭代对象使用 [] 操作符获取索引上的值时,Python 以 itr.__getitem__(index) 处理它,其中itr是可迭代对象,index是你想获取的索引。

因此,当你在自己的类中定义这些特殊方法时会重写与它们关联的函数或运算符的行为,因为实际 Python 是执行调用你的方法。让我们深入了解一下:

正如你所看到的,当你使用该函数或其相应的特殊方法时, 将得到相同的结果。事实上,当你使用 dir() 获取 str 对象的属性和方法列表时,除了str对象上可用的常用方法外,还将在列表中看到这些特殊方法:

如果在类中未通过特殊方法重新定义内置函数或运算符,则会返回TypeError。

那么,如何在你的类中使用特殊的方法?

重载内置函数

数据模型中定义的许多特殊方法如 len, abs, hash, divmod等等可用于更改函数的行为。为此,你只需在类中定义相应的特殊方法。让我们看几个例子:

使用 len() 获取你对象的长度

若要更改 len() 的操作,需要在类中定义特殊方法 __len__() 。当你将自定义类的对象传递给 len() 时,自定义定义将用于获取结果。让我们来实现我们一开始讨论的类 len():

正如你所看到的,现在可以使用 len() 来直接获取购物车的长度。此外,说 "订单的长度"比调用类似order.get_cart_len()的方法更直观。你的调用既 Pythonic 又直观。如果没有定义__len__()方法但仍对你的对象调用len(),则会遇到TypeError:

但是,当重载len()时,你应该记住 Python 需要函数返回一个整数。如果你的方法是返回一个整数以外的任何东西,你会得到TypeError。这很可能是为了使它与 len() 通常用于获取序列长度这一事实保持一致,而这只能是一个整数:

使用 abs()

通过定义类中的特殊方法 __abs__() 可以为类的实例重写内置abs()的操作。abs() 的返回值没有限制,而当你的类定义中缺少特殊方法时, 就会返回TypeError。

在表示二维空间中向量的类中,可用 abs() 获取向量的长度。让我们来看看它的实际过程:

说 "向量绝对值"比调用类似vector.get_mag()的方法更直观。

使用 str () 打印对象

内置的str()用于将类的实例强制转换为str对象,或者更准确地说是获取对象的用户友好型的字符串表示形式,而这可以被普通用户而不是程序员接受。通过在类中定义__str__()方法,在传递str()时可以定义对象应显示的字符串格式。此外,__str__()是 Python 在你对对象调用print()时使用的方法。

让我们在Vector类中实现此目的,使Vector对象的格式化为xi+yj。对y为负值的部分将使用 "迷你语言" 格式处理:

__str__()返回一个str对象是必要的,如果返回类型是非字符串, 则得到TypeError。

使用 repr() 表示对象

内置的repr()用于获取对象的解析字符串表示形式。如果一个对象是解析的,这意味着当repr与函数eval()一起使用时 Python 能够从表示形式中重新创建对象。若要定义repr()的行为,可以使用特殊方法__repr__()。

这也是 Python 用于在 REPL 会话中显示对象的方法。如果未定义__repr__()方法,你将得到类似于<__main__.Vector object at 0x...>一样尝试查看 REPL 会话中的对象内容。让我们在Vector类里查看它的作用:

注:在未定义__str__()方法的情况下,Python 使用__repr__()方法来打印对象,并在调用str()时表示该对象。如果两种方法都缺失, 则默认为<__main__.Vector ...>。而__repr__()是用于在交互式会话中显示对象的唯一方法。类中缺失它则会默认为<__main__.Vector ...>。

此外,虽然__str__()和__repr__()有这种区分,许多流行的库是忽略这种区别的,并混杂使用这两种方法。

下面推荐我们自己的一篇介绍__repr__()和__str__()的文章:https://dbader.org/blog/python-repr-vs-str。

使用 bool() 获得对象的布尔值

内置的bool()可用于获取对象的布尔值。若要重新定义其行为,可以使用特殊方法__bool__() (在 Python 2.x 中是__nonzero__()) 。

此处定义的行为将在所有需要获取布尔值的情境 (如if语句) 中确定实例是否为真。

例如,对于上面定义的Order类,如果购物车列表的长度是非零,则可以认为实例是真。这可用于检查是否应处理订单:

注:当在类中未实现特殊方法__bool__()时,__len__()所返回的值将用作布尔值,其中非零值为真,零值为假。如果两种方法都未实现,则将该类的所有实例视为真。

有许多更特殊的方法重载内置函数。你可以在文档中找到它们。讨论了其中的一些,接下来让我们看看运算符。

英文原文:https://realpython.com/operator-function-overloading/

译者:β

python中mod运算符_自定义 Python 类中的运算符和函数重载(上)相关推荐

  1. python下拉菜单_自定义Django Form中choicefield下拉菜单选取数据库内容实例

    工作中遇到的问题,自定义了一个forms.form表单,某项需要作出下拉菜单,下拉菜单中的选项需要从数据库(objectForm models)中提取. form.py为: class objectF ...

  2. python类装饰器详解-Python类中的装饰器在当前类中的声明与调用详解

    我的Python环境:3.7 在Python类里声明一个装饰器,并在这个类里调用这个装饰器. 代码如下: class Test(): xx = False def __init__(self): pa ...

  3. python中__init__方法_关于python中__init__方法理解

    在理解__init__方法之前,我们需要搞明白,什么时候才需要用到的这个方法 什么是__init__? __init__方法在python中是类的初始化,通俗来讲,就是每次只要你去创建一个类的实例对象 ...

  4. python编写测试系统_纯 python 编写的一套 dubbo 测试平台

    因组织要求,需要一个Dubbo接口的测试工具,经多方研究,遂决定要写一个不需要编写任何代码,直接在页面上填写数据就能直接运行Dubbo接口的测试工具,类似于Postman编写http接口一样简单. 整 ...

  5. MFC开发过程中,自定义的类中做分割窗口的图像显示,GetDC出现问题:function does not take 0 parameters?

    做MFC分割窗口时,其中含有视类CxxVew窗口,含有General Class (自定义的类CMyXX),在CMyXX中使用GetDC时: CDC* pDC = GetDC(); 出现标题中的问题, ...

  6. 在python中定义类时、运算符重载_自定义 Python 类中的运算符和函数重载(上)...

    如果你对 Python 中的str对象使用过 + 或 * 运算符,你一定注意到了它的操作与 int 或 float 类型的区别: 你可能想知道同一内置运算符或函数如何对不同类对象进行不同操作的.这分别 ...

  7. python choice添加下拉框_自定义Django Form中choicefield下拉菜单选取数据库内容实例...

    工作中遇到的问题,自定义了一个forms.form表单,某项需要作出下拉菜单,下拉菜单中的选项需要从数据库(objectForm models)中提取. form.py为: class objectF ...

  8. python如何使用多态_在python 3中,如何将多态应用于类

    介绍 多态性是为不同的基础形式(例如,数据类型或类)利用同一接口的能力.这允许函数在不同时间使用不同类型的实体. 对于Python中的面向对象编程,这意味着可以用与属于特定类的特定对象相同的方式来使用 ...

  9. python中rgb颜色_自定义RGB颜色与Python诅咒

    我正在用Python编写一个程序,使用标准库中的curses模块.在 我希望我的程序只是退出,如果它不能使用自定义颜色我指定的RGB三元组.在 我有一些入门代码,看起来像:import curses ...

最新文章

  1. SharePoint 2007 Web Content Management 性能优化系列 3 - IIS压缩
  2. 10 i lt shell的if_shell脚本编程之if、case条件语句
  3. Spring Cloud Stream 使用延迟消息实现定时任务(RabbitMQ)
  4. 微型计算机储存信息的基本单位是什么,16.磁盘存储器存、取信息的最基本单位是...
  5. 洛谷P1434-滑雪【线性化Dp】
  6. elasticsearch工作笔记002---Centos7.3安装最新版elasticsearch-7.0.0-beta1-x86_64.rpm单机版安装
  7. 测试与开发的冲突举例
  8. AI嘻哈写歌词软件总结
  9. Spring:Spring支持的bean作用域有哪些
  10. C++_华氏度转换摄氏度
  11. 小学计算机课题研究报告,小学信息技术自主学习方法探究研究课题研究报告
  12. 如果自己配电脑电源额定瓦数过高会有什么坏处吗?
  13. 《Effective C++》第三版 第六章 继承与面向对象设计 32~35条例
  14. 攻防世界——杂项(1-5)
  15. 程序员技术面常用知识点
  16. 读书寄语:感谢揭露你过失的人
  17. 从十亿个数中找出前1000个最大的数的算法
  18. MT6735 8.1 Secure Boot 签名
  19. 《货币未来:从金本位到区块链》读书笔记
  20. 你应该知道的前端安全性

热门文章

  1. hdu 1503 Advanced Fruits(DP)
  2. C#的变迁史 - C# 4.0 之线程安全集合篇
  3. 后序非递归遍历二叉树的应用
  4. 获取SD卡上 未安装 APK文件信息
  5. python tkinter计算器实例_python库的tkinter带你进入GUI世界(计算器简单功能)
  6. LeetCode从读题到自闭:1. 两数之和
  7. opencv +opencv_contrib+CMake+VS2015
  8. Android使adb作为host运行在arm64平台
  9. Android Studio第一个NDK程序
  10. dumpsys使用方法