Skip to content

Commit 64505a1

Browse files
lisroachserhiy-storchaka
authored andcommitted
bpo-30486: Allow setting cell value (#1840)
The cell_contents attribute of the cell object is now writable.
1 parent 6cca5c8 commit 64505a1

File tree

4 files changed

+41
-4
lines changed

4 files changed

+41
-4
lines changed

Doc/reference/datamodel.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,9 @@ Callable types
510510
| :attr:`__closure__` | ``None`` or a tuple of cells | Read-only |
511511
| | that contain bindings for the | |
512512
| | function's free variables. | |
513+
| | See below for information on | |
514+
| | the ``cell_contents`` | |
515+
| | attribute. | |
513516
+-------------------------+-------------------------------+-----------+
514517
| :attr:`__annotations__` | A dict containing annotations | Writable |
515518
| | of parameters. The keys of | |
@@ -530,6 +533,9 @@ Callable types
530533
implementation only supports function attributes on user-defined functions.
531534
Function attributes on built-in functions may be supported in the future.*
532535

536+
A cell object has the attribute ``cell_contents``. This can be used to get
537+
the value of the cell, as well as set the value.
538+
533539
Additional information about a function's definition can be retrieved from its
534540
code object; see the description of internal types below.
535541

Lib/test/test_funcattrs.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,26 @@ def f(): print(a)
9393
self.fail("shouldn't be able to read an empty cell")
9494
a = 12
9595

96+
def test_set_cell(self):
97+
a = 12
98+
def f(): return a
99+
c = f.__closure__
100+
c[0].cell_contents = 9
101+
self.assertEqual(c[0].cell_contents, 9)
102+
self.assertEqual(f(), 9)
103+
self.assertEqual(a, 9)
104+
del c[0].cell_contents
105+
try:
106+
c[0].cell_contents
107+
except ValueError:
108+
pass
109+
else:
110+
self.fail("shouldn't be able to read an empty cell")
111+
with self.assertRaises(NameError):
112+
f()
113+
with self.assertRaises(UnboundLocalError):
114+
print(a)
115+
96116
def test___name__(self):
97117
self.assertEqual(self.b.__name__, 'b')
98118
self.b.__name__ = 'c'

Misc/NEWS

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ What's New in Python 3.7.0 alpha 1?
1010
Core and Builtins
1111
-----------------
1212

13+
- bpo-30486: Allows setting cell values for __closure__. Patch by Lisa Roach.
14+
15+
- bpo-30537: itertools.islice now accepts integer-like objects (having
16+
an __index__ method) as start, stop, and slice arguments
17+
1318
- bpo-25324: Tokens needed for parsing in Python moved to C. ``COMMENT``,
1419
``NL`` and ``ENCODING``. This way the tokens and tok_names in the token
1520
module don't get changed when you import the tokenize module.
@@ -128,9 +133,6 @@ Core and Builtins
128133

129134
- bpo-29546: Improve from-import error message with location
130135

131-
- bpo-30537: itertools.islice now accepts integer-like objects (having
132-
an __index__ method) as start, stop, and slice arguments
133-
134136
- Issue #29319: Prevent RunMainFromImporter overwriting sys.path[0].
135137

136138
- Issue #29337: Fixed possible BytesWarning when compare the code objects.

Objects/cellobject.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,17 @@ cell_get_contents(PyCellObject *op, void *closure)
140140
return op->ob_ref;
141141
}
142142

143+
int
144+
cell_set_contents(PyCellObject *op, PyObject *obj)
145+
{
146+
Py_XINCREF(obj);
147+
Py_XSETREF(op->ob_ref, obj);
148+
return 0;
149+
}
150+
143151
static PyGetSetDef cell_getsetlist[] = {
144-
{"cell_contents", (getter)cell_get_contents, NULL},
152+
{"cell_contents", (getter)cell_get_contents,
153+
(setter)cell_set_contents, NULL},
145154
{NULL} /* sentinel */
146155
};
147156

0 commit comments

Comments
 (0)