Python:我可以为超类中定义的运算符使用一个子类返回其自身类型的实例吗?

Cli*_*ens 5 python inheritance

在Python(2.7)中,我想创建一个有理数类,以模仿Fraction类的行为(在模块分数中),但重写__repr__方法以匹配__str__的结果。最初的想法只是出于我自己的想法,只是为了让IDLE输出看起来更友好。但是现在,我对了解潜在的继承/类型问题(我认为可能是普遍感兴趣的)更感兴趣,而不是针对此特定用例找到解决方法,这是很简单的。

问题是,我也想继承所有数值运算符的功能(方法__add __,__ sub__等),但是结果是我的子类的实例,而不是Fraction的实例。那就是我想要的,但是发生了:

class Q(Fraction):
    def __repr__(self):
        return str(self)

>>> Q(1,2)
1/2
>>> Q(1,2) + Q(1,3)
Fraction(5, 6)
Run Code Online (Sandbox Code Playgroud)

发生这种情况是因为Fraction中定义的运算符返回Fraction实例。当然,我可以单独重写所有这些魔术方法,调用父类进行数学运算然后强制转换为我的类型,但是我觉得应该有一种方法可以通用地处理这种重复情况(即,无需编写“ def” 20次)。

我还考虑过使用__getattribute__来拦截方法调用,但这似乎不雅致,极其脆弱,并且可以保证在甚至比此复杂得多的情况下失败。(我知道__getattr__是首选,但似乎不会捕获我感兴趣的方法调用,因为它们是在基类中定义的!)

鉴于我不是基类的作者,是否有比单独覆盖每个方法更好的方法?

Cor*_*man 2

这需要一些工作,但是您可以将其包装起来并创建一个委托者。我实际上做了与您类似的事情,创建一个默认情况下以十六进制打印的 int 。我自己的一个类的一个更好的例子是 int 的子类,以允许位切片读取(写入显然不起作用,因为 int 是不可变的,所以这个特定的代码并没有走得太远......)。也许示例代码很多,但它展示了如何使用它:

# I stole this decorator from another stackoverflow recipe :) 
def returnthisclassfrom(specials):
  specialnames = ['__%s__' % s for s in specials.split()]
  def wrapit(cls, method):
    return lambda *a: cls(method(*a))
  def dowrap(cls):
    for n in specialnames:
      method = getattr(cls, n)
      setattr(cls, n, wrapit(cls, method))
    return cls
  return dowrap

def int_getslice(self, i, j):
    # NON-pythonic, will return everything inclusive i.e. x[5:3] returns 3 bits, not 2.
    # Because that's what users normally expect.
    # If you're a purist, modify below.
    if i > 1000000 or j > 1000000:
        raise ValueError, 'BitSize limited to 1 million bits'
    lo = min(i,j)
    hi = max(i,j)
    mask = (1<<((hi-lo)+1))-1

    return (self>>lo) & mask

def int_getitem(self, i):
    # Safety limit
    if i > 1000000:
        raise ValueError, 'BitSize limited to 1 million bits'
    return (self>>i)&1

def int_iter(self):
    # since getitem makes it iterable, override
    raise AttributeError, 'int object is not iterable'

@returnthisclassfrom('abs add and div floordiv lshift mod mul neg or pow radd rand rdiv rdivmod rfloordiv rlshift rmod rmul ror rpow rrshift rshift rsub rxor rtruediv sub truediv xor trunc')
class BitSliceInt(long):
  __getslice__ = int_getslice
  __getitem__ = int_getitem
  __iter__ = int_iter
Run Code Online (Sandbox Code Playgroud)