I recently tweeted about int('--1')
raising an exception, as I was curious whether people would be surprised by this or not.
Turns out that people are happy with this, but it got me thinking a little bit about the CPython interpreter and its underlying grammar.
A quick glance of the AST (Abstract Syntax Tree) produced by the expression --1
shows that Python's grammar does not actually produce negative numbers:
import ast
formatters = {ast.USub: '-', ast.Num: '{n.n}'}
def render(node):
chldn = map(render, ast.iter_child_nodes(node))
default_fmt = f'{type(node).__name__}({", ".join(chldn)})'
fmt = formatters.get(type(node), default_fmt)
return fmt.format(n=node, c=chldn)
print(render(ast.parse('--1')))
Module(Expr(UnaryOp(-, UnaryOp(-, 1))))
I think this is a perfectly reasonable thing to do, else there would need to be some special cases when we have an expression such as a-1
- the tokenizer could easily end up seeing this as <VARIABLE><LITERAL>
, and we know that such constructs aren't allowed in the python language.
For those that are interested, the negative numbers are produced in the AST opmisation step found at https://github.com/python/cpython/blob/v3.7.2/Python/ast_opt.c#L122 (for CPython 3.7.2 anyway).