Python 定义数字类,有时需要拓展Python已有的数值系统,通过继承numbers.Number
类来简化函数式编程。例如可以把复杂的算法封装在Number
的子类中,以简化或者明晰化应用的其他部分。
Python提供了丰富的数值类型,内置的int
类型和float
类型覆盖了大多数应用场景。使用decimal.Decimal
包能很好地处理货币相关问题。某些场景中,fractions.Fraction
比float
更适用。
例如处理地理数据,可以通过继承float
类,引入新的属性来实现经度或者纬度与弧度之间的转换。利用这个类可以方便地处理跨越赤道或者格林威治子午线时需要进行的计算(mod(2π))
。
由于Python的Number
类是不可变的,常用的函数设计方法都可以在这里使用,对于少数自身状态会变化的函数(例如__iadd__()
函数),直接忽略即可。
使用Number
的子类时,需要考虑下面几点。
- 相等测试与哈希值计算。哈希值计算的核心特点可参考Python标准库文档9.1.2节。
- 其他比较运算符(通常由
@total_ordering
装饰器定义)。 - 算术运算符:
+
、-
、*
、/
、//
、%
和**
,包括处理前置运算符的特殊方法和反向类匹配的附加方法。对于表达式a-b
,Python尝试在a
的类型中寻找实现__sub__()
方法的函数,即a.__sub__(b)
方法。如果左侧变量(这里是a
)的类没有这个方法,或者出现NotImplemented
异常,再检查右侧变量是否提供了b.__rsub__(a)
方法。当b
是a
的子类时为特殊情况,允许子类的实现方法覆盖左侧变量的实现方法。 - 位运算算子:
&
、|
、^
、>>
、<<
和~
。实数无须考虑这些运算符,直接忽略即可。 - 其他函数如
round()
、pow()
、divmod()
等由专门的数值处理方法实现,对这里定义的类可能有意义。
前面有个例子详细演示了创建新数值类型的过程,具体过程可参考https://www.packtpub.com/application-development/mastering-object-oriented-python。
前面讲过,函数式编程和面向对象编程是互补的,完全可以按照函数式编程的要求定义类。创建数值类型的例子很好地展示了如何利用Python的面向对象特征创建易读的函数式程序。