Index: src/lucille/search.py
===================================================================
--- src/lucille/search.py	(.../trunk)	(revision 115)
+++ src/lucille/search.py	(.../branches/ugly-python-optimisations)	(revision 115)
@@ -105,8 +105,10 @@
         self.similarity = similarity
     
     def __iter__(self):
-        while self.advance():
-            yield (self.doc, self.score())
+        advance = self.advance
+        score = self.score
+        while advance():
+            yield (self.doc, score())
 
 
 class TermQuery(Query):
@@ -286,14 +288,16 @@
                 for c in self.query.clauses]
 
     def sum_of_squared_weights(self):
+        MUST_NOT_OCCUR = BooleanClause.MUST_NOT_OCCUR
         return (sum(w.sum_of_squared_weights() 
                     for (c, w) in izip(self.query.clauses, self.weights)
-                    if c.occur != BooleanClause.MUST_NOT_OCCUR)
+                    if c.occur != MUST_NOT_OCCUR)
                 * (self.query.boost ** 2))
 
     def normalize(self, norm):
+        boost = self.query.boost
         for w in self.weights:
-            w.normalize(norm * self.query.boost)
+            w.normalize(norm * boost)
 
     def scorer(self, reader):
         scorers = {BooleanClause.MUST_OCCUR: [], 
@@ -379,7 +383,7 @@
         return self._advance_after_current()
     
     def _advance_after_current(self):
-        self.doc = self.scorers[0].doc
+        doc = self.doc = self.scorers[0].doc
         self._score = self.scorers[0].score()
         self.n_matchers = 1
         while True:
@@ -389,7 +393,7 @@
             else:
                 if len(self.scorers) == 0:
                     break
-            if self.scorers[0].doc != self.doc:
+            if self.scorers[0].doc != doc:
                 break
             self._score += self.scorers[0].score()
             self.n_matchers += 1
@@ -449,17 +453,19 @@
             if not self.excl_scorer.advance():
                 self.excl_scorer = None
             self.first_time = False
-        if not self.req_scorer.advance():
+        req_scorer = self.req_scorer
+        if not req_scorer.advance():
             return False
-        self.doc = self.req_scorer.doc
+        self.doc = req_scorer.doc
         if self.excl_scorer is None:
             return True
         return self._to_non_excluded()
     
     def _to_non_excluded(self):
+        req_scorer = self.req_scorer
         excl_doc = self.excl_scorer.doc
         while True:
-            self.doc = req_doc = self.req_scorer.doc
+            self.doc = req_doc = req_scorer.doc
             if req_doc < excl_doc:
                 return True
             elif req_doc > excl_doc:
@@ -469,7 +475,7 @@
                 excl_doc = self.excl_scorer.doc
                 if excl_doc > req_doc:
                     return True
-            if not self.req_scorer.advance():
+            if not req_scorer.advance():
                 return False
     
     def skip_to(self, target):
@@ -497,35 +503,39 @@
         self.first_time_opt = True
     
     def advance(self):
-        if self.req_scorer.advance():
-            self.doc = self.req_scorer.doc
+        req_scorer = self.req_scorer
+        if req_scorer.advance():
+            self.doc = req_scorer.doc
             return True
         else:
             return False
     
     def skip_to(self, target):
-        if self.req_scorer.skip_to(target):
-            self.doc = self.req_scorer.doc
+        req_scorer = self.req_scorer
+        if req_scorer.skip_to(target):
+            self.doc = req_scorer.doc
             return True
         else:
             return False
     
     def score(self):
-        req_score = self.req_scorer.score()
+        opt_scorer = self.opt_scorer
+        req_scorer = self.req_scorer
+        req_score = req_scorer.score()
         if self.first_time_opt:
             self.first_time_opt = False
-            if not self.opt_scorer.skip_to(self.req_scorer.doc):
+            if not opt_scorer.skip_to(req_scorer.doc):
                 self.opt_scorer = None
                 return req_score
-        elif self.opt_scorer is None:
+        elif opt_scorer is None:
             return req_score
-        elif self.opt_scorer.doc < self.req_scorer.doc and \
-                not self.opt_scorer.skip_to(self.req_scorer.doc):
+        elif opt_scorer.doc < req_scorer.doc and \
+                not opt_scorer.skip_to(req_scorer.doc):
             self.opt_scorer = None
             return req_score
 
-        if self.opt_scorer.doc == self.req_scorer.doc:
-            return req_score + self.opt_scorer.score()
+        if opt_scorer.doc == req_scorer.doc:
+            return req_score + opt_scorer.score()
         else:
             return req_score
 
@@ -541,7 +551,8 @@
 
         def __init__(self, similarity, max_coord):
             self.max_coord = max_coord
-            self.coord_factors = [similarity.coord(i, max_coord) 
+            coord = similarity.coord
+            self.coord_factors = [coord(i, max_coord) 
                     for i in range(max_coord + 1)]
             self.n_matchers = 0
 
@@ -559,21 +570,24 @@
             self.last_scored_doc = -1
 
         def score(self):
-            if self.scorer.doc > self.last_scored_doc:
-                self.last_scored_doc = self.scorer.doc
+            scorer = self.scorer
+            if scorer.doc > self.last_scored_doc:
+                self.last_scored_doc = scorer.doc
                 self.coordinator.n_matchers += 1
-            return self.scorer.score()
+            return scorer.score()
 
         def advance(self):
-            if self.scorer.advance():
-                self.doc = self.scorer.doc
+            scorer = self.scorer
+            if scorer.advance():
+                self.doc = scorer.doc
                 return True
             else:
                 return False
 
         def skip_to(self, target):
-            if self.scorer.skip_to(target):
-                self.doc = self.scorer.doc
+            scorer = self.scorer
+            if scorer.skip_to(target):
+                self.doc = scorer.doc
                 return True
             else:
                 return False
@@ -588,8 +602,9 @@
             self.last_scored_doc = -1
 
         def score(self):
-            if self.doc > self.last_scored_doc:
-                self.last_scored_doc = self.doc
+            doc = self.doc
+            if doc > self.last_scored_doc:
+                self.last_scored_doc = doc
                 self.coordinator.n_matchers += self.n_matchers # super
             return DisjunctionSumScorer.score(self)
     
@@ -604,8 +619,9 @@
             self.last_scored_doc = -1
 
         def score(self):
-            if self.doc > self.last_scored_doc:
-                self.last_scored_doc = self.doc
+            doc = self.doc
+            if doc > self.last_scored_doc:
+                self.last_scored_doc = doc
                 self.coordinator.n_matchers += self.required_n_matchers
             return ConjunctionScorer.score(self)
 
@@ -666,15 +682,17 @@
             return ReqExclScorer(scorer, prohibited_sum_scorer)
     
     def advance(self):
-        if self.counting_sum_scorer.advance():
-            self.doc = self.counting_sum_scorer.doc
+        css = self.counting_sum_scorer
+        if css.advance():
+            self.doc = css.doc
             return True
         else:
             return False
     
     def skip_to(self, target):
-        if self.counting_sum_scorer.skip_to(target):
-            self.doc = self.counting_sum_scorer.doc
+        css = self.counting_sum_scorer
+        if css.skip_to(target):
+            self.doc = css.doc
             return True
         else:
             return False
Index: src/lucille/index.py
===================================================================
--- src/lucille/index.py	(.../trunk)	(revision 115)
+++ src/lucille/index.py	(.../branches/ugly-python-optimisations)	(revision 115)
@@ -533,16 +533,18 @@
         self.size = self.index_stream.length // 8
     
     def doc(self, docnum, fields=None):
-        with self.index_stream.filepos_lock:
-            self.index_stream.seek(docnum * 8)
-            pos = self.index_stream.read_long()
-            self.fields_stream.seek(pos)
+        index_stream = self.index_stream
+        fields_stream = self.fields_stream
+        with index_stream.filepos_lock:
+            index_stream.seek(docnum * 8)
+            pos = index_stream.read_long()
+            fields_stream.seek(pos)
             doc = Document()
-            field_count = self.fields_stream.read_vint()
+            field_count = fields_stream.read_vint()
             for _ in xrange(field_count):
-                field_num = self.fields_stream.read_vint()
-                fi = self.field_infos[field_num]
-                bits = self.fields_stream.read_byte()
+                field_num = fields_stream.read_vint()
+                fi = field_infos[field_num]
+                bits = fields_stream.read_byte()
                 compressed = bits & self.FIELD_IS_COMPRESSED
                 tokenized = bits & self.FIELD_IS_TOKENIZED
                 binary = bits & self.FIELD_IS_BINARY
@@ -649,31 +651,33 @@
         self.term_info = term_info
     
     def __iter__(self):
+        advance = self.advance
         with self.lock:
-            while self.advance(): yield (self.term, self.term_info)
+            while advance(): yield (self.term, self.term_info)
 
     def advance(self):
         """ org.apache.lucene.SegmentTermEnum#next() """
         self.position += 1
         if self.position >= self.size:
             return False
+        input = self.input
 
         # read the term -- Lucene uses TermBuffer for this, I cbf
-        prefix_length = self.input.read_vint()
-        suffix = self.input.read_string()
+        prefix_length = input.read_vint()
+        suffix = input.read_string()
         term_text = self.term[1][:prefix_length] + suffix
-        field_num = self.input.read_vint()
+        field_num = input.read_vint()
         term_field = self.field_infos.field_name(field_num)
 
         ti = TermInfo()
-        ti.doc_freq = self.input.read_vint()
-        ti.freq_pointer = self.term_info.freq_pointer + self.input.read_vint()
-        ti.prox_pointer = self.term_info.prox_pointer + self.input.read_vint()
+        ti.doc_freq = input.read_vint()
+        ti.freq_pointer = self.term_info.freq_pointer + input.read_vint()
+        ti.prox_pointer = self.term_info.prox_pointer + input.read_vint()
         if ti.doc_freq >= self.skip_interval:
-            ti.skip_offset = self.input.read_vint()
+            ti.skip_offset = input.read_vint()
 
         if self.is_index:
-            self.index_pointer += self.input.read_vint()
+            self.index_pointer += input.read_vint()
 
         self.term = (term_field, term_text)
         self.term_info = ti
@@ -681,7 +685,8 @@
         return True
     
     def scan_to(self, term):
-        while term > self.term and self.advance(): pass
+        advance = self.advance
+        while term > self.term and advance(): pass
     
     def clone(self):
         c = copy.copy(self)
@@ -746,8 +751,9 @@
         return prev_i
 
     def _scan_enum(self, term):
-        self.enum.scan_to(term)
-        if self.enum.term == term: return self.enum.term_info
+        enum = self.enum
+        enum.scan_to(term)
+        if enum.term == term: return enum.term_info
         else: return None
     
     def _seek_enum(self, index_offset):
@@ -756,11 +762,12 @@
                 self.index_terms[index_offset], self.index_infos[index_offset])
     
     def get(self, term):
-        with self.enum.lock: # XXX use thread-locals instead
+        enum = self.enum
+        with enum.lock: # XXX use thread-locals instead
             # optimised case for sequential access
-            if term > self.enum.term:
+            if term > enum.term:
                 # term is at or past current ...
-                enum_offset = (self.enum.position // self.enum.index_interval) + 1
+                enum_offset = (enum.position // enum.index_interval) + 1
                 if len(self.index_terms) == enum_offset or \
                         term < self.index_terms[enum_offset]:
                     # ... but before end of block, therefore no need to seek
@@ -816,7 +823,8 @@
 
     def __iter__(self):
         with self.lock: # caller should already hold this, but just for safety
-            while self.advance():
+            advance = self.advance
+            while advance():
                 yield (self.doc, self.freq)
     
     def _do_advance(self):
@@ -833,10 +841,12 @@
 
     def advance(self):
         # omits deleted docs
-        if self.deleted_docs is None: return self._do_advance()
+        _do_advance = self._do_advance
+        deleted_docs = self.deleted_docs
+        if deleted_docs is None: return _do_advance()
         while True:
-            if self._do_advance():
-                if not self.deleted_docs[self.doc]:
+            if _do_advance():
+                if not deleted_docs[self.doc]:
                     return True
             else:
                 return False
@@ -848,11 +858,13 @@
             # we can use the skip data to get closer to the right position
             if self.skip_stream is None:
                 self.skip_stream = self.freq_stream.clone()
+            skip_stream = self.skip_stream
+            freq_stream = self.freq_stream
             if not self.have_skipped:
-                self.skip_stream.seek(self.skip_pointer)
+                skip_stream.seek(self.skip_pointer)
                 self.have_skipped = True
             last_skip_doc = self.skip_doc
-            last_freq_pointer = self.freq_stream.tell()
+            last_freq_pointer = freq_stream.tell()
             num_skipped = -1 - (self.count % self.skip_interval)
             while target > self.skip_doc:
                 last_skip_doc = self.skip_doc
@@ -861,16 +873,17 @@
                     num_skipped += self.skip_interval
                 if self.skip_count >= self.num_skips:
                     break
-                self.skip_doc += self.skip_stream.read_vint()
-                self.freq_pointer += self.skip_stream.read_vint()
+                self.skip_doc += skip_stream.read_vint()
+                self.freq_pointer += skip_stream.read_vint()
                 self.skip_count += 1
-            if last_freq_pointer > self.freq_stream.tell():
+            if last_freq_pointer > freq_stream.tell():
                 self.freq_stream.seek(last_freq_pointer)
                 self.doc = last_skip_doc
                 self.count += num_skipped
-        self.advance() # always advance at least once
+        advance = self.advance
+        advance() # always advance at least once
         while target > self.doc:
-            if not self.advance():
+            if not advance():
                 return False
         return True
 
@@ -1125,17 +1138,19 @@
                 self.term_enums.push(te)
     
     def __iter__(self):
-        while self.advance():
+        advance = self.advance
+        while advance():
             yield (self.term, self.term_info)
     
     def advance(self):
-        if len(self.term_enums) == 0:
+        tes = self.term_enums
+        if len(tes) == 0:
             return False
-        te = self.term_enums.pop()
+        te = tes.pop()
         self.term = te.term
         self.term_info = te.term_info
         if te.advance():
-            self.term_enums.push(te)
+            tes.push(te)
         return True
 
 
@@ -1160,7 +1175,8 @@
         self.current = 0
     
     def __iter__(self):
-        while self.advance():
+        advance = self.advance
+        while advance():
             yield (self.doc, self.freq)
     
     def advance(self):
