Explanation of this Python language feature? [x for x in x for x in x] (to flatten a nested list)

Chris Angelico rosuav at gmail.com
Fri Apr 4 04:11:40 EDT 2014


On Fri, Apr 4, 2014 at 6:52 PM, Steven D'Aprano
<steve+comp.lang.python at pearwood.info> wrote:
> py> x = Decimal("0.7777777777787516")
> py> y = Decimal("0.7777777777787518")
> py> (x + y) / 2
> Decimal('0.7777777777787515')
>
> I've changed my mind about Python using Decimal as the default numeric
> type. I think that would send a very strong message that Python is not
> for serious numeric work.

Hmm. Good point. (I'm not familiar with your notation, by the way;
assuming x...y includes both endpoints? The first thing that comes to
mind is git's revision syntax, in which x and y would be
tags/commits/branches and that would give you everything that's in
those branches but not in their common parent. And I doubt very much
that's what you mean!) So I go back to a previous form of the
request/desire: that the AST store numeric literals as their original
strings (maybe as well as the parsed version), such that an AST
transform can replace all float literals with Decimal literals (if
they exist, or calls to Decimal and string args if they don't).

>>> print(ast.dump(ast.parse("print(0.1 + 0.2)")))
Module(body=[Expr(value=Call(func=Name(id='print', ctx=Load()),
args=[BinOp(left=Num(n=0.1), op=Add(), right=Num(n=0.2))],
keywords=[], starargs=None, kwargs=None))])

Possibly the easiest way - and maybe I should shift this part of the
discussion to -ideas - would be to have Num nodes retain additional
meta-information, in the same way that nodes retain line/column info.
Then it would be relatively simple to write a "Decimal-mode" hook for
IDLE that would turn it into a Decimal calculator instead of a binary
float calculator. Adding Decimal as a supported type (which would have
to happen if Python gets Decimal literals, but could be done in other
ways too) would help, though it's not strictly necessary.

>>> mod=ast.parse("print(0.1 + 0.2)")
>>> exec(compile(mod,"-","exec"))
0.30000000000000004

>>> mod.body[0].value.args[0].left.n=Decimal("0.1")
>>> mod.body[0].value.args[0].right.n=Decimal("0.2")
>>> exec(compile(mod,"-","exec"))
Traceback (most recent call last):
  File "<pyshell#28>", line 1, in <module>
    exec(compile(mod,"-","exec"))
TypeError: non-numeric type in Num

But it can still be done, as long as it's possible to go back to the
original string - which currently it's not, short of parsing the
entire Python program manually.

ChrisA



More information about the Python-list mailing list