Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/333.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
重载Python中的所有算术运算符_Python - Fatal编程技术网

重载Python中的所有算术运算符

重载Python中的所有算术运算符,python,Python,假设我构建了一个类,它基本上表示一个数字加上一些奇特的东西。该类的实例在任何算术/数学运算中的行为都应该类似于数字 我可以重载该类中的所有数字运算符,但没有更短的解决方案吗? 该类基本上如下所示: class MyFancyNumber: def __init__(self, num, info): self.num = num # the actual number self.info = info # some more info, or other

假设我构建了一个类,它基本上表示一个数字加上一些奇特的东西。该类的实例在任何算术/数学运算中的行为都应该类似于数字

我可以重载该类中的所有数字运算符,但没有更短的解决方案吗?

该类基本上如下所示:

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

不,您必须定义所有算术运算符,否则Python将如何知道如何处理它们。不要忘记,您还需要反向运算符,如
\uuu radd\uu

另外,您编写的代码返回
x+1
int
。你的意思是,还是你想添加一个花式号码来返回另一个花式号码

您可以将
int
float
子类化。这样,您就不必重新实现运算符,但无论何时对某个值进行操作,都会失去其特殊性

更好的解决方案是在属性中包含数值,并在需要时显式转换为数字。您可以使用
\uuuu int\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

文档介绍了如果您真的想模拟数字类型,您需要做什么:对于Python3.x或Python2.x,这是怎么回事

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'

我想根据上面的内容,您可以找到您需要的。

在python 2.7中,只要在init中只传递一个参数,这对我是有效的。遗憾的是,我不知道为什么它会起作用

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    
用法


我不认为这是特别地道的,但是

假设所有函数定义的行为都相同,比如“只需调用
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')
60
40
500
5
-51
-50
50

编辑:我不确定您希望算术的结果是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)
结果:

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

这可能有助于您开始。以这种方式使用
\uuuuu添加\uuuuu
可能无法实现您想要的功能
MyFancyNumber(1,'abc')+1
将为您提供一个
int
对象,而不是
MyFancyNumber
。据我所知,他不想返回一个MyFancyNumber,他只想将所有功能作为运算符中的一个数字。@Szabolcs:是的。基本上,每当一个
MyFancyNumber
出现在一个算术表达式中时,我也很乐意使用隐式转换。我还添加了init方法。如果您在示例中包含额外的参数会更好。另外,这与最初的方法存在相同的问题,即在任何操作中都会丢失子类,而这些操作可能不是他们想要的。他希望该类的实例在任何算术/数学操作中都表现为数字。这种方法与我的方法相比有一个优势,您不必穷尽地枚举要定义的每个运算符。不要在一个月后冒冷汗醒来,大喊“我忘了实现
\uuu radd\uu
!”;-)此方法不允许任何人在初始化以外的任何时间设置
.num
,否则,这些操作将不会像您预期的那样工作。@palswim从OP开始,这不是一个要求。在Python中,数字通常是不可变的,因此在这种情况下,我不会将用户与可变性混淆。它可能不是特别习惯用法,但肯定是编程的