Skip to content

Commit 556e94b

Browse files
committed
Issue python#17643: Add __callback__ attribute to weakref.ref.
1 parent 548677b commit 556e94b

4 files changed

Lines changed: 44 additions & 3 deletions

File tree

Doc/library/weakref.rst

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,15 @@ Extension types can easily be made to support weak references; see
111111

112112
This is a subclassable type rather than a factory function.
113113

114+
.. attribute:: __callback__
115+
116+
This read-only attribute returns the callback currently associated to the
117+
weakref. If there is no callback or if the referent of the weakref is
118+
no longer alive then this attribute will have value ``None``.
119+
120+
.. versionadded:: 3.4
121+
Added the :attr:`__callback__` attribute.
122+
114123

115124
.. function:: proxy(object[, callback])
116125

@@ -261,8 +270,9 @@ These method have the same issues as the and :meth:`keyrefs` method of
261270
Weak Reference Objects
262271
----------------------
263272

264-
Weak reference objects have no attributes or methods, but do allow the referent
265-
to be obtained, if it still exists, by calling it:
273+
Weak reference objects have no methods and no attributes besides
274+
:attr:`ref.__callback__`. A weak reference object allows the referent to be
275+
obtained, if it still exists, by calling it:
266276

267277
>>> import weakref
268278
>>> class Object:

Lib/test/test_weakref.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,30 @@ def cb(wparent):
802802
del root
803803
gc.collect()
804804

805+
def test_callback_attribute(self):
806+
x = Object(1)
807+
callback = lambda ref: None
808+
ref1 = weakref.ref(x, callback)
809+
self.assertIs(ref1.__callback__, callback)
810+
811+
ref2 = weakref.ref(x)
812+
self.assertIsNone(ref2.__callback__)
813+
814+
def test_callback_attribute_after_deletion(self):
815+
x = Object(1)
816+
ref = weakref.ref(x, self.callback)
817+
self.assertIsNotNone(ref.__callback__)
818+
del x
819+
support.gc_collect()
820+
self.assertIsNone(ref.__callback__)
821+
822+
def test_set_callback_attribute(self):
823+
x = Object(1)
824+
callback = lambda ref: None
825+
ref1 = weakref.ref(x, callback)
826+
with self.assertRaises(AttributeError):
827+
ref1.__callback__ = lambda ref: None
828+
805829

806830
class SubclassableWeakrefTestCase(TestBase):
807831

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ What's New in Python 3.4.0 Alpha 1?
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #17643: Add __callback__ attribute to weakref.ref.
14+
1315
- Issue #16447: Fixed potential segmentation fault when setting __name__ on a
1416
class.
1517

Objects/weakrefobject.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,11 @@ weakref___init__(PyObject *self, PyObject *args, PyObject *kwargs)
338338
}
339339

340340

341+
static PyMemberDef weakref_members[] = {
342+
{"__callback__", T_OBJECT, offsetof(PyWeakReference, wr_callback), READONLY},
343+
{NULL} /* Sentinel */
344+
};
345+
341346
PyTypeObject
342347
_PyWeakref_RefType = {
343348
PyVarObject_HEAD_INIT(&PyType_Type, 0)
@@ -369,7 +374,7 @@ _PyWeakref_RefType = {
369374
0, /*tp_iter*/
370375
0, /*tp_iternext*/
371376
0, /*tp_methods*/
372-
0, /*tp_members*/
377+
weakref_members, /*tp_members*/
373378
0, /*tp_getset*/
374379
0, /*tp_base*/
375380
0, /*tp_dict*/

0 commit comments

Comments
 (0)