On 10/2/2013 10:34 PM, Steven D'Aprano wrote:

You are both assuming that LOAD_CONST will re-use the same tuple
(1, 2, 3) in multiple places.

No I did not. To save tuple creation time, a pre-compiled tuple is reused when its display expression is re-executed. If I had been interested in multiple occurrences of the same display, I would have tested.

>>> def f():
        a = 1,'a',3333, 'bbb'; x = 1,'a',3333, 'bbb'
        b = 1,'a',3333, 'bbb'
        c = 'a'
        d = 3333 + 3333
        
>>> f.__code__.co_consts
(None, 1, 'a', 3333, 'bbb', (1, 'a', 3333, 'bbb'), (1, 'a', 3333, 'bbb'), (1, 'a', 3333, 'bbb'), 6666)

Empirically, ints and strings are checked for prior occurrence in co_consts before being added. I suspect None is too, but will not assume.

How is the issue of multiple occurrences of constants relevant to my topic statement? Let me quote it, with misspellings corrected.

"CPython core developers have been very conservative about what
transformations they put into the compiler." [misspellings corrected]

Aha! Your example and that above reinforce this statement. Equal tuples are not necessarily identical and cannot necessarily be substituted for each other in all code.

>>> (1, 2) == (1.0, 2.0)
True

But replacing (1.0, 2.0) with (1, 2), by only storing the latter, would not be valid without some possibly tricky context analysis. The same is true for equal numbers, and the optimizer pays attention.

>>> def g():
        a = 1
        b = 1.0

>>> g.__code__.co_consts
(None, 1, 1.0)

For numbers, the proper check is relatively easy:

for item in const_list:
  if type(x) is type(item) and x == item:
    break  # identical item already in working list
else:
  const_list.append(x)

Writing a valid recursive function to do the same for tuples, and proving its validity to enough other core developers to make it accepted, is much harder and hardly seems worthwhile.

It would probably be easier to compare the parsed AST subtrees for the displays rather than the objects created from them.

---
> py> def f():
> ...     a = (1, 2, 3)
> ...     b = (1, 2, 3)
[snip]
> So even though both a and b are created by the same LOAD_CONST byte-code,

I am not sure what you mean by 'created'. LOAD_CONST puts the address of an object in co_consts on the top of the virtual machine stack.

> the object is not re-used (although it could be!)

It can be reused, in this case, because the constant displays are identical, as defined above.

> and two distinct tuples are created.

Because it is not easy to make the compiler see that only one is needed.

--
Terry Jan Reedy

--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to