一般来说,一元+
在 Python 中应该做什么?
我问是因为到目前为止,我从未见过这样的情况:
+obj != obj
通用对象在哪里obj
实现__pos__()
.
所以我想知道:为什么存在+
和__pos__()
存在?你能提供一个真实世界的例子,上面的表达式计算为True
吗?
一般来说,一元+
在 Python 中应该做什么?
我问是因为到目前为止,我从未见过这样的情况:
+obj != obj
通用对象在哪里obj
实现__pos__()
.
所以我想知道:为什么存在+
和__pos__()
存在?你能提供一个真实世界的例子,上面的表达式计算为True
吗?
这是包中的“真实世界”示例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')
在 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
我相信 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/+0
is+infinity
和1/-epsilon
= -infinity
。无非1/x
是x
从右0
(+)或左(-)取限制。
由于0
和+0
行为不同,0 != +0
.
这里的很多例子看起来更像是错误。不过,这实际上是一项功能:
+
暗示一个副本。这在为标量和数组编写通用代码时非常有用。
例如:
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
......我想这会起作用,但它很麻烦。
一元+
是一个非常好的选择。
对于对称性,因为一元减号是运算符,所以一元加号也必须是运算符。在大多数算术情况下,它什么都不做,但请记住,用户可以定义任意类并将这些运算符用于他们想要的任何东西,即使它不是严格代数的。
我知道这是一个旧线程,但我想扩展现有答案以提供更广泛的示例:
+
如果不是,可以断言积极性并抛出异常 - 对于检测极端情况非常有用。±sqrt(z)
其视为单个对象 - 用于求解二次方程,用于多分支分析函数,任何可以将双值函数“折叠”为一个带有符号的分支的东西。这包括 vlopez 提到的 ±0 情况。y=+++---+++x
. 更重要的是,他们不必通勤。这构建了一组可能有用的自由加减号。即使在正式的语法实现中。那,加上其他人提到的所有类型转换原因。
毕竟......如果您需要的话,多一个操作员真是太好了。
__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++中。
一元+
实际上是查看值是否为数字的最快方法(如果不是,则引发异常)!它是字节码中的一条指令,像 isinstance(i, int) 这样的指令实际上会查找并调用isinstance
函数!