Python为数字类型提供a set of abstract base classes。这些以Number
开头,其中Complex
是一个子类,依此类推至Real
,Rational
和Integral
。由于每个都是最后一个的子类,它们都支持序列中之前的类的特殊功能。例如,您可以编写(1).numerator
以获取Python整数1
的分子,该分子使用整数字面值1
创建,并被视为一个有理数。在Real和Rational之间添加数字类型,并支持Rational数字的类型功能
链接的页面注释:当然,数字有更多可能的ABC,如果它阻止添加这些数据的可能性,这将是一个糟糕的层次结构。 - 从而增加新
class MyFoo(Complex): ...
MyFoo.register(Real)
这有加复数的新子类的效果,使得Real
类型的对象将测试其新的类的实例:你可以用复杂和真实之间添加MyFoo类别“在”Complex
和Real
之间“。然而,这并没有解决新类别可能会引入其子类别未提供的功能(如numerator
属性所例示的功能)的可能性。
例如,假设您要添加一个类,其实例表示a + b√2
形式的数字,其中a
和b
是有理数。您可能会在内部将这些数字表示为一对Fraction
(来自Python标准库的fraction.Fraction
的实例)。显然,这类数字恰好是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!')
有没有比这更好的方法?