| '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__)) |