diff --git a/Lib/pickle.py b/Lib/pickle.py index faa8fd7e557..350d4a46c06 100644 --- a/Lib/pickle.py +++ b/Lib/pickle.py @@ -674,7 +674,10 @@ class _Pickler: else: self.write(LONG4 + pack(">> dis(pickle.dumps(x, 1)) diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py index 243bc94ee49..bf6116b2dfb 100644 --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -1821,7 +1821,7 @@ class AbstractPickleTests(unittest.TestCase): with self.subTest(proto=proto): s = self.dumps(x, proto) if proto < 1: - self.assertIn(b'\nL64206', s) # LONG + self.assertIn(b'\nI64206', s) # INT else: self.assertIn(b'M\xce\xfa', s) # BININT2 self.assertEqual(opcode_in_pickle(pickle.NEWOBJ, s), @@ -1837,7 +1837,7 @@ class AbstractPickleTests(unittest.TestCase): with self.subTest(proto=proto): s = self.dumps(x, proto) if proto < 1: - self.assertIn(b'\nL64206', s) # LONG + self.assertIn(b'\nI64206', s) # INT elif proto < 2: self.assertIn(b'M\xce\xfa', s) # BININT2 elif proto < 4: @@ -1857,7 +1857,7 @@ class AbstractPickleTests(unittest.TestCase): with self.subTest(proto=proto): s = self.dumps(x, proto) if proto < 1: - self.assertIn(b'\nL64206', s) # LONG + self.assertIn(b'\nI64206', s) # INT elif proto < 2: self.assertIn(b'M\xce\xfa', s) # BININT2 elif proto < 4: diff --git a/Misc/NEWS.d/next/Library/2017-11-15-19-04-22.bpo-32037.r8-5Nk.rst b/Misc/NEWS.d/next/Library/2017-11-15-19-04-22.bpo-32037.r8-5Nk.rst new file mode 100644 index 00000000000..d077d0e2110 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2017-11-15-19-04-22.bpo-32037.r8-5Nk.rst @@ -0,0 +1,4 @@ +Integers that fit in a signed 32-bit integer will be now pickled with +protocol 0 using the INT opcode. This will decrease the size of a pickle, +speed up pickling and unpickling, and make these integers be unpickled as +int instances in Python 2. diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 4b7f1ed66b3..943c70112b7 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -1858,18 +1858,13 @@ save_long(PicklerObject *self, PyObject *obj) PyObject *repr = NULL; Py_ssize_t size; long val; + int overflow; int status = 0; - const char long_op = LONG; - - val= PyLong_AsLong(obj); - if (val == -1 && PyErr_Occurred()) { - /* out of range for int pickling */ - PyErr_Clear(); - } - else if (self->bin && - (sizeof(long) <= 4 || - (val <= 0x7fffffffL && val >= (-0x7fffffffL - 1)))) { + val= PyLong_AsLongAndOverflow(obj, &overflow); + if (!overflow && (sizeof(long) <= 4 || + (val <= 0x7fffffffL && val >= (-0x7fffffffL - 1)))) + { /* result fits in a signed 4-byte integer. Note: we can't use -0x80000000L in the above condition because some @@ -1882,31 +1877,35 @@ save_long(PicklerObject *self, PyObject *obj) char pdata[32]; Py_ssize_t len = 0; - pdata[1] = (unsigned char)(val & 0xff); - pdata[2] = (unsigned char)((val >> 8) & 0xff); - pdata[3] = (unsigned char)((val >> 16) & 0xff); - pdata[4] = (unsigned char)((val >> 24) & 0xff); + if (self->bin) { + pdata[1] = (unsigned char)(val & 0xff); + pdata[2] = (unsigned char)((val >> 8) & 0xff); + pdata[3] = (unsigned char)((val >> 16) & 0xff); + pdata[4] = (unsigned char)((val >> 24) & 0xff); - if ((pdata[4] == 0) && (pdata[3] == 0)) { - if (pdata[2] == 0) { - pdata[0] = BININT1; - len = 2; + if ((pdata[4] != 0) || (pdata[3] != 0)) { + pdata[0] = BININT; + len = 5; } - else { + else if (pdata[2] != 0) { pdata[0] = BININT2; len = 3; } + else { + pdata[0] = BININT1; + len = 2; + } } else { - pdata[0] = BININT; - len = 5; + sprintf(pdata, "%c%ld\n", INT, val); + len = strlen(pdata); } - if (_Pickler_Write(self, pdata, len) < 0) return -1; return 0; } + assert(!PyErr_Occurred()); if (self->proto >= 2) { /* Linear-time pickling. */ @@ -1986,6 +1985,7 @@ save_long(PicklerObject *self, PyObject *obj) goto error; } else { + const char long_op = LONG; const char *string; /* proto < 2: write the repr and newline. This is quadratic-time (in