引言
有些事情让我不安,比如运算符重载。我决定不支持运算符重载,这完全是个人选择,因为我见过太多 C++ 程序员滥用它——James Gosling(Java 之父)
ps: 运算符重载它不香吗
写在前面
对于复利公式,在python中只需要
|
|
其中periods
是整数, rate
、interest
和principal
是精确的数字(Python 中decimal.Decimal
类的实例)
但是在Java
中,如果把float
换成精度不定的BigDecimal
,就无法再使用中缀运算符,因为中缀运算符只支持基本类型。用过java大数类的都知道会写吐的:
|
|
Python禁止重载内置类型的运算符
一元运算符
- (__neg__)
, 取负运算符+ (__pos__)
, 取正运算符~ (__invert__)
, 取反运算符
一元运算符要遵守运算符的一个基本规则:始终返回一个新对象
x
和+x
何时不等
当x
是decimal.Decimal
实例子时,由于+
运算返回新的实例,可能会导致偏差, 所以导致内容不等, 即x != +x
ps一般比较两个浮点数都要设置一个精度来判别
重载加法运算符+
和乘法运算符*
为了支持涉及不同类型的运算,Python为中缀运算符特殊方法提供了特殊的分派机制
。对
表达式a + b
来说,解释器会执行以下几步操作
- 如果
a
有__add__
方法,而且返回值不是NotImplemented
,调用a.__add__(b)
,然后返回结果。 - 如果
a
没有__add__
方法,或者调用__add__
方法返回NotImplemented
,检查b
有没有__radd__
方法,如果有,而且没有返回NotImplemented
,调用b.__radd__(a)
,然后返回结果。 - 如果
b
没有__radd__
方法,或者调用__radd__
方法返回NotImplemented
,抛出TypeError
,并在错误消息中指明操作数类型不支持。
注意
- 实现一元运算符和中缀运算符的特殊方法一定
不能修改操作数
。使用这些运算符的表达式期待结果是新对象
- 如果由于类型不兼容而导致运算符特殊方法无法返回有效的结果,那么应该返回
NotImplemented
,而不是抛出TypeError
。返回 NotImplemented 时,另一个操作数所属的类型还有机会执行运算,即Python
会尝试调用反向方法。 - 为了遵守鸭子类型精神,我们不能测试
other
操作数(即右操作数)的类型,我们要捕获异常,然后返回NotImplemented
。如果解释器还未反转操作数,那么它将尝试去做。如果反向方法返回NotImplemented
,那么Python
会抛出TypeError
,并返回一个标准的错误消息,例如“unsupported operand type(s) for +: Vector and str”。
python3.5
支持中缀运算符@
(点积运算)
比较运算符
Python解释器对众多比较运算符(==
、!=
、>
、<
、>=
、<=
)的处理与前文类似,不过在两个方面有重大区别。正向和反向调用使用的是同一系列方法。如图所示
Python在object
基类中通过__ne__
方法为!=
提供了便利的实现
增量赋值运算符
None
写在最后
我不能体会之前说的少用isinstance()
去判断参数类型转而去拥抱鸭子类型
,这有什么区别吗?反而我觉得用isinstance()
会更显式
, 而像鸭子类型
那样try...except..
反而更隐式