Multiple Unary Operations in Python

Question:

I made a typo in one script while using a SQL like comment instead of a Python comment, which lead to expression

-- sys.exit()

I took me a while to realize that the exit works and the program stops.

The most probable explanation is that the - is considered as an unary operator and that multiple such operators are allowed.

The test case of

x = -----------1

which evaluates to -1 supports it.

Unfortunately I was not able to find the relevant syntax.

The UNARY_NEGATIVE describes byte code, not the Python syntax.

Is my interpretation correct?

Asked By: Marmite Bomber

||

Answers:

Yes, one relevant part of the specification is 6.6. Unary arithmetic and bitwise operations, which shows:

u_expr ::=  power | "-" u_expr | "+" u_expr | "~" u_expr

This means that multiple unary negations can follow each other, but by itself that only means that something like - - - -x is valid (with spaces). To prove that ----x is valid, another fact about Python is needed: unlike in many other languages, in Python -- is not a token. So --x can only be interpreted as -(-x), not as -- x where -- has its own meaning distinct from two negations. There isn’t really anywhere in particular in the spec that positively says that -- is not token, it’s a fact by omission, eg you can check the full grammar for mentions of -- and confirm that it isn’t there.

Answered By: harold

What is happening is that the unary expression will only raise an error once they have determined that the data type they are decorating is an invalid type at which point it will raise a TypeError. However in order for it to determine the data type it needs to evaluate the rest of the expression, which in your case is sys.exit() which raises its exception and exits the program, thus never giving the unary expression a chance to raise the TypeError

This can be demonstrated by creating a function the throws a generic expression and performing and testing it with any of the unary operators, since they all have the same priority level.

This is an example of the TypeError typically associated with invalid unary expresions:

>>> ++++ "1"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: bad operand type for unary +: 'str'

Then with a function that raises an generic Exception

>>> def example():
...     raise Exception("This is not a TypeError")
...
>>> ++++ example()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in example
Exception: This is not a TypeError

In your example you never get to see the error message because it immediately exits the program.

Answered By: Alexander
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.