Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 12f4334

Browse files
bpo-41334: Convert constructors of str, bytes and bytearray to Argument Clinic (GH-21535)
1 parent e123012 commit 12f4334

9 files changed

Lines changed: 307 additions & 93 deletions

File tree

Doc/whatsnew/3.10.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ arguments passed to the Python executable.
121121
Optimizations
122122
=============
123123

124+
* Constructors :func:`str`, :func:`bytes` and :func:`bytearray` are now faster
125+
(around 30--40% for small objects).
126+
(Contributed by Serhiy Storchaka in :issue:`41334`.)
127+
124128
* The :mod:`runpy` module now imports fewer modules.
125129
The ``python3 -m module-name`` command startup time is 1.3x faster in
126130
average.

Lib/test/test_grammar.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -584,12 +584,14 @@ def d22v(a, b, c=1, d=2, *rest): pass
584584
d22v(1, *(2, 3), **{'d': 4})
585585

586586
# keyword argument type tests
587-
try:
588-
str('x', **{b'foo':1 })
589-
except TypeError:
590-
pass
591-
else:
592-
self.fail('Bytes should not work as keyword argument names')
587+
with warnings.catch_warnings():
588+
warnings.simplefilter('ignore', BytesWarning)
589+
try:
590+
str('x', **{b'foo':1 })
591+
except TypeError:
592+
pass
593+
else:
594+
self.fail('Bytes should not work as keyword argument names')
593595
# keyword only argument tests
594596
def pos0key1(*, key): return key
595597
pos0key1(key=100)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Constructors :func:`str`, :func:`bytes` and :func:`bytearray` are now faster
2+
(around 30--40% for small objects).

Objects/bytearrayobject.c

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -738,13 +738,20 @@ bytearray_ass_subscript(PyByteArrayObject *self, PyObject *index, PyObject *valu
738738
}
739739
}
740740

741+
/*[clinic input]
742+
bytearray.__init__
743+
744+
source as arg: object = NULL
745+
encoding: str = NULL
746+
errors: str = NULL
747+
748+
[clinic start generated code]*/
749+
741750
static int
742-
bytearray_init(PyByteArrayObject *self, PyObject *args, PyObject *kwds)
751+
bytearray___init___impl(PyByteArrayObject *self, PyObject *arg,
752+
const char *encoding, const char *errors)
753+
/*[clinic end generated code: output=4ce1304649c2f8b3 input=1141a7122eefd7b9]*/
743754
{
744-
static char *kwlist[] = {"source", "encoding", "errors", 0};
745-
PyObject *arg = NULL;
746-
const char *encoding = NULL;
747-
const char *errors = NULL;
748755
Py_ssize_t count;
749756
PyObject *it;
750757
PyObject *(*iternext)(PyObject *);
@@ -755,11 +762,6 @@ bytearray_init(PyByteArrayObject *self, PyObject *args, PyObject *kwds)
755762
return -1;
756763
}
757764

758-
/* Parse arguments */
759-
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oss:bytearray", kwlist,
760-
&arg, &encoding, &errors))
761-
return -1;
762-
763765
/* Make a quick exit if no first argument */
764766
if (arg == NULL) {
765767
if (encoding != NULL || errors != NULL) {
@@ -2354,7 +2356,7 @@ PyTypeObject PyByteArray_Type = {
23542356
0, /* tp_descr_get */
23552357
0, /* tp_descr_set */
23562358
0, /* tp_dictoffset */
2357-
(initproc)bytearray_init, /* tp_init */
2359+
(initproc)bytearray___init__, /* tp_init */
23582360
PyType_GenericAlloc, /* tp_alloc */
23592361
PyType_GenericNew, /* tp_new */
23602362
PyObject_Del, /* tp_free */

Objects/bytesobject.c

Lines changed: 40 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2580,24 +2580,27 @@ static PyNumberMethods bytes_as_number = {
25802580
};
25812581

25822582
static PyObject *
2583-
bytes_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
2583+
bytes_subtype_new(PyTypeObject *, PyObject *);
2584+
2585+
/*[clinic input]
2586+
@classmethod
2587+
bytes.__new__ as bytes_new
2588+
2589+
source as x: object = NULL
2590+
encoding: str = NULL
2591+
errors: str = NULL
2592+
2593+
[clinic start generated code]*/
25842594

25852595
static PyObject *
2586-
bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
2596+
bytes_new_impl(PyTypeObject *type, PyObject *x, const char *encoding,
2597+
const char *errors)
2598+
/*[clinic end generated code: output=1e0c471be311a425 input=f0a966d19b7262b4]*/
25872599
{
2588-
PyObject *x = NULL;
2589-
const char *encoding = NULL;
2590-
const char *errors = NULL;
2591-
PyObject *new = NULL;
2600+
PyObject *bytes;
25922601
PyObject *func;
25932602
Py_ssize_t size;
2594-
static char *kwlist[] = {"source", "encoding", "errors", 0};
25952603

2596-
if (type != &PyBytes_Type)
2597-
return bytes_subtype_new(type, args, kwds);
2598-
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oss:bytes", kwlist, &x,
2599-
&encoding, &errors))
2600-
return NULL;
26012604
if (x == NULL) {
26022605
if (encoding != NULL || errors != NULL) {
26032606
PyErr_SetString(PyExc_TypeError,
@@ -2606,78 +2609,73 @@ bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
26062609
"errors without a string argument");
26072610
return NULL;
26082611
}
2609-
return PyBytes_FromStringAndSize(NULL, 0);
2612+
bytes = PyBytes_FromStringAndSize(NULL, 0);
26102613
}
2611-
2612-
if (encoding != NULL) {
2614+
else if (encoding != NULL) {
26132615
/* Encode via the codec registry */
26142616
if (!PyUnicode_Check(x)) {
26152617
PyErr_SetString(PyExc_TypeError,
26162618
"encoding without a string argument");
26172619
return NULL;
26182620
}
2619-
new = PyUnicode_AsEncodedString(x, encoding, errors);
2620-
if (new == NULL)
2621-
return NULL;
2622-
assert(PyBytes_Check(new));
2623-
return new;
2621+
bytes = PyUnicode_AsEncodedString(x, encoding, errors);
26242622
}
2625-
2626-
if (errors != NULL) {
2623+
else if (errors != NULL) {
26272624
PyErr_SetString(PyExc_TypeError,
26282625
PyUnicode_Check(x) ?
26292626
"string argument without an encoding" :
26302627
"errors without a string argument");
26312628
return NULL;
26322629
}
2633-
26342630
/* We'd like to call PyObject_Bytes here, but we need to check for an
26352631
integer argument before deferring to PyBytes_FromObject, something
26362632
PyObject_Bytes doesn't do. */
2637-
func = _PyObject_LookupSpecial(x, &PyId___bytes__);
2638-
if (func != NULL) {
2639-
new = _PyObject_CallNoArg(func);
2633+
else if ((func = _PyObject_LookupSpecial(x, &PyId___bytes__)) != NULL) {
2634+
bytes = _PyObject_CallNoArg(func);
26402635
Py_DECREF(func);
2641-
if (new == NULL)
2636+
if (bytes == NULL)
26422637
return NULL;
2643-
if (!PyBytes_Check(new)) {
2638+
if (!PyBytes_Check(bytes)) {
26442639
PyErr_Format(PyExc_TypeError,
2645-
"__bytes__ returned non-bytes (type %.200s)",
2646-
Py_TYPE(new)->tp_name);
2647-
Py_DECREF(new);
2640+
"__bytes__ returned non-bytes (type %.200s)",
2641+
Py_TYPE(bytes)->tp_name);
2642+
Py_DECREF(bytes);
26482643
return NULL;
26492644
}
2650-
return new;
26512645
}
26522646
else if (PyErr_Occurred())
26532647
return NULL;
2654-
2655-
if (PyUnicode_Check(x)) {
2648+
else if (PyUnicode_Check(x)) {
26562649
PyErr_SetString(PyExc_TypeError,
26572650
"string argument without an encoding");
26582651
return NULL;
26592652
}
26602653
/* Is it an integer? */
2661-
if (_PyIndex_Check(x)) {
2654+
else if (_PyIndex_Check(x)) {
26622655
size = PyNumber_AsSsize_t(x, PyExc_OverflowError);
26632656
if (size == -1 && PyErr_Occurred()) {
26642657
if (!PyErr_ExceptionMatches(PyExc_TypeError))
26652658
return NULL;
26662659
PyErr_Clear(); /* fall through */
2660+
bytes = PyBytes_FromObject(x);
26672661
}
26682662
else {
26692663
if (size < 0) {
26702664
PyErr_SetString(PyExc_ValueError, "negative count");
26712665
return NULL;
26722666
}
2673-
new = _PyBytes_FromSize(size, 1);
2674-
if (new == NULL)
2675-
return NULL;
2676-
return new;
2667+
bytes = _PyBytes_FromSize(size, 1);
26772668
}
26782669
}
2670+
else {
2671+
bytes = PyBytes_FromObject(x);
2672+
}
2673+
2674+
if (bytes != NULL && type != &PyBytes_Type) {
2675+
Py_SETREF(bytes, bytes_subtype_new(type, bytes));
2676+
}
26792677

2680-
return PyBytes_FromObject(x);
2678+
return bytes;
26812679
}
26822680

26832681
static PyObject*
@@ -2889,15 +2887,12 @@ PyBytes_FromObject(PyObject *x)
28892887
}
28902888

28912889
static PyObject *
2892-
bytes_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
2890+
bytes_subtype_new(PyTypeObject *type, PyObject *tmp)
28932891
{
2894-
PyObject *tmp, *pnew;
2892+
PyObject *pnew;
28952893
Py_ssize_t n;
28962894

28972895
assert(PyType_IsSubtype(type, &PyBytes_Type));
2898-
tmp = bytes_new(&PyBytes_Type, args, kwds);
2899-
if (tmp == NULL)
2900-
return NULL;
29012896
assert(PyBytes_Check(tmp));
29022897
n = PyBytes_GET_SIZE(tmp);
29032898
pnew = type->tp_alloc(type, n);
@@ -2907,7 +2902,6 @@ bytes_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
29072902
((PyBytesObject *)pnew)->ob_shash =
29082903
((PyBytesObject *)tmp)->ob_shash;
29092904
}
2910-
Py_DECREF(tmp);
29112905
return pnew;
29122906
}
29132907

Objects/clinic/bytearrayobject.c.h

Lines changed: 70 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)