63

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

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

+obj != obj

通用对象在哪里obj实现__pos__().

所以我想知道:为什么存在+__pos__()存在?你能提供一个真实世界的例子,上面的表达式计算为True吗?

4

7 回答 7

48

这是包中的“真实世界”示例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')
于 2013-05-29T16:29:26.287 回答
30

在 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})

因此,如果您在 a 中有负数或零计数Counter,您就会遇到+obj != obj.

>>> obj = Counter({'a': 0})
>>> +obj != obj
True
于 2013-09-16T00:41:44.233 回答
28

我相信 Python 运算符受到 C 的启发,其中+引入了运算符以实现对称性(以及一些有用的技巧,请参阅评论)。

在 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"

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

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

While1/0仍未定义,1/epsilon = 1/+0is+infinity1/-epsilon= -infinity。无非1/xx从右0(+)或左(-)取限制。

由于0+0行为不同,0 != +0.

于 2013-05-29T16:26:16.177 回答
7

这里的很多例子看起来更像是错误。不过,这实际上是一项功能:

操作员+暗示一个副本

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

例如:

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......我想这会起作用,但它很麻烦。

一元+是一个非常好的选择。

于 2019-09-15T08:57:31.877 回答
5

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

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

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

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

毕竟......如果您需要的话,多一个操作员真是太好了。

于 2016-02-18T13:46:53.297 回答
3

__pos__()Python中的存在为程序员提供了与C++语言中类似的可能性——重载运算符,在本例中为一元运算符 +

重载运算符意味着为不同的对象赋予它们不同的含义,例如二进制对于+数字字符串的行为不同- 数字相加,而字符串连接。)

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

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

所以+object意思是一样的object.__pos__()——它们是可以互换的。

但是,+object更容易对眼睛。

特定对象的创建者可以随意实现这些功能——正如其他人在现实世界的示例中所展示的那样。

还有我的贡献——开个玩笑: ++i != +i 在 C/C++中。

于 2016-11-21T20:07:06.080 回答
0

一元+实际上是查看值是否为数字的最快方法(如果不是,则引发异常)!它是字节码中的一条指令,像 isinstance(i, int) 这样的指令实际上会查找并调用isinstance函数!

于 2021-12-20T06:27:21.630 回答