7

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)

これは Fraction で定義された演算子が Fraction インスタンスを返すために発生します。もちろん、これらすべての魔法のメソッドを個別にオーバーライドして、親クラスを呼び出して計算を行ってから自分の型に強制することもできますが、そのような反復的な状況を一般的に処理する方法が必要だと思います (つまり、"def" 20 を記述せずに)回)。

メソッド呼び出しをインターセプトするために __getattribute__ を使用することも検討しましたが、これは洗練されておらず、非常に壊れやすく、これよりわずかに複雑な状況でも失敗することがほとんど保証されています。(私は __getattr__ が好まれることを知っていますが、それらは基本クラスで定義されているため、私が興味を持っているメソッド呼び出しをキャッチしないようです!)

私が基本クラスの作成者ではないことを考えると、各メソッドを個別にオーバーライドするよりも良い方法はありますか?

4

1 に答える 1

2

少し手間がかかりますが、ラップしてデリゲータを作成できます。デフォルトで16進数で出力されるintを作成するために、私は実際にあなたがしたことと同様のことをしました。int をサブクラス化する私自身のクラスの 1 つからのより良い例で、ビットスライス読み取りを可能にします (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
于 2013-11-13T15:35:00.060 に答える