What are the specific rules for constant folding?

2024/10/8 12:32:16

I just realized that CPython seems to treat constant expressions, which represent the same value, differently with respect to constant folding. For example:

>>> import dis
>>> dis.dis('2**66')1           0 LOAD_CONST               0 (2)2 LOAD_CONST               1 (66)4 BINARY_POWER6 RETURN_VALUE
>>> dis.dis('4**33')1           0 LOAD_CONST               2 (73786976294838206464)2 RETURN_VALUE

For the second example constant folding is applied while for the first it is not though both represent the same value. It doesn't seem to be related to the value of the exponent nor to the magnitude of the result since the following expressions are folded as well:

>>> dis.dis('2.0**66')1           0 LOAD_CONST               2 (7.378697629483821e+19)2 RETURN_VALUE
>>> dis.dis('4**42')1           0 LOAD_CONST               2 (19342813113834066795298816)2 RETURN_VALUE

Why are the first two expressions treated differently and, more generally, what are the specific rules that CPython follows for constant folding?


Tested on:

$ python3.6 --version
Python 3.6.5 :: Anaconda, Inc.
$ python3.7 --version
Python 3.7.1
Answer

There are no rules for constant folding. There are only implementation details. They have changed before, and they will change again.

Heck, you can't even talk about the "Python 3 behavior", or the "Python 3.6 behavior", because these implementation details changed between 3.6.4 and 3.6.5. On 3.6.4, the 2**66 example gets constant-folded.

For now, and no one knows how long "for now" will last, the implementation details are that the AST optimizer includes safeguards to prevent spending too much time or memory on constant folding. The safeguard for 2**66 or 4**33 is based on the number of bits in the LHS and the value of the RHS:

if (PyLong_Check(v) && PyLong_Check(w) && Py_SIZE(v) && Py_SIZE(w) > 0) {size_t vbits = _PyLong_NumBits(v);size_t wbits = PyLong_AsSize_t(w);if (vbits == (size_t)-1 || wbits == (size_t)-1) {return NULL;}if (vbits > MAX_INT_SIZE / wbits) {return NULL;}
}

MAX_INT_SIZE is #defined earlier as 128. Since 2 is a 2-bit number and 4 is a 3-bit number, the estimated result size is smaller for 4**33, so it passes the check and gets constant-folded.

On Python 3.6.5, the implementation details are mostly similar, but this constant folding happens in the bytecode peephole optimizer instead of the AST optimizer, which doesn't exist on 3.6.5.

On Python 3.6.4, the pre-check safeguard doesn't exist. The peephole optimizer will discard too-large constant-folding results after computing them, which results in different thresholds than the pre-checks.

https://en.xdnf.cn/q/70124.html

Related Q&A

installing opencv for python on mavericks

I am trying to install opencv on a Macbook Pro late 2013 with mavericks. I didnt find any binaries so I am trying to build it. I tried http://www.guidefreitas.com/installing-opencv-2-4-2-on-mac-osx-mou…

Python 3 reading CSV file with line breaks in rows

I have a large CSV file with one column and line breaks in some of its rows. I want to read the content of each cell and write it to a text file but the CSV reader is splitting the cells with line brea…

Python appending dictionary, TypeError: unhashable type?

abc = {} abc[int: anotherint]Then the error came up. TypeError: unhashable type? Why I received this? Ive tried str()

Calling C# code within Python3.6

with absolutely no knowledge of coding in C#, I wish to call a C# function within my python code. I know theres quite a lot of Q&As around the same problem, but for some strange reason, im unable t…

Pycharm 3.4.1 - AppRegistryNotReady: Models arent loaded yet. Django Rest framewrok

Im using DRF and Pycharm 3.4.1 and Django 1.7. When I try to test my serializer class via Pycharm django console, it gives me the following error:Codefrom items_app.serializers import ItemSerializer s …

Pass Flask route parameters into a decorator

I have written a decorator that attempts to check we have post data for a Flask POST route:Heres my decorator:def require_post_data(required_fields=None):def decorator(f):@wraps(f)def decorated_functio…

update env variable on notebook in VsCode

I’m working on a python project with a notebook and .env file on VsCode. I have problem when trying to refresh environment variables in a notebook (I found a way but its super tricky). My project: .en…

How do I properly set up flask-admin views with using an application factory?

Im trying to setup flask-admin model views with SQLAlchemy against user and role models. Instead of a function admin view Im getting:ValueError: Invalid model property name <class app.models.Role>…

Django Rest Framework: Correct way to serialize ListFields

Based on the DRF documentation I have a created a list of email_id stored in my model in the following way Models.pyclass UserData(models.Model):emails = models.CharField(max_length=100,blank=False)In…

Flask-SQLAlchemy TimeoutError

My backend configuration is :Ubuntu 12.04 Python 2.7 Flask 0.9 Flask-SQLAlchemy Postgres 9.2Ive got this error message: TimeoutError: QueuePool limit of size 5 overflow 10 reached, connection timed ou…