| 1 |
from timeit import Timer |
|---|
| 2 |
|
|---|
| 3 |
# A control model |
|---|
| 4 |
setup_a = ''' |
|---|
| 5 |
class Model(object): |
|---|
| 6 |
pass |
|---|
| 7 |
m = Model() |
|---|
| 8 |
''' |
|---|
| 9 |
|
|---|
| 10 |
# A model which has a __setattr__ which does nothing |
|---|
| 11 |
setup_b = ''' |
|---|
| 12 |
class Model(object): |
|---|
| 13 |
def __setattr__(self, name, value): |
|---|
| 14 |
super(Model, self).__setattr__(name, value) |
|---|
| 15 |
m = Model() |
|---|
| 16 |
''' |
|---|
| 17 |
|
|---|
| 18 |
# A model which has a __setattr__ which matches this patch |
|---|
| 19 |
setup_c = ''' |
|---|
| 20 |
class Model(object): |
|---|
| 21 |
def __setattr__(self, name, value): |
|---|
| 22 |
if name != '_modified_attrs' and (not hasattr(self, name) or |
|---|
| 23 |
value != getattr(self, name)): |
|---|
| 24 |
if hasattr(self, '_modified_attrs'): |
|---|
| 25 |
if name not in self._modified_attrs: |
|---|
| 26 |
self._modified_attrs.add(name) |
|---|
| 27 |
else: |
|---|
| 28 |
self._modified_attrs = set((name,)) |
|---|
| 29 |
super(Model, self).__setattr__(name, value) |
|---|
| 30 |
m = Model() |
|---|
| 31 |
''' |
|---|
| 32 |
|
|---|
| 33 |
# Optimized for speed, and dropped the value check as Brian suggested |
|---|
| 34 |
setup_d = ''' |
|---|
| 35 |
class Model(object): |
|---|
| 36 |
def __setattr__(self, name, value): |
|---|
| 37 |
try: |
|---|
| 38 |
if name not in self._modified_attrs: |
|---|
| 39 |
self._modified_attrs.add(name) |
|---|
| 40 |
except AttributeError: |
|---|
| 41 |
if name != '_modified_attrs': |
|---|
| 42 |
self._modified_attrs = set((name,)) |
|---|
| 43 |
super(Model, self).__setattr__(name, value) |
|---|
| 44 |
m = Model() |
|---|
| 45 |
''' |
|---|
| 46 |
|
|---|
| 47 |
# A model which has uses properties to track changes |
|---|
| 48 |
# Bonus: only field access would be tracked this way |
|---|
| 49 |
setup_e = ''' |
|---|
| 50 |
def track_property(klass, name): |
|---|
| 51 |
p = '_p_%s' % name |
|---|
| 52 |
def fget(o): |
|---|
| 53 |
getattr(o, p) |
|---|
| 54 |
def fset(o, value): |
|---|
| 55 |
set_modified(o) |
|---|
| 56 |
setattr(o, p, value) |
|---|
| 57 |
def set_modified(o): |
|---|
| 58 |
try: |
|---|
| 59 |
if name not in o._modified_attrs: |
|---|
| 60 |
o._modified_attrs.add(name) |
|---|
| 61 |
except AttributeError: |
|---|
| 62 |
o._modified_attrs = set((name,)) |
|---|
| 63 |
setattr(klass, name, property(fget, fset)) |
|---|
| 64 |
class Model(object): |
|---|
| 65 |
def __init__(self): |
|---|
| 66 |
track_property(self.__class__, 'an_attribute') |
|---|
| 67 |
track_property(self.__class__, 'another_attribute') |
|---|
| 68 |
m = Model() |
|---|
| 69 |
''' |
|---|
| 70 |
|
|---|
| 71 |
setup_a1 = setup_a + ''' |
|---|
| 72 |
m.another_attribute="test" |
|---|
| 73 |
''' |
|---|
| 74 |
|
|---|
| 75 |
setup_b1 = setup_b + ''' |
|---|
| 76 |
m.another_attribute="test" |
|---|
| 77 |
''' |
|---|
| 78 |
|
|---|
| 79 |
setup_c1 = setup_c + ''' |
|---|
| 80 |
m.another_attribute="test" |
|---|
| 81 |
''' |
|---|
| 82 |
|
|---|
| 83 |
setup_d1 = setup_d + ''' |
|---|
| 84 |
m.another_attribute="test" |
|---|
| 85 |
''' |
|---|
| 86 |
|
|---|
| 87 |
setup_e1 = setup_e + ''' |
|---|
| 88 |
m.another_attribute="test" |
|---|
| 89 |
''' |
|---|
| 90 |
|
|---|
| 91 |
def timed(t, control=None): |
|---|
| 92 |
if control is None: |
|---|
| 93 |
return '%.3f' % (t) |
|---|
| 94 |
return '%.3f (%.1fx)' % (t, t/control) |
|---|
| 95 |
|
|---|
| 96 |
print "Single Assignment" |
|---|
| 97 |
test = 'm.an_attribute="test"' |
|---|
| 98 |
control = Timer(test, setup_a).timeit() |
|---|
| 99 |
print "Control: ", timed(control) |
|---|
| 100 |
print "noop: ", timed(Timer(test, setup_b).timeit(), control) |
|---|
| 101 |
print "patch: ", timed(Timer(test, setup_c).timeit(), control) |
|---|
| 102 |
print "optimized:", timed(Timer(test, setup_d).timeit(), control) |
|---|
| 103 |
print "property: ", timed(Timer(test, setup_e).timeit(), control) |
|---|
| 104 |
print |
|---|
| 105 |
print "Double Assignment" |
|---|
| 106 |
test = 'm.an_attribute="test";m.another_attribute="test"' |
|---|
| 107 |
control = Timer(test, setup_a).timeit() |
|---|
| 108 |
print "Control: ", timed(control) |
|---|
| 109 |
print "noop: ", timed(Timer(test, setup_b).timeit(), control) |
|---|
| 110 |
print "patch: ", timed(Timer(test, setup_c).timeit(), control) |
|---|
| 111 |
print "optimized:", timed(Timer(test, setup_d).timeit(), control) |
|---|
| 112 |
print "property: ", timed(Timer(test, setup_e).timeit(), control) |
|---|