Index: trac/config.py
===================================================================
--- trac/config.py	(revision 8720)
+++ trac/config.py	(working copy)
@@ -28,6 +28,8 @@
 
 _TRUE_VALUES = ('yes', 'true', 'enabled', 'on', 'aye', '1', 1, True)
 
+_use_default = object()
+
 def _to_utf8(basestr):
     return to_unicode(basestr).encode('utf-8')
 
@@ -53,6 +55,7 @@
         self._lastmtime = 0
         self._sections = {}
         self.parse_if_needed()
+        self._cache = {}
 
     def __contains__(self, name):
         """Return whether the configuration contains a section of the given
@@ -237,6 +240,7 @@
         changed = False
         modtime = os.path.getmtime(self.filename)
         if modtime > self._lastmtime:
+            self._cache = {}
             self.parser._sections = {}
             self.parser.read(self.filename)
             self._lastmtime = modtime
@@ -311,6 +315,10 @@
         
         Valid default input is a string. Returns a string.
         """
+        ckey = (self.name, key)
+        cached = self.config._cache.get(ckey, _use_default)
+        if cached is not _use_default:
+            return cached
         name_str = _to_utf8(self.name)
         key_str = _to_utf8(key)
         if self.config.parser.has_option(name_str, key_str):
@@ -318,17 +326,19 @@
         elif self.config.parent:
             value = self.config.parent[self.name].get(key, default)
         else:
-            option = Option.registry.get((self.name, key))
+            option = Option.registry.get(ckey)
             if option:
-                value = option.default or default
+                value = option.default or _use_default
             else:
-                value = default
+                value = _use_default
+        if value is _use_default:
+            return default
         if not value:
-            return u''
+            value = u''
         elif isinstance(value, basestring):
-            return to_unicode(value)
-        else:
-            return value
+            value = to_unicode(value)
+        self.config._cache[ckey] = value
+        return value
 
     def getbool(self, key, default=''):
         """Return the value of the specified option as boolean.
@@ -418,6 +428,7 @@
         
         These changes are not persistent unless saved with `save()`.
         """
+        self.config._cache.pop((self.name, key), None)
         name_str = _to_utf8(self.name)
         key_str = _to_utf8(key)
         if not self.config.parser.has_section(name_str):

