Home > database >  Contiguous operators in Python raises no error
Contiguous operators in Python raises no error

Time:07-02

Accidentally, I typed multiple contiguous operators and it ran successfully. This is what I did

2    3 // returns 5

Then i tried multiple combinations and it actually executes only the last operator

2    -3 // returns -1

This is somewhat strange to me. Shouldn't it just raise syntax error. Any details or related information will be helpful. Why did they choose to be it like that?

I am running Python3.10.4. Might have different behavior on other versions. I know its not a pure programming problem but it do related to system design. What was the intention or need to do this?

CodePudding user response:

The unhelpful answer is that it's not a SyntaxError, because it's valid syntax.

Both and - are used for binary and unary operators, and once they're resolved, in your example to constants, the next unary conversion is applied until there's nothing (or, just the binary operation) remaining.

You can see how python interprets it by using the astroid library to parse it and see what the resulting operation tree looks like:

In [97]: x = astroid.parse('3   3')

In [98]: print(x.body[0].repr_tree())
Expr(value=BinOp(
      op=' ',
      left=Const(
         value=3,
         kind=None),
      right=UnaryOp(
         op=' ',
         operand=UnaryOp(
            op=' ',
            operand=Const(
               value=3,
               kind=None)))))

So, 3 is just 3. [that] 3 = 3 (again). Then the final 3 3 is a binary addition.

Of course, you could try to "fix" this, with some sort of notion along the lines of:

n [122]: class Int(int):
     ...:     def __neg__(self):
     ...:         return NegatedInt(super().__neg__())
     ...:     def __pos__(self):
     ...:         return PosInt(super().__pos__())
     ...: class PosInt(Int):
     ...:     def __pos__(self):
     ...:         raise ValueError('no excessive positivity')
     ...:     def __repr__(self):
     ...:         return f'P{int(self)}'
     ...: class NegatedInt(Int):
     ...:     def __neg__(self):
     ...:         raise ValueError('no double negation!')
     ...:     def __repr__(self):
     ...:         return f'N{int(self)}'
     ...:
     ...: val = Int(3)
     ...: (val, -val,  val)
Out[122]: (3, N-3, P3)

In [123]: --val
ValueError: no double negation!


In [124]:   val
ValueError: no excessive positivity


In [125]:  - - -val
Out[125]: P-3

can't honestly say it's a good idea though.

CodePudding user response:

What's happening here is that you have chosen a set of operators that work in both binary and unary use cases. The first operator in the sequence is taken as the binary operator and the rest are taken as unary operators on the right operand. The extra operators are essentially just multiplying the right operand by 1 or -1.

# Positive 3 - like multiplying by  1
 3
# Negative 3 - like multiplying by -1
-3

The below code boils down to 2 (positive 3)

2    3 # Equivalent to 2   ( 3)

The example after that boils down to 2 ( ( (-3))). Which is just 2-3 = -1

2    -3 # Equivalent to 2   ( ( (-3)))

Notice when you do something like this with * because it is taken as a unary operator and * does not actually have an unary application, you get a syntax error:

2  *- 3 # Equivalent to 2   (*(-3))) which makes no sense to the interpreter, what's (*3)?

But this would be okay:

2* -3 # Equivalent to 2 * ( (-3))

because here * is first so it is taken as the binary operator. The expression boils down to 2 * ( (-3))) or 2 * (-3) = -6

  • Related