2012-07-24 25 views
3
class Number(object): 
    def __init__(self): 
     super(Number, self).__init__() 
     self.data = 10 

    def __getattr__(self, name): 
     def _missing(*args, **kwargs): 
      method = getattr(self.data, name) 
      return method(args[0]) 

     return _missing 

a = Number() 
b = Number() 

print a.__add__(10) # this is ok! 
print a + 10   # TypeError: "unsupported operand type(s) for +: 'Number' and 'int'" 
print a + b   # TypeError: "unsupported operand type(s) for +: 'Number' and 'Number'" 

問題: 什麼是「一.__添加__(10)」和「A + 10」,我怎麼能勾運算符「+」之間的區別?蟒蛇:如何實例的方法調用轉發到它的屬性

+0

覆蓋'__add__'方法。 – Stan 2012-07-24 10:57:51

回答

4

Python只會使用實際的__add__方法,而不是僅由於__getattr__而「存在」的方法。

當加入__add__ = (10).__add__它工作正常。

所以你想要做的是增加代理方法:

def __add__(self, *args): return self.data.__add__(*args) 
def __sub__(self, *args): return self.data.__sub__(*args) 
# ... 
+0

感謝您的回覆,但我想使用更「動態」的方式來實現這一點,任何建議?一個python內置的數字類有大量的\ __ xx \ __方法,我不想逐個添加它們。 :) – chinloon 2012-07-24 11:08:48

+0

不幸的是,這是要走的路 - 但你可以做很多複製和粘貼,例如,來自[werkzeug的LocalProxy類](https://github.com/mitsuhiko/werkzeug/blob/master/werkzeug/local.py#L350),它應該可以通過搜索和替換操作進行小的更改。 – ThiefMaster 2012-07-24 12:12:30

+1

@chinloon在https://mail.python.org/pipermail/python-ideas/2015-December/037348.html是一個有趣的想法可能對你有用... – Liso 2015-12-17 08:12:02

1

你可以試試這個,但它不漂亮:

import numbers 

def redirect(name): 
    def redirected(self, *args): 
     assert len(args) <= 1 
     if len(args) == 1 and isinstance(args[0], Number): 
      return getattr(self._data, name)(args[0]._data) 
     else: 
      return getattr(self._data, name)(*args) 
    return redirected 

names = set(['__gt__', '__ge__']) 
names.update(numbers.Real.__abstractmethods__) 
methods = dict((name, redirect(name)) for name in names) 
methods.update(
    {'__init__': lambda self, data: setattr(self, '_data', float(data))}) 
Number = type("Number",(), methods) 

您可以使用它像這樣:

>>> a = Number(5) 
>>> b = Number(7) 
>>> a + 10 
15.0 
>>> a + b 
12.0 
>>> a > b 
False 
>>> a == Number(5.0) 
True 

請注意,從算術運算符返回的類型是float而不是Number(這可能是也可能不是你所期望的)。

如果您想要整數,您可以刪除float()呼叫並將numbers.Real更改爲numbers.Integral。 但是請注意,算術運算符將停止使用浮點值。