2013-11-10 57 views
4

在Python(2.7)中,我想創建一個有理數字類,它模仿Fraction類(在模塊分數中)的行爲,但是會覆蓋__repr__方法來匹配__str__的結果。最初的想法只是爲了我自己的修補,並且爲了讓IDLE輸出看起來更友好。但是現在我更感興趣的是理解潛在的繼承/打字問題 - 我認爲這可能是普遍感興趣的 - 而不是爲這個特定的用例找到解決方法,這是毫無意義的。Python:我可以爲超類中定義的運算符創建自己類型的子類返回實例嗎?

問題是,我想繼承所有數值運算符(方法__add__,__sub__等)的功能,但結果是我的子類的實例而不是分數的實例。這就是我想要的,但相反,發生這種情況:

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__是首選,但似乎不會捕獲我感興趣的方法調用,因爲它們是在基類中定義的!)

鑑於我不是基類的作者,是否有比單獨覆蓋每種方法更好的方法?

+5

不幸的是,你必須定義所有的魔法方法。 ('__geattribute__'將不起作用,它不會捕獲神奇方法的魔法調用。)但是,您可以使用[這裏]描述的方法(http://stackoverflow.com/questions/9057669/how-can-i -intercept-calls-to-pythons-magic-methods-in-new-style-classes)自動創建這樣的方法。基本上,你編寫了一個元類,它自動定義了調用基類魔術方法的神奇方法,並將結果包裝在派生類中。 – BrenBarn

+1

所以主要的問題是你的基類'Fraction'沒有很好的繼承設計。如果是的話,它會使用'type(self)(...)'來創建它返回的對象(或者它顯示的repr-strings)。不幸的是,這意味着它會讓你的生活變得更難 – shx2

回答

1

這是一個工作,但你可以包裝它並創建一個委託。我實際上做了類似於你所做的事情,創建一個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 
+0

這段代碼工作得很好,雖然完全公開,但它確實導致了至少一個運算符(\ _ \ _ rpow \ _ \ _)的無限循環,這可能與分數模塊處理反向運算符的複雜方式有關。 –

相關問題