title: How to maintain state in Python without classes?
body: <p>Are there <code>pythonic</code> ways to maintain state (for purposes of optimisation, for example) without going fully object-oriented?</p>
  
  <p>To illustrate my question better, here's an example of a pattern I use frequently in JavaScript:</p>
  
  <pre><code>var someFunc = (function () {
      var foo = some_expensive_initialization_operation();
      return someFunc (bar) {
          // do something with foo and bar
      }
  }());
  </code></pre>
  
  <p>Externally this is just a function like any other, with no need to initialise objects or anything like that, but the closure allows computing values a single time that I then essentially use as constants.</p>
  
  <p>An example of this in Python is when optimising regular expressions - it's useful to use <code>re.compile</code> and stored the compiled version for <code>match</code> and <code>search</code> operations.</p>
  
  <p>The only ways I know of to do this in Python are by setting a variable in the module scope:</p>
  
  <pre><code>compiled_regex = compile_my_regex()
  
  def try_match(m): # In reality I wouldn't wrap it as pointlessly as this
      return compiled_regex.match(m)
  </code></pre>
  
  <p>Or by creating a class:</p>
  
  <pre><code>class MatcherContainer(object):
      def __init__(self):
          self.compiled_regex = compile_my_regex()
      def try_match(self, m):
          self.compiled_regex.match(m)
  
  my_matcher = MatcherContainer()
  </code></pre>
  
  <p>The former approach is ad-hoc and it's not very clear that the function and the variable declared above it are associated with each other. It also sits pollutes the module's namespace a bit, which I'm not too happy with.</p>
  
  <p>The latter approach seems verbose and a bit heavy on the boilerplate.</p>
  
  <p>The only other way I can think of to deal with this is to factor any functions like this out into separate files (modules) and just import the functions, so that everything's clean.</p>
  
  <p>Any advice from more experienced Pythoners on how to deal with this? Or do you just not worry about it and get on with solving the problem?</p>