Skip to content

Commit a9f48a0

Browse files
committed
Merged revisions 72223 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r72223 | antoine.pitrou | 2009-05-02 23:13:23 +0200 (sam., 02 mai 2009) | 5 lines Isue #5084: unpickling now interns the attribute names of pickled objects, saving memory and avoiding growth in size of subsequent pickles. Proposal and original patch by Jake McGuire. ........
1 parent 6fa98fb commit a9f48a0

4 files changed

Lines changed: 42 additions & 2 deletions

File tree

‎Lib/pickle.py‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1195,7 +1195,15 @@ def load_build(self):
11951195
if isinstance(state, tuple) and len(state) == 2:
11961196
state, slotstate = state
11971197
if state:
1198-
inst.__dict__.update(state)
1198+
d = inst.__dict__
1199+
intern = sys.intern
1200+
try:
1201+
for k, v in state.items():
1202+
d[intern(k)] = v
1203+
# keys in state don't have to be strings
1204+
# don't blow up, but don't go out of our way
1205+
except TypeError:
1206+
d.update(state)
11991207
if slotstate:
12001208
for k, v in slotstate.items():
12011209
setattr(inst, k, v)

‎Lib/test/pickletester.py‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,20 @@ def test_many_puts_and_gets(self):
932932
"Failed protocol %d: %r != %r"
933933
% (proto, obj, loaded))
934934

935+
def test_attribute_name_interning(self):
936+
# Test that attribute names of pickled objects are interned when
937+
# unpickling.
938+
for proto in protocols:
939+
x = C()
940+
x.foo = 42
941+
x.bar = "hello"
942+
s = self.dumps(x, proto)
943+
y = self.loads(s)
944+
x_keys = sorted(x.__dict__)
945+
y_keys = sorted(y.__dict__)
946+
for x_key, y_key in zip(x_keys, y_keys):
947+
self.assertIs(x_key, y_key)
948+
935949
# Test classes for reduce_ex
936950

937951
class REX_one(object):

‎Misc/NEWS‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ Installation
109109
Library
110110
-------
111111

112+
- Issue #5084: unpickling now interns the attribute names of pickled objects,
113+
saving memory and avoiding growth in size of subsequent pickles. Proposal
114+
and original patch by Jake McGuire.
115+
112116
- The json module now works exclusively with str and not bytes.
113117

114118
- Issue #3959: The ipaddr module has been added to the standard library.

‎Modules/_pickle.c‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4020,6 +4020,8 @@ load_build(UnpicklerObject *self)
40204020
/* Set inst.__dict__ from the state dict (if any). */
40214021
if (state != Py_None) {
40224022
PyObject *dict;
4023+
PyObject *d_key, *d_value;
4024+
Py_ssize_t i;
40234025

40244026
if (!PyDict_Check(state)) {
40254027
PyErr_SetString(UnpicklingError, "state is not a dictionary");
@@ -4029,7 +4031,19 @@ load_build(UnpicklerObject *self)
40294031
if (dict == NULL)
40304032
goto error;
40314033

4032-
PyDict_Update(dict, state);
4034+
i = 0;
4035+
while (PyDict_Next(state, &i, &d_key, &d_value)) {
4036+
/* normally the keys for instance attributes are
4037+
interned. we should try to do that here. */
4038+
Py_INCREF(d_key);
4039+
if (PyUnicode_CheckExact(d_key))
4040+
PyUnicode_InternInPlace(&d_key);
4041+
if (PyObject_SetItem(dict, d_key, d_value) < 0) {
4042+
Py_DECREF(d_key);
4043+
goto error;
4044+
}
4045+
Py_DECREF(d_key);
4046+
}
40334047
Py_DECREF(dict);
40344048
}
40354049

0 commit comments

Comments
 (0)