Python中+(pos)一元运算符的用途是什么?

时间:2013-05-29 16:14:12

标签: python

一般来说,一元+应该在Python中做什么?

我问,因为到目前为止,我从未见过这样的情况:

+obj != obj

obj是实现__pos__()的通用对象。

所以我想知道:为什么+__pos__()存在?您能否提供一个真实示例,其中上面的表达式求值为True

6 个答案:

答案 0 :(得分:39)

以下是decimal包中的“真实世界”示例:

>>> from decimal import Decimal
>>> obj = Decimal('3.1415926535897932384626433832795028841971')
>>> +obj != obj  # The __pos__ function rounds back to normal precision
True
>>> obj
Decimal('3.1415926535897932384626433832795028841971')
>>> +obj
Decimal('3.141592653589793238462643383')

答案 1 :(得分:22)

我认为Python操作符受C的启发,+运算符是为了对称而引入的(还有一些有用的hacks,请参阅注释)。

在弱类型语言(如PHP或Javascript)中,+告诉运行时将变量的值强制转换为数字。例如,在Javascript中:

   +"2" + 1
=> 3
   "2" + 1
=> '21'

Python是强类型的,因此字符串不能用作数字,因此,不要实现一元加运算符。

当然可以实现+ obj!= obj:

的对象
>>> class Foo(object):
...     def __pos__(self):
...        return "bar"
... 
>>> +Foo()
'bar'
>>> obj = Foo()
>>> +"a"

至于它实际上有意义的例子,请查看 surreal numbers。他们是实物的超集,其中包括 无穷小的值(+ epsilon, - epsilon),其中epsilon是 一个小于任何其他正数的正值,但是 大于0;和无限的(+无穷大, - 无穷大)。

您可以定义epsilon = +0-epsilon = -0

虽然1/0仍未定义,但1/epsilon = 1/+0+infinity1/-epsilon = -infinity。它是 只是从右侧(+)或左侧( - )获取1/x x aproaches 0的限制。

由于0+0行为不同,因此0 != +0才有意义。

答案 2 :(得分:17)

在Python 3.3及更高版本中,collections.Counter使用+运算符删除非正数。

>>> from collections import Counter
>>> fruits = Counter({'apples': 0, 'pears': 4, 'oranges': -89})
>>> fruits
Counter({'pears': 4, 'apples': 0, 'oranges': -89})
>>> +fruits
Counter({'pears': 4})

因此,如果Counter中的计数为负数或为零,则表明您的情况为+obj != obj

>>> obj = Counter({'a': 0})
>>> +obj != obj
True

答案 3 :(得分:5)

对于对称性,因为一元减号是一个算子,一元加号也必须是。在大多数算术情况下,它不会做任何事情,但请记住,用户可以定义任意类并将这些运算符用于他们想要的任何内容,即使它不是严格的代数。

我知道这是一个旧线程,但我想扩展现有的答案以提供更广泛的例子:

  • +可以断言积极性并抛出异常,如果不是 - 检测极端情况非常有用。
  • 对象可以是多值的(将±sqrt(z)视为单个对象 - 用于求解二次方程,用于多分支分析函数,任何可以将二值函数“折叠”到带有符号的一个分支中的任何内容。这包括vlopez提到的±0案例。
  • 如果您进行延迟评估,则可能会创建一个函数对象,该函数对象会向其他内容添加任何内容。例如,如果您要逐步解析算术。
  • 作为身份函数传递给某些函数的参数。
  • 对于符号累积的代数结构 - 梯形算子等。当然,它可以通过其他功能完成,但可以想象可以看到像y=+++---+++x这样的东西。更重要的是,他们不必通勤。这构建了一个免费的正和负组,这可能是有用的。即使在正式的语法实现中也是如此。
  • 狂野使用:在某种意义上,它可以将计算中的一个步骤“标记为”“活跃”。收割/播种系统 - 每个加号记住价值,最后,你可以收集收集的中间产品......因为为什么不呢?

那,加上其他人提到的所有类型转换原因。

毕竟......如果你需要的话,还有一个操作员很高兴。

答案 4 :(得分:2)

这里的许多示例看起来更像是bug。不过,这实际上是一项功能:

+运算符表示副本

在为标量和数组编写通用代码时,这非常有用。

例如:

def f(x, y):
    z = +x
    z += y
    return z

此功能适用于标量 NumPy数组无需进行额外的复制,而无需可以更改对象,并且没有需要任何外部依赖项!

如果您使用numpy.positive或类似的东西,则会引入NumPy依赖关系,并将数字强制为NumPy类型,而调用者可能会不希望这样。

如果您进行了z = x + y,则结果将不再是与x相同的类型。在许多情况下都可以,但如果不是,则不是一种选择。

如果您执行了z = --x,则将创建不必要的副本,这很慢。

如果您进行了z = 1 * x,则将执行不必要的乘法,这也很慢。

如果您做了copy.copy ...我想那是可行的,但这很麻烦。

一元+是一个非常不错的选择。

答案 5 :(得分:1)

__pos__()存在于 Python 中,为程序员提供与 C++语言 - 重载运算符类似的可能性,在这种情况下,一元运算符 +

重载运算符意味着为不同的对象提供不同的含义,例如 binary + 的行为方式不同数字字符串 - 数字已添加,而字符串连接。)

对象可以实现(除此之外)这些模拟数字类型函数(方法):

    __pos__(self)             # called for unary +
    __neg__(self)             # called for unary -
    __invert__(self)          # called for unary ~

所以+objectobject.__pos__()相同 - 它们是可互换的。

然而+object更容易被人看到。

特定对象的创造者可以随心所欲地实现这些功能 - 正如其他人在现实世界中所展示的那样。

我的贡献 - 作为一个笑话: ++i != +i in C / C ++