Python 为数字类型提供了一组抽象基类。这些以 开头Number
,其中Complex
是一个子类,依此类推,一直到Real
,Rational
和Integral
。由于每个都是最后一个的子类,因此每个都支持序列中在它之前的类的特殊功能。例如,您可以编写(1).numerator
以获取 Python integer 的分子,该分子是1
使用整数文字创建的1
,被视为有理数。
链接页面说明:当然,数字可能有更多的 ABC,如果排除了添加这些的可能性,这将是一个糟糕的层次结构。您可以在 Complex 和 Real 之间添加 MyFoo:
class MyFoo(Complex): ...
MyFoo.register(Real)
这具有添加复数的新子类的效果,这样类型的对象Real
将作为新类的实例进行测试 - 因此在“中间”Complex
和Real
某种意义上添加了新类。然而,这并没有解决新类可能引入numerator
其子类未提供的功能(例如由属性举例说明的功能)的可能性。
例如,假设您要添加一个类,其实例表示形式为a + b√2
wherea
和b
是有理数的数字。您可能会在内部将这些数字表示为一对Fraction
s(fraction.Fraction
来自 Python 标准库的实例)。显然,这类数是 的子类Real
,我们希望将Rational
其视为它的子类(因为每个有理数都是我们的新类型的数b == 0
)。所以我们会这样做:
class FractionWithRoot2Part (Real): ...
FractionWithRoot2Part.register(Rational)
我们可能希望向新类添加属性(比如)返回数字a
和b
. 这些属性可能被称为RationalPart
和CoefficientOfRoot2
。然而,这很尴尬,因为现有的类型数量Rational
将不具有这些属性。如果我们写(1).RationalPart
,那么我们将得到一个AttributeError
. 示范:
Python 3.3.1 (v3.3.1:d9893d13c628, Apr 6 2013, 20:25:12) [MSC v.1600 32 bit (In
tel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from abc import *
>>> class c1 (metaclass = ABCMeta):
... def x (self): return 5
...
>>> class c2: pass
...
>>> c1.register(c2)
<class '__main__.c2'>
>>> a1 = c1()
>>> a2 = c2()
>>> a1.x()
5
>>> a2.x()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'c2' object has no attribute 'x'
因此,我们并没有真正引入一个新的类型,它“介于”现有的两个类型之间,因为子类关系的“底部”类型不支持“中间”类的行为。
解决这个问题的普遍接受的方法是什么?一种可能性是提供一个函数(不是任何类的方法),它可以处理任何类型的输入并智能地行动;像这样的东西:
def RationalPart (number):
if isinstance(number, FractionWithRoot2Part):
try:
return number.RationalPart
except AttributeError:
# number is presumably of type Rational
return number
else:
raise TypeError('This is not supported you dummy!')
还有比这更好的方法吗?