diff --git a/CHANGES.txt b/CHANGES.txt
index a509af2fa4d16d7abfce4ddbe38963a94b2723f6_Q0hBTkdFUy50eHQ=..e55d98f7c2eb4e7c9e3d898b7356ef4d9bc2995b_Q0hBTkdFUy50eHQ= 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,2 +1,8 @@
+Version 2.3.1 released 2011-12-29
+
+* namedtuple_as_object now checks _asdict to ensure that it
+  is callable.
+  https://github.com/simplejson/simplejson/issues/26
+
 Version 2.3.0 released 2011-12-05
 
@@ -1,6 +7,6 @@
 Version 2.3.0 released 2011-12-05
 
-* Any objects with _asdict() methods are now considered for 
+* Any objects with _asdict() methods are now considered for
   namedtuple_as_object.
   https://github.com/simplejson/simplejson/pull/22
 
diff --git a/conf.py b/conf.py
index a509af2fa4d16d7abfce4ddbe38963a94b2723f6_Y29uZi5weQ==..e55d98f7c2eb4e7c9e3d898b7356ef4d9bc2995b_Y29uZi5weQ== 100644
--- a/conf.py
+++ b/conf.py
@@ -44,7 +44,7 @@
 # The short X.Y version.
 version = '2.3'
 # The full version, including alpha/beta/rc tags.
-release = '2.3.0'
+release = '2.3.1'
 
 # There are two options for replacing |today|: either, you set today to some
 # non-false value, then it is used:
diff --git a/simplejson/__init__.py b/simplejson/__init__.py
index a509af2fa4d16d7abfce4ddbe38963a94b2723f6_c2ltcGxlanNvbi9fX2luaXRfXy5weQ==..e55d98f7c2eb4e7c9e3d898b7356ef4d9bc2995b_c2ltcGxlanNvbi9fX2luaXRfXy5weQ== 100644
--- a/simplejson/__init__.py
+++ b/simplejson/__init__.py
@@ -97,7 +97,7 @@
     $ echo '{ 1.2:3.4}' | python -m simplejson.tool
     Expecting property name: line 1 column 2 (char 2)
 """
-__version__ = '2.3.0'
+__version__ = '2.3.1'
 __all__ = [
     'dump', 'dumps', 'load', 'loads',
     'JSONDecoder', 'JSONDecodeError', 'JSONEncoder',
diff --git a/simplejson/_speedups.c b/simplejson/_speedups.c
index a509af2fa4d16d7abfce4ddbe38963a94b2723f6_c2ltcGxlanNvbi9fc3BlZWR1cHMuYw==..e55d98f7c2eb4e7c9e3d898b7356ef4d9bc2995b_c2ltcGxlanNvbi9fc3BlZWR1cHMuYw== 100644
--- a/simplejson/_speedups.c
+++ b/simplejson/_speedups.c
@@ -169,7 +169,15 @@
 static int
 _is_namedtuple(PyObject *obj)
 {
-    return PyObject_HasAttrString(obj, "_asdict");
+    int rval = 0;
+    PyObject *_asdict = PyObject_GetAttrString(obj, "_asdict");
+    if (_asdict == NULL) {
+        PyErr_Clear();
+        return 0;
+    }
+    rval = PyCallable_Check(obj);
+    Py_DECREF(obj);
+    return rval;
 }
 
 static int
diff --git a/simplejson/encoder.py b/simplejson/encoder.py
index a509af2fa4d16d7abfce4ddbe38963a94b2723f6_c2ltcGxlanNvbi9lbmNvZGVyLnB5..e55d98f7c2eb4e7c9e3d898b7356ef4d9bc2995b_c2ltcGxlanNvbi9lbmNvZGVyLnB5 100644
--- a/simplejson/encoder.py
+++ b/simplejson/encoder.py
@@ -157,7 +157,7 @@
 
         If namedtuple_as_object is true (the default), objects with
         ``_asdict()`` methods will be encoded as JSON objects.
-        
+
         If tuple_as_array is true (the default), tuple (and subclasses) will
         be encoded as JSON arrays.
         """
@@ -387,11 +387,4 @@
                 yield buf
                 if isinstance(value, list):
                     chunks = _iterencode_list(value, _current_indent_level)
-                elif (_namedtuple_as_object and hasattr(value, '_asdict')):
-                    chunks = _iterencode_dict(value._asdict(),
-                                              _current_indent_level)
-                elif _tuple_as_array and isinstance(value, tuple):
-                    chunks = _iterencode_list(value, _current_indent_level)
-                elif isinstance(value, dict):
-                    chunks = _iterencode_dict(value, _current_indent_level)
                 else:
@@ -397,5 +390,14 @@
                 else:
-                    chunks = _iterencode(value, _current_indent_level)
+                    _asdict = _namedtuple_as_object and getattr(value, '_asdict', None)
+                    if _asdict and callable(_asdict):
+                        chunks = _iterencode_dict(_asdict(),
+                                                  _current_indent_level)
+                    elif _tuple_as_array and isinstance(value, tuple):
+                        chunks = _iterencode_list(value, _current_indent_level)
+                    elif isinstance(value, dict):
+                        chunks = _iterencode_dict(value, _current_indent_level)
+                    else:
+                        chunks = _iterencode(value, _current_indent_level)
                 for chunk in chunks:
                     yield chunk
         if newline_indent is not None:
@@ -471,11 +473,4 @@
             else:
                 if isinstance(value, list):
                     chunks = _iterencode_list(value, _current_indent_level)
-                elif (_namedtuple_as_object and hasattr(value, '_asdict')):
-                    chunks = _iterencode_dict(value._asdict(),
-                                              _current_indent_level)
-                elif _tuple_as_array and isinstance(value, tuple):
-                    chunks = _iterencode_list(value, _current_indent_level)
-                elif isinstance(value, dict):
-                    chunks = _iterencode_dict(value, _current_indent_level)
                 else:
@@ -481,5 +476,14 @@
                 else:
-                    chunks = _iterencode(value, _current_indent_level)
+                    _asdict = _namedtuple_as_object and getattr(value, '_asdict', None)
+                    if _asdict and callable(_asdict):
+                        chunks = _iterencode_dict(_asdict(),
+                                                  _current_indent_level)
+                    elif _tuple_as_array and isinstance(value, tuple):
+                        chunks = _iterencode_list(value, _current_indent_level)
+                    elif isinstance(value, dict):
+                        chunks = _iterencode_dict(value, _current_indent_level)
+                    else:
+                        chunks = _iterencode(value, _current_indent_level)
                 for chunk in chunks:
                     yield chunk
         if newline_indent is not None:
@@ -505,15 +509,4 @@
         elif isinstance(o, list):
             for chunk in _iterencode_list(o, _current_indent_level):
                 yield chunk
-        elif (_namedtuple_as_object and hasattr(o, '_asdict')):
-            for chunk in _iterencode_dict(o._asdict(), _current_indent_level):
-                yield chunk
-        elif (_tuple_as_array and isinstance(o, tuple)):
-            for chunk in _iterencode_list(o, _current_indent_level):
-                yield chunk
-        elif isinstance(o, dict):
-            for chunk in _iterencode_dict(o, _current_indent_level):
-                yield chunk
-        elif _use_decimal and isinstance(o, Decimal):
-            yield str(o)
         else:
@@ -519,13 +512,26 @@
         else:
-            if markers is not None:
-                markerid = id(o)
-                if markerid in markers:
-                    raise ValueError("Circular reference detected")
-                markers[markerid] = o
-            o = _default(o)
-            for chunk in _iterencode(o, _current_indent_level):
-                yield chunk
-            if markers is not None:
-                del markers[markerid]
+            _asdict = _namedtuple_as_object and getattr(o, '_asdict', None)
+            if _asdict and callable(_asdict):
+                for chunk in _iterencode_dict(_asdict(), _current_indent_level):
+                    yield chunk
+            elif (_tuple_as_array and isinstance(o, tuple)):
+                for chunk in _iterencode_list(o, _current_indent_level):
+                    yield chunk
+            elif isinstance(o, dict):
+                for chunk in _iterencode_dict(o, _current_indent_level):
+                    yield chunk
+            elif _use_decimal and isinstance(o, Decimal):
+                yield str(o)
+            else:
+                if markers is not None:
+                    markerid = id(o)
+                    if markerid in markers:
+                        raise ValueError("Circular reference detected")
+                    markers[markerid] = o
+                o = _default(o)
+                for chunk in _iterencode(o, _current_indent_level):
+                    yield chunk
+                if markers is not None:
+                    del markers[markerid]
 
     return _iterencode
diff --git a/simplejson/tests/test_namedtuple.py b/simplejson/tests/test_namedtuple.py
index a509af2fa4d16d7abfce4ddbe38963a94b2723f6_c2ltcGxlanNvbi90ZXN0cy90ZXN0X25hbWVkdHVwbGUucHk=..e55d98f7c2eb4e7c9e3d898b7356ef4d9bc2995b_c2ltcGxlanNvbi90ZXN0cy90ZXN0X25hbWVkdHVwbGUucHk= 100644
--- a/simplejson/tests/test_namedtuple.py
+++ b/simplejson/tests/test_namedtuple.py
@@ -35,6 +35,18 @@
     def _asdict(self):
         return self.point._asdict()
 
+class DeadDuck(object):
+    _asdict = None
+
+class DeadDict(dict):
+    _asdict = None
+
+CONSTRUCTORS = [
+    lambda v: v,
+    lambda v: [v],
+    lambda v: [{'key': v}],
+]
+
 class TestNamedTuple(unittest.TestCase):
     def test_namedtuple_dumps(self):
         for v in [Value(1), Point(1, 2), DuckValue(1), DuckPoint(1, 2)]:
@@ -89,3 +101,21 @@
                 json.loads(sio.getvalue()))
             self.assertRaises(TypeError, json.dump, v, StringIO(),
                 tuple_as_array=False, namedtuple_as_object=False)
+
+    def test_asdict_not_callable_dump(self):
+        for f in CONSTRUCTORS:
+            self.assertRaises(TypeError,
+                json.dump, f(DeadDuck()), StringIO(), namedtuple_as_object=True)
+            sio = StringIO()
+            json.dump(f(DeadDict()), sio, namedtuple_as_object=True)
+            self.assertEqual(
+                json.dumps(f({})),
+                sio.getvalue())
+
+    def test_asdict_not_callable_dumps(self):
+        for f in CONSTRUCTORS:
+            self.assertRaises(TypeError,
+                json.dumps, f(DeadDuck()), namedtuple_as_object=True)
+            self.assertEqual(
+                json.dumps(f({})),
+                json.dumps(f(DeadDict()), namedtuple_as_object=True))