有些事情让我不安,比如运算符重载。我决定不支持运算符重载,这完全是个人选择,因为我见过太多 C++ 程序员滥用它。

                                                ——James Gosling

                                                    Java 之父

  运算符重载的作用是让用户定义的对象使用中缀运算符(如 + 和 |)或一元运算符(如 - 和 ~)。说得宽泛一些,在 Python 中,函数调用(())、属性访问(.)和元素访问 / 切片([])也是运算符。

  我们为 Vector 类简略实现了几个运算符。__add__ 和 __mul__ 方法是为了展示如何使用特殊方法重载运算符,不过有些小问题被我们忽视了。此外,我们定义的Vector2d.__eq__ 方法认为 Vector(3, 4) == [3, 4] 是真的(True),这可能并不合理。

运算符重载基础

  在某些圈子中,运算符重载的名声并不好。这个语言特性可能(已经)被滥用,让程序员困惑,导致缺陷和意料之外的性能瓶颈。但是,如果使用得当,API 会变得好用,代码会变得易于阅读。Python 施加了一些限制,做好了灵活性、可用性和安全性方面的平衡:

  • 不能重载内置类型的运算符
  • 不能新建运算符,只能重载现有的
  • 某些运算符不能重载——is、and、or 和 not(不过位运算符
  • &、| 和 ~ 可以)

  前面的博文已经为 Vector 定义了一个中缀运算符,即 ==,这个运算符由__eq__ 方法支持。我们将改进 __eq__ 方法的实现,更好地处理不是Vector 实例的操作数。然而,在运算符重载方面,众多比较运算符(==、!=、>、<、>=、<=)是特例,因此我们首先将在 Vector 中重载四个算术运算符:一元运算符 - 和 +,以及中缀运算符 + 和 *。

一元运算符 

  -(__neg__)

    一元取负算术运算符。如果 x 是 -2,那么 -x == 2。

  +(__pos__)

    一元取正算术运算符。通常,x == +x,但也有一些例外。如果好奇,请阅读“x 和 +x 何时不相等”附注栏。

  ~(__invert__)

    对整数按位取反,定义为 ~x == -(x+1)。如果 x 是 2,那么 ~x== -3。

  支持一元运算符很简单,只需实现相应的特殊方法。这些特殊方法只有一个参数,self。然后,使用符合所在类的逻辑实现。不过,要遵守运算符的一个基本规则:始终返回一个新对象。也就是说,不能修改self,要创建并返回合适类型的新实例。

  对 - 和 + 来说,结果可能是与 self 同属一类的实例。多数时候,+ 最好返回 self 的副本。abs(...) 的结果应该是一个标量。但是对 ~ 来说,很难说什么结果是合理的,因为可能不是处理整数的位,例如在ORM 中,SQL WHERE 子句应该返回反集。

  def __abs__(self):
return math.sqrt(sum(x * x for x in self)) def __neg__(self):
return Vector(-x for x in self) #为了计算 -v,构建一个新 Vector 实例,把 self 的每个分量都取反 def __pos__(self):
return Vector(self) #为了计算 +v,构建一个新 Vector 实例,传入 self 的各个分量 

x 和 +x 何时不相等

  每个人都觉得 x == +x,而且在 Python 中,几乎所有情况下都是这样。但是,我在标准库中找到两例 x != +x 的情况。

  第一例与 decimal.Decimal 类有关。如果 x 是 Decimal 实例,在算术运算的上下文中创建,然后在不同的上下文中计算 +x,那么 x!= +x。例如,x 所在的上下文使用某个精度,而计算 +x 时,精度变了,例如下面的

Python 正确重载运算符的更多相关文章

  1. 流畅的python第十三章正确重载运算符

    运算符重载基础 不能重载内置类型的运算符 不能新建运算符,只能重载现有的 某些运算符不能重载-------is,and,or和not(不过位运算符&,|和~可以) 一元运算符

  2. 『流畅的Python』第13章:正确重载运算符

  3. Python 中的运算符重载

    本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理 一种运算符对于不同类型的对象,有不同的使用方式.例如, + 用于整型对象,表示两个数相加:用于字符串 ...

  4. c++中有些重载运算符为什么要返回引用

    事实上,我们的重载运算符返回void.返回对象本身.返回对象引用都是可以的,并不是说一定要返回一个引用,只不过在不同的情况下需要不同的返回值. 那么什么情况下要返回对象的引用呢? 原因有两个: 允许进 ...

  5. python 的重载

    python 的重载主要包括方法重载和运算符重载.1.python 方法重载: 其他的语言一般对于方法重载的话,主要是根据参数的类型不同或者是数量不同来区分同名的方法.而python则比较特殊,它本身 ...

  6. C++ Primer : : 第十四章 : 重载运算符与类型转换之类型转换运算符和重载匹配

    类型转换运算符 class SmallInt { public: SmallInt(int i = 0) : val(i) { if (i < 0 || i > 255) throw st ...

  7. Chapter14:重载运算符

    对于一个运算符函数来说,它或者是类的成员,或者至少含有一个类类型的参数. int operator+(int, int);//错误,不能为int重定义内置运算符 对于一个重载的运算符来说,其优先级和结 ...

  8. operator重载运算符

    1.重载运算符的函数一般格式如下 函数类型    operator  运算符名称    (形参表列) {对运算符的重载处理} 例如,想将"+"用于Complex(复数)的加法运算, ...

  9. JAVA 没有重载运算符,那么 String 类型的加法是怎么实现的,以及String类型不可变的原因和好处

    1, JAVA 不具备 C++ 和 C# 一样的重载运算符 来实现类与类之间相互计算 的功能    这其实一定程度上让编程失去了代码的灵活性, 但是个人认为,这在一定程度上减少了代码异常的概率     ...

随机推荐

  1. 原生js数组

     forEach()遍历:在原来数组上进行操作 var arrF = [2,3,4]; var arrS = arrF.forEach(function (value,index,a) { //val ...

  2. jQuery选择器分类

    jQuery的基本选择器 选择器的分类 <!--1.基本选择器 2.层级选择器 3.过滤选择器 3.1 基本过滤选择器 3.2 内容过滤选择器 3.3 可见性过滤选择器 3.4 子元素过滤选择器 ...

  3. zepto.js 的tap事件中点击一次触发两次事件

    html代码: <div class="xh-lxx-cart-count1"> <span class="minus">-</s ...

  4. docker~为什么没人说说.dockerignore

    回到目录 最近一直专注于docker的开发之中,而在使用Dockerfile时发现有个问题,当你的发布目录只能是obj\Docker\publish,而指向其它目录dockefile并不认它,只有如何 ...

  5. javascript王国的一次旅行,一个没有类的世界怎么玩转面向对象?

    1. 前言 作为Java 帝国的未来继承人,Java小王子受到了严格的教育, 不但精通Java语言.Java虚拟机.java类库和框架,还对各种官方的Java规范了如指掌. 近日他听说一个叫做Java ...

  6. 导出EXCEL遇到问题

    EXCEL设置的格式要与写入信息的格式要匹配,比如写入信息是字符串类型,而EXCEL单元格是DATE类型则会出错.

  7. HDOJ2007-平方和与立方和

    Problem Description 给定一段连续的整数,求出他们中所有偶数的平方和以及所有奇数的立方和.   Input 输入数据包含多组测试实例,每组测试实例包含一行,由两个整数m和n组成.   ...

  8. 【highchart】经典问题

    摘要 记录遇到的一些问题和解决方案 时差 数据容量 多表联动 1. 时差 问题描述 highcharts 默认是标准 UTC 时间,而国内默认是东八区时间,所以会有8个小时的时差 解决方法 使用hig ...

  9. javascript中的闭包(Closure)的学习

    闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 下面是我在网上通过学习阮一峰老师的笔记,感觉总结很不错,特记录于此. 一.变量的作用域 要理解 ...

  10. 如何重置密码 oracle sys和system

    有时候我们会忘记oracle sys和system的密码,不用担心,通过sqlplus即可修改密码.只能修改,不能找回. 方法如下: 1.打开 cmd界面,输入sqlplus /nolog 显示结果如 ...