Created
January 20, 2019 14:23
-
-
Save pelson/170925c235fbbe55b3b914706b670534 to your computer and use it in GitHub Desktop.
CPython grammar and negative numbers - they only appear after an AST optimisation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"I recently [tweeted](https://twitter.com/pypelson/status/1086869193809633280) about ``int('--1')`` raising an exception, as I was curious whether people would be surprised by this or not.\n", | |
"\n", | |
"Turns out that people *are* happy with this, but it got me thinking a little bit about the CPython interpreter and its underlying grammar.\n", | |
"\n", | |
"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: " | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"Module(Expr(UnaryOp(-, UnaryOp(-, 1))))\n" | |
] | |
} | |
], | |
"source": [ | |
"import ast\n", | |
" \n", | |
"formatters = {ast.USub: '-', ast.Num: '{n.n}'}\n", | |
"\n", | |
"def render(node):\n", | |
" chldn = map(render, ast.iter_child_nodes(node))\n", | |
" default_fmt = f'{type(node).__name__}({\", \".join(chldn)})'\n", | |
" fmt = formatters.get(type(node), default_fmt)\n", | |
" return fmt.format(n=node, c=chldn)\n", | |
"\n", | |
"print(render(ast.parse('--1')))" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"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." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"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)." | |
] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python [default]", | |
"language": "python", | |
"name": "python3" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython3", | |
"version": "3.6.6" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 2 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment