diff -r 2bf154ca43c6 Lib/test/test_weakref.py --- a/Lib/test/test_weakref.py Sat Apr 06 01:15:30 2013 +0200 +++ b/Lib/test/test_weakref.py Sat Apr 06 13:52:33 2013 +0100 @@ -802,6 +802,29 @@ del root gc.collect() + def test_callback_attribute(self): + x = Object(1) + callback = lambda ref: None + ref1 = weakref.ref(x, callback) + self.assertIs(ref1.__callback__, callback) + + ref2 = weakref.ref(x) + self.assertIsNone(ref2.__callback__) + + def test_callback_attribute_after_deletion(self): + x = Object(1) + ref = weakref.ref(x, self.callback) + self.assertIsNotNone(ref.__callback__) + del x + self.assertIsNone(ref.__callback__) + + def test_set_callback_attribute(self): + x = Object(1) + callback = lambda ref: None + ref1 = weakref.ref(x, callback) + with self.assertRaises(AttributeError): + ref1.__callback__ = lambda ref: None + class SubclassableWeakrefTestCase(TestBase): diff -r 2bf154ca43c6 Objects/weakrefobject.c --- a/Objects/weakrefobject.c Sat Apr 06 01:15:30 2013 +0200 +++ b/Objects/weakrefobject.c Sat Apr 06 13:52:33 2013 +0100 @@ -209,6 +209,24 @@ PyWeakref_GET_OBJECT(other), op); } +/* Getter for __callback__ attribute. */ +static PyObject * +weakref_get_callback(PyWeakReference* self) +{ + if (self->wr_callback == NULL) { + Py_RETURN_NONE; + } + else { + Py_INCREF(self->wr_callback); + return self->wr_callback; + } +} + +static PyGetSetDef weakref_getset[] = { + {"__callback__", (getter)weakref_get_callback, (setter)NULL}, + {NULL} /* Sentinel */ +}; + /* Given the head of an object's list of weak references, extract the * two callback-less refs (ref and proxy). Used to determine if the * shared references exist and to determine the back link for newly @@ -370,7 +388,7 @@ 0, /*tp_iternext*/ 0, /*tp_methods*/ 0, /*tp_members*/ - 0, /*tp_getset*/ + weakref_getset, /*tp_getset*/ 0, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/