Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are constant computations cached in Python?

Tags:

python

Say I have a function in Python that uses a constant computed float value like 1/3.

def div_by_3(x):
    return x * (1/3)

If I call the function repeatedly, will the value of 1/3 be automatically cached for efficiency? Or do I have to do something manually such as the following?

def div_by_3(x, _ONE_THIRD=1/3):
    return x * _ONE_THIRD
like image 519
aiai Avatar asked Oct 07 '15 19:10

aiai


People also ask

Does Python automatically cache?

No, it's not. The call will be done twice. So, there's room for optimizing the code. – Klaus D.

What is caching in Python?

Caching is an optimization technique that you can use in your applications to keep recent or often-used data in memory locations that are faster or computationally cheaper to access than their source. Imagine you're building a newsreader application that fetches the latest news from different sources.


1 Answers

Find out for yourself! The dis module is great for inspecting this sort of stuff:

>>> from dis import dis
>>> def div_by_3(x):
...     return x * (1/3.)
... 
>>> dis(div_by_3)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               1 (1)
              6 LOAD_CONST               2 (3.0)
              9 BINARY_DIVIDE       
             10 BINARY_MULTIPLY     
             11 RETURN_VALUE        

As you can see, the 1/3 calculation happens every time. (Note: I changed 3 to 3. to force float division, otherwise it'd just be 0. You can also enable future-division, which actually changed the behavior, see edit section below).

And your second approach:

>>> def db3(x, _ONE_THIRD=1/3.):
...   return x * _ONE_THIRD
... 
>>> dis(db3)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_FAST                1 (_ONE_THIRD)
              6 BINARY_MULTIPLY     
              7 RETURN_VALUE        

More information on the second can be found by inspecting the function object:

>>> inspect.getargspec(db3)
ArgSpec(args=['x', '_ONE_THIRD'], varargs=None, keywords=None, defaults=(0.3333333333333333,))

You can see the default value is cached in there.

EDIT: Turns out this is a little more interesting -- in Python 3 they do get cached (and also in Python 2.7 when you enable from __future__ import division):

>>> dis.dis(div_by_3)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               3 (0.3333333333333333)
              6 BINARY_MULTIPLY
              7 RETURN_VALUE

Switching to integer division (//) in either Python 3 or 2.7-with-future-division doesn't change this, it just alters the constant to be a 0 instead of 0.333.. Also, using integer division directly in 2.7 without future-division will cache the 0 as well.

Learned something new today!

like image 136
tzaman Avatar answered Oct 13 '22 23:10

tzaman