| 'Show relative speeds of local, nonlocal, global, and built-in access.' | |
| # Please leave this code so that it runs under older versions of | |
| # Python 3 (no f-strings). That will allow benchmarking for | |
| # cross-version comparisons. To run the benchmark on Python 2, | |
| # comment-out the nonlocal reads and writes. | |
| from collections import deque, namedtuple | |
| trials = [None] * 500 | |
| steps_per_trial = 25 | |
| class A(object): | |
| def m(self): | |
| pass | |
| class B(object): | |
| __slots__ = 'x' | |
| def __init__(self, x): | |
| self.x = x | |
| class C(object): | |
| def __init__(self, x): | |
| self.x = x | |
| def read_local(trials=trials): | |
| v_local = 1 | |
| for t in trials: | |
| v_local; v_local; v_local; v_local; v_local | |
| v_local; v_local; v_local; v_local; v_local | |
| v_local; v_local; v_local; v_local; v_local | |
| v_local; v_local; v_local; v_local; v_local | |
| v_local; v_local; v_local; v_local; v_local | |
| def make_nonlocal_reader(): | |
| v_nonlocal = 1 | |
| def inner(trials=trials): | |
| for t in trials: | |
| v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal | |
| v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal | |
| v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal | |
| v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal | |
| v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal; v_nonlocal | |
| inner.__name__ = 'read_nonlocal' | |
| return inner | |
| read_nonlocal = make_nonlocal_reader() | |
| v_global = 1 | |
| def read_global(trials=trials): | |
| for t in trials: | |
| v_global; v_global; v_global; v_global; v_global | |
| v_global; v_global; v_global; v_global; v_global | |
| v_global; v_global; v_global; v_global; v_global | |
| v_global; v_global; v_global; v_global; v_global | |
| v_global; v_global; v_global; v_global; v_global | |
| def read_builtin(trials=trials): | |
| for t in trials: | |
| oct; oct; oct; oct; oct | |
| oct; oct; oct; oct; oct | |
| oct; oct; oct; oct; oct | |
| oct; oct; oct; oct; oct | |
| oct; oct; oct; oct; oct | |
| def read_classvar_from_class(trials=trials, A=A): | |
| A.x = 1 | |
| for t in trials: | |
| A.x; A.x; A.x; A.x; A.x | |
| A.x; A.x; A.x; A.x; A.x | |
| A.x; A.x; A.x; A.x; A.x | |
| A.x; A.x; A.x; A.x; A.x | |
| A.x; A.x; A.x; A.x; A.x | |
| def read_classvar_from_instance(trials=trials, A=A): | |
| A.x = 1 | |
| a = A() | |
| for t in trials: | |
| a.x; a.x; a.x; a.x; a.x | |
| a.x; a.x; a.x; a.x; a.x | |
| a.x; a.x; a.x; a.x; a.x | |
| a.x; a.x; a.x; a.x; a.x | |
| a.x; a.x; a.x; a.x; a.x | |
| def read_instancevar(trials=trials, a=C(1)): | |
| for t in trials: | |
| a.x; a.x; a.x; a.x; a.x | |
| a.x; a.x; a.x; a.x; a.x | |
| a.x; a.x; a.x; a.x; a.x | |
| a.x; a.x; a.x; a.x; a.x | |
| a.x; a.x; a.x; a.x; a.x | |
| def read_instancevar_slots(trials=trials, a=B(1)): | |
| for t in trials: | |
| a.x; a.x; a.x; a.x; a.x | |
| a.x; a.x; a.x; a.x; a.x | |
| a.x; a.x; a.x; a.x; a.x | |
| a.x; a.x; a.x; a.x; a.x | |
| a.x; a.x; a.x; a.x; a.x | |
| def read_namedtuple(trials=trials, D=namedtuple('D', ['x'])): | |
| a = D(1) | |
| for t in trials: | |
| a.x; a.x; a.x; a.x; a.x | |
| a.x; a.x; a.x; a.x; a.x | |
| a.x; a.x; a.x; a.x; a.x | |
| a.x; a.x; a.x; a.x; a.x | |
| a.x; a.x; a.x; a.x; a.x | |
| def read_boundmethod(trials=trials, a=A()): | |
| for t in trials: | |
| a.m; a.m; a.m; a.m; a.m | |
| a.m; a.m; a.m; a.m; a.m | |
| a.m; a.m; a.m; a.m; a.m | |
| a.m; a.m; a.m; a.m; a.m | |
| a.m; a.m; a.m; a.m; a.m | |
| def write_local(trials=trials): | |
| v_local = 1 | |
| for t in trials: | |
| v_local = 1; v_local = 1; v_local = 1; v_local = 1; v_local = 1 | |
| v_local = 1; v_local = 1; v_local = 1; v_local = 1; v_local = 1 | |
| v_local = 1; v_local = 1; v_local = 1; v_local = 1; v_local = 1 | |
| v_local = 1; v_local = 1; v_local = 1; v_local = 1; v_local = 1 | |
| v_local = 1; v_local = 1; v_local = 1; v_local = 1; v_local = 1 | |
| def make_nonlocal_writer(): | |
| v_nonlocal = 1 | |
| def inner(trials=trials): | |
| nonlocal v_nonlocal | |
| for t in trials: | |
| v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1 | |
| v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1 | |
| v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1 | |
| v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1 | |
| v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1; v_nonlocal = 1 | |
| inner.__name__ = 'write_nonlocal' | |
| return inner | |
| write_nonlocal = make_nonlocal_writer() | |
| def write_global(trials=trials): | |
| global v_global | |
| for t in trials: | |
| v_global = 1; v_global = 1; v_global = 1; v_global = 1; v_global = 1 | |
| v_global = 1; v_global = 1; v_global = 1; v_global = 1; v_global = 1 | |
| v_global = 1; v_global = 1; v_global = 1; v_global = 1; v_global = 1 | |
| v_global = 1; v_global = 1; v_global = 1; v_global = 1; v_global = 1 | |
| v_global = 1; v_global = 1; v_global = 1; v_global = 1; v_global = 1 | |
| def write_classvar(trials=trials, A=A): | |
| for t in trials: | |
| A.x = 1; A.x = 1; A.x = 1; A.x = 1; A.x = 1 | |
| A.x = 1; A.x = 1; A.x = 1; A.x = 1; A.x = 1 | |
| A.x = 1; A.x = 1; A.x = 1; A.x = 1; A.x = 1 | |
| A.x = 1; A.x = 1; A.x = 1; A.x = 1; A.x = 1 | |
| A.x = 1; A.x = 1; A.x = 1; A.x = 1; A.x = 1 | |
| def write_instancevar(trials=trials, a=C(1)): | |
| for t in trials: | |
| a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1 | |
| a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1 | |
| a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1 | |
| a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1 | |
| a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1 | |
| def write_instancevar_slots(trials=trials, a=B(1)): | |
| for t in trials: | |
| a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1 | |
| a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1 | |
| a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1 | |
| a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1 | |
| a.x = 1; a.x = 1; a.x = 1; a.x = 1; a.x = 1 | |
| def read_list(trials=trials, a=[1]): | |
| for t in trials: | |
| a[0]; a[0]; a[0]; a[0]; a[0] | |
| a[0]; a[0]; a[0]; a[0]; a[0] | |
| a[0]; a[0]; a[0]; a[0]; a[0] | |
| a[0]; a[0]; a[0]; a[0]; a[0] | |
| a[0]; a[0]; a[0]; a[0]; a[0] | |
| def read_deque(trials=trials, a=deque([1])): | |
| for t in trials: | |
| a[0]; a[0]; a[0]; a[0]; a[0] | |
| a[0]; a[0]; a[0]; a[0]; a[0] | |
| a[0]; a[0]; a[0]; a[0]; a[0] | |
| a[0]; a[0]; a[0]; a[0]; a[0] | |
| a[0]; a[0]; a[0]; a[0]; a[0] | |
| def read_dict(trials=trials, a={0: 1}): | |
| for t in trials: | |
| a[0]; a[0]; a[0]; a[0]; a[0] | |
| a[0]; a[0]; a[0]; a[0]; a[0] | |
| a[0]; a[0]; a[0]; a[0]; a[0] | |
| a[0]; a[0]; a[0]; a[0]; a[0] | |
| a[0]; a[0]; a[0]; a[0]; a[0] | |
| def read_strdict(trials=trials, a={'key': 1}): | |
| for t in trials: | |
| a['key']; a['key']; a['key']; a['key']; a['key'] | |
| a['key']; a['key']; a['key']; a['key']; a['key'] | |
| a['key']; a['key']; a['key']; a['key']; a['key'] | |
| a['key']; a['key']; a['key']; a['key']; a['key'] | |
| a['key']; a['key']; a['key']; a['key']; a['key'] | |
| def list_append_pop(trials=trials, a=[1]): | |
| ap, pop = a.append, a.pop | |
| for t in trials: | |
| ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop() | |
| ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop() | |
| ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop() | |
| ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop() | |
| ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop() | |
| def deque_append_pop(trials=trials, a=deque([1])): | |
| ap, pop = a.append, a.pop | |
| for t in trials: | |
| ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop() | |
| ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop() | |
| ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop() | |
| ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop() | |
| ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop() | |
| def deque_append_popleft(trials=trials, a=deque([1])): | |
| ap, pop = a.append, a.popleft | |
| for t in trials: | |
| ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); | |
| ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); | |
| ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); | |
| ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); | |
| ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); ap(1); pop(); | |
| def write_list(trials=trials, a=[1]): | |
| for t in trials: | |
| a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 | |
| a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 | |
| a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 | |
| a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 | |
| a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 | |
| def write_deque(trials=trials, a=deque([1])): | |
| for t in trials: | |
| a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 | |
| a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 | |
| a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 | |
| a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 | |
| a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 | |
| def write_dict(trials=trials, a={0: 1}): | |
| for t in trials: | |
| a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 | |
| a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 | |
| a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 | |
| a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 | |
| a[0]=1; a[0]=1; a[0]=1; a[0]=1; a[0]=1 | |
| def write_strdict(trials=trials, a={'key': 1}): | |
| for t in trials: | |
| a['key']=1; a['key']=1; a['key']=1; a['key']=1; a['key']=1 | |
| a['key']=1; a['key']=1; a['key']=1; a['key']=1; a['key']=1 | |
| a['key']=1; a['key']=1; a['key']=1; a['key']=1; a['key']=1 | |
| a['key']=1; a['key']=1; a['key']=1; a['key']=1; a['key']=1 | |
| a['key']=1; a['key']=1; a['key']=1; a['key']=1; a['key']=1 | |
| def loop_overhead(trials=trials): | |
| for t in trials: | |
| pass | |
| if __name__=='__main__': | |
| from timeit import Timer | |
| for f in [ | |
| 'Variable and attribute read access:', | |
| read_local, read_nonlocal, read_global, read_builtin, | |
| read_classvar_from_class, read_classvar_from_instance, | |
| read_instancevar, read_instancevar_slots, | |
| read_namedtuple, read_boundmethod, | |
| '\nVariable and attribute write access:', | |
| write_local, write_nonlocal, write_global, | |
| write_classvar, write_instancevar, write_instancevar_slots, | |
| '\nData structure read access:', | |
| read_list, read_deque, read_dict, read_strdict, | |
| '\nData structure write access:', | |
| write_list, write_deque, write_dict, write_strdict, | |
| '\nStack (or queue) operations:', | |
| list_append_pop, deque_append_pop, deque_append_popleft, | |
| '\nTiming loop overhead:', | |
| loop_overhead]: | |
| if isinstance(f, str): | |
| print(f) | |
| continue | |
| timing = min(Timer(f).repeat(7, 1000)) | |
| timing *= 1000000 / (len(trials) * steps_per_trial) | |
| print('{:6.1f} ns\t{}'.format(timing, f.__name__)) |