Compile time evaluation of dictionaries

Terry Reedy tjreedy at udel.edu
Thu Mar 10 17:40:40 EST 2011


On 3/10/2011 11:23 AM, Gerald Britton wrote:
> Today I noticed that an expression like this:
>
> "one:%(one)s two:%(two)s" % {"one": "is the loneliest number", "two":
> "can be as bad as one"}
>
> could be evaluated at compile time, but is not:

In fact, it could be evaluated at writing time ;-).
This would be an example of constant folding, except that a dict is not, 
in itself, a constant.

>>>> dis(compile(
> ... '"one:%(one)s two:%(two)s" % {"one": "is the loneliest number",
> "two": "can be as bad as one"}',
> ... '','exec'))
>   1           0 LOAD_CONST               0 ('one:%(one)s two:%(two)s')
>               3 BUILD_MAP                2
>               6 LOAD_CONST               1 ('is the loneliest number')
>               9 LOAD_CONST               2 ('one')
>              12 STORE_MAP
>              13 LOAD_CONST               3 ('can be as bad as one')
>              16 LOAD_CONST               4 ('two')
>              19 STORE_MAP
>              20 BINARY_MODULO
>              21 POP_TOP
>              22 LOAD_CONST               5 (None)
>              25 RETURN_VALUE
>>>>
>
> Any idea why Python works this way?

Because that is how the language is defined.

>  I see that, in 3.2, an
> optimization was done for sets (See "Optimizations" at
> http://docs.python.org/py3k/whatsnew/3.2.html) though I do not see
> anything similar for dictionaries.

I presume you mean this:

"Python’s peephole optimizer now recognizes patterns such x in {1, 2, 3} 
as being a test for membership in a set of constants. The optimizer 
recasts the set as a frozenset and stores the pre-built constant.

Now that the speed penalty is gone, it is practical to start writing 
membership tests using set-notation. This style is both semantically 
clear and operationally fast:

extension = name.rpartition('.')[2]
if extension in {'xml', 'html', 'xhtml', 'css'}:
     handle(name)

(Patch and additional tests contributed by Dave Malcolm; issue 6690)."

This is possible because: sets have a frozen counterpart, and cpython 
*sometimes* follows an 'as if' rule for optimizations. There is no 
frozendict, so the same pattern could not be followed.

Note first that the optimization is *not* an example of constant 
folding, but recognition that an unbound mutable cannot be mutated, and 
therefore, if all its contents are fixed, can be 'cast' to constant form 
at compile time.

Note second that the optimization does not apply to all such set 
instances, but only to this particular 'in' context. It follows a 
similar optimization for turning lists into tuples (although in this 
latter case, the programmer could have remembered to use () instead of []).

The optimization *did* happen because various people started an issue, 
wrote a patch, reviewed the patch, and committed it to the cpython 
source. You might read the issue if you have not:

http://bugs.python.org/issue6690

Terry Jan Reedy





More information about the Python-list mailing list