2017-02-27 21 views
9

假設我創建了一個基本上代表一個數字加上一些花哨的東西的類。在任何算術/數學運算中,該類的實例的行爲應該與數字類似。用Python重載所有算術運算符

我可以重載該類中的所有數值運算符,但是沒有更短的解決方案嗎?

類基本上是這樣的:

class MyFancyNumber: 
    def __init__(self, num, info): 
     self.num = num # the actual number 
     self.info = info # some more info, or other data 
    def doFancyStuff(self): 
     # does something fancy 
    def __add__(self, other): 
     return self.num + other # same pattern for all numeric functions 
+1

https://docs.python.org/3/library/numbers.html這可能會幫助您開始。 –

+1

以這種方式使用'__add__'可能無法做到你想要的。 'MyFancyNumber(1,'abc')+ 1'會給你一個'int'對象,而不是'MyFancyNumber'。 –

+1

據我所知,他不想返回一個MyFancyNumber,他只想把所有的功能都作爲運算符術語中的一個數字。 – Szabolcs

回答

1

不,你必須定義,否則所有的算術運算符怎麼會知道的Python與他們做什麼。不要忘記你還需要像__radd__這樣的逆向運算符。

此外,您所寫的代碼返回intx+1。你的意思是說,還是你想添加一個奇特的數字來返回另一個奇特的數字?

您可以將子類別intfloat。然後,您不必重新實現操作員,但是每當您操作某個值時,您仍然會失去特殊性。

更好的解決方案只是在屬性中包含數值並在需要時將其明確地轉換爲數字。您可以使用__int__()__float__()來實現轉換。

文檔涵蓋了你需要做什麼,如果你真的想要模仿一個數值類型:爲Python 3.x的https://docs.python.org/3/reference/datamodel.html?highlight=int#emulating-numeric-types或爲Python 2.x的https://docs.python.org/2/reference/datamodel.html?highlight=int#emulating-numeric-types

7

這個是什麼?

class MyFancyNumber(int): 
    def __new__(cls, num, info=None): 
     return super(MyFancyNumber, cls).__new__(cls, num) 
    def __init__(self, num, info=None): 
     self.num = num 
     self.info = info 
>>> MyFancyNumber(5) 
5 
>>> MyFancyNumber(5) + 2 
7 
>>> MyFancyNumber(5)/4 
1 
>>> MyFancyNumber(5) * 0.5 
2.5 
>>> MyFancyNumber(5) - 7 
-2 
>>> MyFancyNumber(5, 'info').info 
'info' 

我想根據上面的內容,你可以弄清楚你需要什麼。

+0

如果您在示例中包含額外參數,那會更好。此外,這與原來的問題相同,即在任何可能或可能不是他們想要的操作上丟失子類。 – Duncan

+0

他希望該類的實例在任何算術/數學運算中的行爲應與數字類似。 – Szabolcs

+0

這種方法優於我的方法的一個優點是,您不必窮舉所有要定義的操作符。一個月後,冷汗沒有醒來,喊道:「我忘了執行'__radd__'!」 ;-) – Kevin

0

只要你在init中只傳遞一個參數,它就可以在python 2.7中使用。可悲的是,不知道它爲什麼會起作用。

class MyFancyNumber(int): 
    def __init__(self, num): 
     self.num = num # the actual number 

    def add_info(self,info): 
     self.info = info ## Add the info separately 

    def doFancyStuff(self): 
     # does something fancy 

print MyFancyNumber(5)+5  

使用

f = MyFancyNumber(2) 
f.add_info(info) 
f+4    ## returns 6 
2

我並不贊同這個爲特別地道,但是......

假設所有的函數定義的行爲相同,像「只是調用基行爲self.num類,並將所有非自變量應用於它「,然後您可以遍歷所有要定義的函數名稱,並使用setattr創建每個函數名稱。例如:

class MyFancyNumber(object): 
    def __init__(self, num, info): 
     self.num = num 
     self.info = info 
    def __repr__(self): 
     return "MyFancyNumber({}, {})".format(repr(self.num), repr(self.info)) 

def make_func(name): 
    return lambda self, *args: MyFancyNumber(getattr(self.num, name)(*args), self.info) 

for name in ["__add__", "__sub__", "__mul__", "__div__", "__invert__", "__neg__", "__pos__"]: 
    setattr(MyFancyNumber, name, make_func(name)) 

x = MyFancyNumber(50, "hello") 
print(x + 10) 
print(x - 10) 
print(x * 10) 
print(x/10) 
print(~x) 
print(-x) 
print(+x) 

結果:

MyFancyNumber(60, 'hello') 
MyFancyNumber(40, 'hello') 
MyFancyNumber(500, 'hello') 
MyFancyNumber(5, 'hello') 
MyFancyNumber(-51, 'hello') 
MyFancyNumber(-50, 'hello') 
MyFancyNumber(50, 'hello') 

編輯:我不知道你是否想運算的結果是一個MyFancyNumber或常規內置數值類型,但無論是這樣,執行是非常相似的:

class MyFancyNumber(object): 
    def __init__(self, num, info): 
     self.num = num 
     self.info = info 
    def __repr__(self): 
     return "MyFancyNumber({}, {})".format(repr(self.num), repr(self.info)) 

def make_func(name): 
    return lambda self, *args: getattr(self.num, name)(*args) 

for name in ["__add__", "__sub__", "__mul__", "__div__", "__invert__", "__neg__", "__pos__"]: 
    setattr(MyFancyNumber, name, make_func(name)) 

x = MyFancyNumber(50, "hello") 
print(x + 10) 
print(x - 10) 
print(x * 10) 
print(x/10) 
print(~x) 
print(-x) 
print(+x) 

結果:

60 
40 
500 
5 
-51 
-50 
50 
+0

它可能不是特別習慣,但肯定是程序化的 – ofloveandhate