2014-03-29 18 views
0

Python为数字类型提供a set of abstract base classes。这些以Number开头,其中Complex是一个子类,依此类推至Real,RationalIntegral。由于每个都是最后一个的子类,它们都支持序列中之前的类的特殊功能。例如,您可以编写(1).numerator以获取Python整数1的分子,该分子使用整数字面值1创建,并被视为一个有理数。在Real和Rational之间添加数字类型,并支持Rational数字的类型功能

链接的页面注释:当然,数字有更多可能的ABC,如果它阻止添加这些数据的可能性,这将是一个糟糕的层次结构。 - 从而增加新

class MyFoo(Complex): ... 
MyFoo.register(Real) 

这有加复数的新子类的效果,使得Real类型的对象将测试其新的类的实例:你可以用复杂和真实之间添加MyFoo类别“在”ComplexReal之间“。然而,这并没有解决新类别可能会引入其子类别未提供的功能(如numerator属性所例示的功能)的可能性。

例如,假设您要添加一个类,其实例表示a + b√2形式的数字,其中ab是有理数。您可能会在内部将这些数字表示为一对Fraction(来自Python标准库的fraction.Fraction的实例)。显然,这类数字恰好是Real的子类,我们希望将Rational作为它的子类(因为每个有理数是我们的新类型的一个数字,其中b == 0)。所以我们这样做:

class FractionWithRoot2Part (Real): ... 
FractionWithRoot2Part.register(Rational) 

我们可能希望将属性添加到新的类(比方说)返回的人数ab。这些属性可能被称为RationalPartCoefficientOfRoot2。但是,这很尴尬,因为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!') 

有没有比这更好的方法?

回答

0

您不能使用ABCs以这种方式修改现有类(实际上,您无法以这种方式安全地修改现有类)。 ABCs只是定制一个类是否作为另一个类的子类(以及它的实例作为另一个的实例进行测试)的机制,而不是实际更改子类实现的机制。当文件谈到定义一个“介于两者之间”的新类时,这就是它意义上的含义;它仅仅意味着在子类/实例检查之间,而不是实际的继承。这说明here

基本知识介绍虚拟的子类,这是不从一个类继承,但仍然受到isinstance()认可和issubclass()

注意它说什么类:虚拟子类实际上并没有从你的ABC继承,他们只是测试,就好像他们一样。这就是ABC设计的工作原理。建议使用它们的方法here

ABC可以被直接子类化,然后充当混合类。

所以你不能使用ABC修改现有的Rational类。做你想做什么的方法是创建一个从Rational继承的新类,并将你的ABC作为一个mixin使用。然后使用该类而不是常规的Rational。

事实上,你甚至可能真的不需要在这里使用ABC。使用ABC的唯一好处是,如果有人明确地测试,它会让你的新理性数字看起来像Rationals;但只要您从Rational继承,并从您的新类中继承了您想要的行为,那么新类将会像Rationals一样动作

当你说

这是尴尬的,但是,因为输入Rational的现有数量将不具备这些特性。

你有针对性的情况精髓。这似乎笨拙,但它也将是强大的尴尬,如果有人可以进来,与ABC结束运行,开始在继承层次坚持上面摆着一个新的超类修改现有类的行为。这不是它的工作原理。没有安全的方法可以将任何类的实例的现有实例添加到;唯一安全的做法是向新班级添加新行为,并告诉人们使用新班级而不是旧班级。

相关问题