Django

Code

Ticket #4102: 4102-timings.3.py

File 4102-timings.3.py, 4.5 kB (added by SmileyChris, 1 year ago)

"hyper-optimized" method, and showing the downfall of the properties method

Line 
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 setup_b2 = '''
18 class Model(object):
19     def __setattr__(self, name, value):
20         self.__dict__[name] = value
21 m = Model()
22 '''
23
24 # A model which has a __setattr__ which matches this patch
25 setup_c = '''
26 class Model(object):
27     def __setattr__(self, name, value):
28         if name != '_modified_attrs' and (not hasattr(self, name) or
29                                           value != getattr(self, name)):
30             if hasattr(self, '_modified_attrs'):
31                 if name not in self._modified_attrs:
32                     self._modified_attrs.add(name)
33             else:
34                 self._modified_attrs = set((name,))
35         super(Model, self).__setattr__(name, value)
36 m = Model()
37 '''
38
39 # Optimized for speed, and dropped the value check as Brian suggested
40 setup_d = '''
41 class Model(object):
42     def __setattr__(self, name, value):
43         try:
44             if name not in self._modified_attrs:
45                 self._modified_attrs.add(name)
46         except AttributeError:
47             if name != '_modified_attrs':
48                 self._modified_attrs = set((name,))
49         super(Model, self).__setattr__(name, value)
50 m = Model()
51 '''
52
53 # Hyper-optimized
54 setup_h = '''
55 class Model(object):
56     def __init__(self):
57         self._reset_modified_attrs()
58     def _reset_modified_attrs(self):
59         self.__dict__['_modified_attrs'] = []
60     def __setattr__(self, name, value):
61         if name not in self._modified_attrs:
62             self._modified_attrs.append(name)
63         self.__dict__[name] = value
64 m = Model()
65 '''
66
67 # A model which has uses properties to track changes
68 # Bonus: only field access would be tracked this way
69 setup_f = '''
70 def track_property(klass, name):
71     p = '_p_%s' % name
72     def fget(o):
73         getattr(o, p)
74     def fset(o, value):
75         set_modified(o)
76         setattr(o, p, value)
77     def set_modified(o):
78         try:
79             if name not in o._modified_attrs:
80                 o._modified_attrs.add(name)
81         except AttributeError:
82             o._modified_attrs = set((name,))
83     setattr(klass, name, property(fget, fset))
84 class Model(object):
85     def __init__(self):
86         track_property(self.__class__, 'an_attribute')
87         track_property(self.__class__, 'another_attribute')
88 m = Model()
89 '''
90
91 # A model which has uses a new style attribute object
92 # Bonus: only field access would be tracked this way
93 setup_g = '''
94 def track_property(klass, name):
95     p = '_p_%s' % name
96     def set_modified(o):
97         try:
98             if name not in o._modified_attrs:
99                 o._modified_attrs.add(name)
100         except AttributeError:
101             o._modified_attrs = set((name,))
102     class Attr(object):
103         def __get__(self, instance, value):
104             getattr(instance, p)
105         def __set__(self, instance, value):
106             set_modified(instance)
107             setattr(instance, p, value)
108     setattr(klass, name, Attr())
109 class Model(object):
110     def __init__(self):
111         track_property(self.__class__, 'an_attribute')
112         track_property(self.__class__, 'another_attribute')
113 m = Model()
114 '''
115
116 def timed(t, control=None):
117     if control is None:
118         return '%.3f' % (t)
119     return '%.3f (%.1fx)' % (t, t/control)
120
121 def do_test(test, extra_setup=''):
122     control = Timer(test, setup_a+extra_setup).timeit()
123     print "Control:  ", timed(control)
124     print "noop:     ", timed(Timer(test, setup_b+extra_setup).timeit(), control)
125     print "patch:    ", timed(Timer(test, setup_c+extra_setup).timeit(), control)
126     print "optimized:", timed(Timer(test, setup_d+extra_setup).timeit(), control)
127     print "noop-h-op:", timed(Timer(test, setup_b2+extra_setup).timeit(), control)
128     print "h-optimiz:", timed(Timer(test, setup_h+extra_setup).timeit(), control)
129     print "property: ", timed(Timer(test, setup_f+extra_setup).timeit(), control)
130     print "new-attr: ", timed(Timer(test, setup_g+extra_setup).timeit(), control)
131    
132 print "Single Assignment"
133 do_test('m.an_attribute="test"')
134
135 print
136 print "Double Assignment"
137 do_test('m.an_attribute="test";m.another_attribute="test"')
138
139 print
140 print "Retreiving"
141 do_test('m.an_attribute', extra_setup='m.an_attribute="test"')