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

前端 未结 6 1467
日久生厌
日久生厌 2020-11-27 18:04

Generally speaking, what should the unary + do in Python?

I\'m asking because, so far, I have never seen a situation like this:

+obj !=          


        
相关标签:
6条回答
  • 2020-11-27 18:40

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

    0 讨论(0)
  • 2020-11-27 18:45

    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
    
    0 讨论(0)
  • 2020-11-27 18:47

    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.

    0 讨论(0)
  • 2020-11-27 18:56

    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')
    
    0 讨论(0)
  • 2020-11-27 19:02

    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.

    0 讨论(0)
  • 2020-11-27 19:03

    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.

    0 讨论(0)
提交回复
热议问题