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

Question:

Generally speaking, what should the unary + do in 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__().

So I’m wondering: why do + and __pos__() exist? Can you provide a real-world example where the expression above evaluates to True?

Asked By: user16538

||

Answers:

I believe that Python operators where inspired by C, where the + operator was introduced for symmetry (and also some useful hacks, see comments).

In weakly typed languages such as PHP or Javascript, + tells the runtime to coerce the value of the variable into a number. For example, in 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.

It is certainly possible to implement an object for which +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; and infinite ones (+ infinity, – infinity).

You could define epsilon = +0, and -epsilon = -0.

While 1/0 is still undefined, 1/epsilon = 1/+0 is +infinity, and 1/-epsilon = -infinity. It is
nothing more than taking limits of 1/x as x aproaches 0 from the right (+) or from the left (-).

As 0 and +0 behave differently, it makes sense that 0 != +0.

Answered By: vlopez

Here’s a “real-world” example from the decimal package:

>>> 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')
Answered By: Chris Taylor

In Python 3.3 and above, collections.Counter uses the + operator to remove non-positive counts.

>>> 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.

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

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.
  • 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. 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.

Answered By: orion

__pos__() exists in Python to give programmers similar possibilities as in C++ language — to overload operators, in this case the unary operator +.

(Overloading operators means give them a different meaning for different objects, e. g. 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.

However, +object is more easy on the eye.

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++.

Answered By: MarianD

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!

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.

If you did z = x + y, your result would no longer necessarily be the same type as 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.

If you did z = 1 * x, you’d perform an unnecessary multiplication, which is also slow.

If you did copy.copy… I guess that’d work, but it’s pretty cumbersome.

Unary + is a really great option for this.

Answered By: user541686

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!

Answered By: snoopyjc
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.