2017-02-27 18 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