简体   繁体   English

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

[英]What's the purpose of the + (pos) unary operator in Python?

Generally speaking, what should the unary + do in Python?一般来说,Python中的一元+应该做什么?

I'm asking because, so far, I have never seen a situation like this:我问是因为到目前为止,我从未见过这样的情况:

+obj != obj

Where obj is a generic object implementing __pos__() .其中obj是实现__pos__()的通用 object 。

So I'm wondering: why do + and __pos__() exist?所以我想知道:为什么+__pos__()存在? Can you provide a real-world example where the expression above evaluates to True ?你能提供一个真实的例子,上面的表达式计算为True吗?

Here's a "real-world" example from the decimal package:这是来自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')

In Python 3.3 and above, collections.Counter uses the + operator to remove non-positive counts.在 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})

So if you have negative or zero counts in a Counter , you have a situation where +obj != obj .因此,如果Counter有负数或零计数,则会出现+obj != obj

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

I believe that Python operators where inspired by C, where the + operator was introduced for symmetry (and also some useful hacks, see comments).我相信 Python 运算符的灵感来自 C,其中引入了+运算符以实现对称(还有一些有用的技巧,请参阅注释)。

In weakly typed languages such as PHP or Javascript, + tells the runtime to coerce the value of the variable into a number.在弱类型语言(如 PHP 或 Javascript)中,+ 告诉运行时将变量的值强制转换为数字。 For example, in Javascript:例如,在 Javascript 中:

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

Python is strongly typed, so strings don't work as numbers, and, as such, don't implement an unary plus operator. Python 是强类型的,因此字符串不能用作数字,因此不实现一元加号运算符。

It is certainly possible to implement an object for which +obj != obj :当然可以实现一个 +obj != obj 的对象:

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

As for an example for which it actually makes sense, check out the surreal numbers .至于实际有意义的示例,请查看超现实数字 They are a superset of the reals which includes infinitesimal values (+ epsilon, - epsilon), where epsilon is a positive value which is smaller than any other positive number, but greater than 0;它们是实数的超集,包括无穷小的值 (+ epsilon, - epsilon),其中 epsilon 是一个正值,它小于任何其他正数,但大于 0; and infinite ones (+ infinity, - infinity).和无穷大(+无穷大,-无穷大)。

You could define epsilon = +0 , and -epsilon = -0 .您可以定义epsilon = +0-epsilon = -0

While 1/0 is still undefined, 1/epsilon = 1/+0 is +infinity , and 1/-epsilon = -infinity .虽然1/0仍未定义,但1/epsilon = 1/+0+infinity ,而1/-epsilon = -infinity It is nothing more than taking limits of 1/x as x aproaches 0 from the right (+) or from the left (-).x从右边 (+) 或从左边 (-) 趋近0 ,它只不过是取1/x极限。

As 0 and +0 behave differently, it makes sense that 0 != +0 .由于0+0行为不同,因此0 != +0是有道理的。

For symmetry, because unary minus is an operator, unary plus must be too.对于对称,因为一元减号是一个运算符,所以一元加号也必须是。 In most arithmetic situations, it doesn't do anything, but keep in mind that users can define arbitrary classes and use these operators for anything they want, even if it isn't strictly algebraic.在大多数算术情况下,它不做任何事情,但请记住,用户可以定义任意类并将这些运算符用于他们想要的任何东西,即使它不是严格的代数。

I know it's an old thread, but I wanted to extend the existing answers to provide a broader set of examples:我知道这是一个旧线程,但我想扩展现有答案以提供更广泛的示例:

  • + could assert for positivity and throw exception if it's not - very useful to detect corner cases. +可以断言肯定性,如果不是,则抛出异常 - 对于检测极端情况非常有用。
  • The object may be multivalued (think ±sqrt(z) as a single object -- for solving quadratic equations, for multibranched analytical functions, anything where you can "collapse" a twovalued function into one branch with a sign. This includes the ±0 case mentioned by vlopez.该对象可能是多值的(将±sqrt(z)视为单个对象——用于求解二次方程、多分支分析函数、任何可以将双值函数“折叠”为带有符号的分支的任何东西。这包括 ±0 vlopez 提到的案例。
  • If you do lazy evaluation, this may create a function object that adds something to whatever it is applied to something else.如果您进行惰性求值,这可能会创建一个函数对象,将某些内容添加到应用于其他内容的任何内容中。 For instance, if you are parsing arithmetics incrementally.例如,如果您以增量方式解析算术。
  • As an identity function to pass as an argument to some functional.作为身份函数作为参数传递给某些函数。
  • For algebraic structures where sign accumulates -- ladder operators and such.对于符号累积的代数结构——梯形运算符等。 Sure, it could be done with other functions, but one could conceivably see something like y=+++---+++x .当然,它可以用其他函数来完成,但可以想象看到像y=+++---+++x这样的东西。 Even more, they don't have to commute.更重要的是,他们不必通勤。 This constructs a free group of plus and minuses which could be useful.这构建了一组可能有用的免费加号和减号。 Even in formal grammar implementations.即使在正式的语法实现中。
  • Wild usage: it could "mark" a step in the calculation as "active" in some sense.疯狂用法:它可以在某种意义上将计算中的一个步骤“标记”为“活动”。 reap/sow system -- every plus remembers the value and at the end, you can gather the collected intermediates... because why not?收割/播种系统——每一个加号都会记住价值,最后,你可以收集收集到的中间体......因为为什么不呢?

That, plus all the typecasting reasons mentioned by others.那,加上其他人提到的所有类型转换原因。

And after all... it's nice to have one more operator in case you need it.毕竟……如果您需要的话,再多一个操作员就好了。

A lot of examples here look more like bugs.这里的很多例子看起来更像是错误。 This one is actually a feature, though:不过,这实际上是一个功能:

The + operator implies a copy . +运算符意味着一个副本

This is extremely useful when writing generic code for scalars and arrays.这在为标量和数组编写通用代码时非常有用。

For example:例如:

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

This function works on both scalars and NumPy arrays without making extra copies and without changing the type of the object and without requiring any external dependencies!此功能上标量NumPy的阵列工作未做额外的副本并没有改变对象的类型,无需任何外部依赖!

If you used numpy.positive or something like that, you would introduce a NumPy dependency, and you would force numbers to NumPy types, which can be undesired by the caller.如果您使用numpy.positive或类似的东西,您将引入 NumPy 依赖项,并且您将强制数字为 NumPy 类型,这可能是调用者不希望的。

If you did z = x + y , your result would no longer necessarily be the same type as x .如果你做了z = x + y ,你的结果将不再一定是与x相同的类型。 In many cases that's fine, but when it's not, it's not an option.在许多情况下这很好,但如果不是,则不是一种选择。

If you did z = --x , you would create an unnecessary copy, which is slow.如果你做了z = --x ,你会创建一个不必要的副本,这很慢。

If you did z = 1 * x , you'd perform an unnecessary multiplication, which is also slow.如果你做了z = 1 * x ,你会执行一个不必要的乘法,这也很慢。

If you did copy.copy ... I guess that'd work, but it's pretty cumbersome.如果你做了copy.copy ......我想那会起作用,但它很麻烦。

Unary + is a really great option for this. Unary +是一个非常好的选择。

__pos__() exists in Python to give programmers similar possibilities as in C++ language — to overload operators , in this case the unary operator + . __pos__()存在于Python 中,为程序员提供与C++语言类似的可能性——重载运算符,在这种情况下是一元运算符+

( Overloading operators means give them a different meaning for different objects , eg binary + behaves differently for numbers and for strings — numbers are added while strings are concatenated .) 重载运算符意味着为不同的对象赋予它们不同的含义,例如二进制+数字字符串的行为不同——在连接字符串时添加数字。)

Objects may implement (beside others) these emulating numeric types functions (methods):对象可以实现(除其他之外)这些模拟数字类型的函数(方法):

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

So +object means the same as object.__pos__() — they are interchangeable.所以+objectobject.__pos__()意思相同——它们可以互换。

However, +object is more easy on the eye.然而, +object更容易被人看到。

Creator of a particular object has free hands to implement these functions as he wants — as other people showed in their real world's examples.特定对象的创建者可以自由地按照自己的意愿实现这些功能——正如其他人在他们现实世界的例子中所展示的那样。

And my contribution — as a joke: ++i != +i in C/C++ .还有我的贡献——开个玩笑: ++i != +i in C/C++

Unary + is actually the fastest way to see if a value is numeric or not (and raise an exception if it isn't)!一元+实际上是查看值是否为数字的最快方法(如果不是则引发异常)! It's a single instruction in bytecode, where something like isinstance(i, int) actually looks up and calls the isinstance function!它是字节码中的一条指令,其中诸如 isinstance(i, int) 之类的东西实际上查找并调用了isinstance函数!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM