Skip to content

Instantly share code, notes, and snippets.

@kwikwag
Last active January 17, 2020 21:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kwikwag/1dc6ecf2688bb03cd4c062a654d0bad3 to your computer and use it in GitHub Desktop.
Save kwikwag/1dc6ecf2688bb03cd4c062a654d0bad3 to your computer and use it in GitHub Desktop.
import timeit
from math import pow
import sys
# Python 2/3 compatible
# note : alternative versions of this file had pow(x,0.33) replaced with
# sqrt(x) or max(x,33,1,2,3,4,5,6,6,7,8,9) to see the effect of the
# number of arguments on run times.
class CallMe:
def __init__(self, context):
self.context = context
def __call__(self, *args, **kwargs):
return self.context(*args, **kwargs)
def call_me(func):
return lambda *args, **kwargs: func(*args, **kwargs)
print('Closure:')
print(timeit.timeit('[call_me(pow)(n,0.33) for n in range(2000)]', number=2000, setup='from math import pow; from __main__ import call_me'))
print('Class:')
print(timeit.timeit('[CallMe(pow)(n,0.33) for n in range(2000)]', number=2000, setup='from math import pow; from __main__ import CallMe'))
print('Bare call:')
print(timeit.timeit('[pow(n,0.33) for n in range(2000)]', number=2000, setup='from math import pow; from __main__ import CallMe'))
print(timeit.timeit('[pow(n,0.33) for n in range(2000)]', number=2000, setup='from math import pow; from __main__ import call_me'))
closu_call = call_me(pow)
class_call = CallMe(pow)
print(closu_call(77,0.33))
print(class_call(77,0.33))
print(pow(77,0.33))
assert(closu_call(77,0.33) == class_call(77,0.33))
assert(closu_call(77,0.33) == pow(77,0.33))
print('Closure (prebuilt):')
print(timeit.timeit('[a(n,0.33) for n in range(2000)]', number=2000, setup='from math import pow; from __main__ import closu_call as a'))
print('Class (prebuilt):')
print(timeit.timeit('[a(n,0.33) for n in range(2000)]', number=2000, setup='from math import pow; from __main__ import class_call as a'))
print('Bare call:')
print(timeit.timeit('[pow(n,0.33) for n in range(2000)]', number=2000, setup='from math import pow; from __main__ import closu_call as a'))
print(timeit.timeit('[pow(n,0.33) for n in range(2000)]', number=2000, setup='from math import pow; from __main__ import class_call as a'))
try: # guppy wasn't able to install for Python 3
from guppy import hpy
n = 1000000
h = hpy()
print("Heap size before:")
print(h.heap().size)
print("Constructing many")
if len(sys.argv) > 1 and sys.argv[1] == '1':
print("...closures")
results = [ call_me(pow) for i in range(n) ]
else:
print("...callable classes")
results = [ CallMe(pow) for i in range(n) ]
h = hpy()
print("Heap size after:")
print(h.heap().size)
print(sum([ results[i](77,0.33) for i in range(n) ]))
except Exception as e:
print("Skipping heap size test because of exception: " + str(e))
pass
@cl0ne
Copy link

cl0ne commented Jan 17, 2020

N.B. For python3 during installation of guppy you will be notified:

    setup.py: Error: This guppy package only supports Python2.                                                                                                
    You can find the recommended Python3 version here:                                                                                                        
    https://github.com/zhuyifei1999/guppy3  

And in Python 3.8.1 I got the following heap measurements: 232695531 for closures and 160695531 for callable classes. Callable classes used 30% less memory :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment