diff -r b83ae75beaca Include/object.h
--- a/Include/object.h	Sat Feb 25 01:22:36 2012 +0100
+++ b/Include/object.h	Sat Feb 25 03:23:20 2012 +0100
@@ -615,6 +615,8 @@ given type object has a specified featur
 #define Py_TPFLAGS_HAVE_STACKLESS_EXTENSION 0
 #endif
 
+#define Py_TPFLAGS_IS_FINAL   (1L<<17)
+
 /* Objects support type attribute cache */
 #define Py_TPFLAGS_HAVE_VERSION_TAG   (1L<<18)
 #define Py_TPFLAGS_VALID_VERSION_TAG  (1L<<19)
diff -r b83ae75beaca Objects/typeobject.c
--- a/Objects/typeobject.c	Sat Feb 25 01:22:36 2012 +0100
+++ b/Objects/typeobject.c	Sat Feb 25 03:23:20 2012 +0100
@@ -1968,7 +1968,7 @@ type_new(PyTypeObject *metatype, PyObjec
     PyHeapTypeObject *et;
     PyMemberDef *mp;
     Py_ssize_t i, nbases, nslots, slotoffset, add_dict, add_weak;
-    int j, may_add_dict, may_add_weak;
+    int j, may_add_dict, may_add_weak, is_final;
 
     assert(args != NULL && PyTuple_Check(args));
     assert(kwds == NULL || PyDict_Check(kwds));
@@ -2040,12 +2040,16 @@ type_new(PyTypeObject *metatype, PyObjec
     if (dict == NULL)
         goto error;
 
+    is_final = (PyDict_GetItemString(dict, "__final__") != NULL);
+
     /* Check for a __slots__ sequence variable in dict, and count it */
     slots = PyDict_GetItemString(dict, "__slots__");
     nslots = 0;
     add_dict = 0;
     add_weak = 0;
     may_add_dict = base->tp_dictoffset == 0;
+    if (is_final)
+        may_add_dict = 0;
     may_add_weak = base->tp_weaklistoffset == 0 && base->tp_itemsize == 0;
     if (slots == NULL) {
         if (may_add_dict) {
@@ -2188,6 +2192,8 @@ type_new(PyTypeObject *metatype, PyObjec
         Py_TPFLAGS_BASETYPE;
     if (base->tp_flags & Py_TPFLAGS_HAVE_GC)
         type->tp_flags |= Py_TPFLAGS_HAVE_GC;
+    if (is_final)
+        type->tp_flags |= Py_TPFLAGS_IS_FINAL;
 
     /* Initialize essential fields */
     type->tp_as_number = &et->as_number;
@@ -2548,6 +2554,12 @@ type_getattro(PyTypeObject *type, PyObje
 static int
 type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
 {
+    if (type->tp_flags & Py_TPFLAGS_IS_FINAL) {
+        PyErr_Format(PyExc_TypeError,
+                     "%s type is read-only",
+                     type->tp_name);
+        return -1;
+    }
     if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
         PyErr_Format(
             PyExc_TypeError,
