Issue #18896: Python function can now have more than 255 parameters.
collections.namedtuple() now supports tuples with more than 255 elements.
This commit is contained in:
parent
14d8b9693b
commit
5bb8b9134b
|
@ -75,8 +75,9 @@ New Features
|
||||||
Other Language Changes
|
Other Language Changes
|
||||||
======================
|
======================
|
||||||
|
|
||||||
* More than 255 arguments can now be passed to a function.
|
* More than 255 arguments can now be passed to a function, and a function can
|
||||||
(Contributed by Serhiy Storchaka in :issue:`12844`.)
|
now have more than 255 parameters.
|
||||||
|
(Contributed by Serhiy Storchaka in :issue:`12844` and :issue:`18896`.)
|
||||||
|
|
||||||
|
|
||||||
New Modules
|
New Modules
|
||||||
|
|
|
@ -37,7 +37,7 @@ typedef struct {
|
||||||
for tracebacks and debuggers; otherwise, constant de-duplication
|
for tracebacks and debuggers; otherwise, constant de-duplication
|
||||||
would collapse identical functions/lambdas defined on different lines.
|
would collapse identical functions/lambdas defined on different lines.
|
||||||
*/
|
*/
|
||||||
unsigned char *co_cell2arg; /* Maps cell vars which are arguments. */
|
Py_ssize_t *co_cell2arg; /* Maps cell vars which are arguments. */
|
||||||
PyObject *co_filename; /* unicode (where it was loaded from) */
|
PyObject *co_filename; /* unicode (where it was loaded from) */
|
||||||
PyObject *co_name; /* unicode (name, for reference) */
|
PyObject *co_name; /* unicode (name, for reference) */
|
||||||
PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) See
|
PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) See
|
||||||
|
@ -84,9 +84,8 @@ typedef struct {
|
||||||
#define CO_FUTURE_GENERATOR_STOP 0x80000
|
#define CO_FUTURE_GENERATOR_STOP 0x80000
|
||||||
|
|
||||||
/* This value is found in the co_cell2arg array when the associated cell
|
/* This value is found in the co_cell2arg array when the associated cell
|
||||||
variable does not correspond to an argument. The maximum number of
|
variable does not correspond to an argument. */
|
||||||
arguments is 255 (indexed up to 254), so 255 work as a special flag.*/
|
#define CO_CELL_NOT_AN_ARG (-1)
|
||||||
#define CO_CELL_NOT_AN_ARG 255
|
|
||||||
|
|
||||||
/* This should be defined if a future statement modifies the syntax.
|
/* This should be defined if a future statement modifies the syntax.
|
||||||
For example, when a keyword is added.
|
For example, when a keyword is added.
|
||||||
|
|
|
@ -319,8 +319,7 @@ class TestNamedTuple(unittest.TestCase):
|
||||||
self.assertEqual(Dot(1)._replace(d=999), (999,))
|
self.assertEqual(Dot(1)._replace(d=999), (999,))
|
||||||
self.assertEqual(Dot(1)._fields, ('d',))
|
self.assertEqual(Dot(1)._fields, ('d',))
|
||||||
|
|
||||||
# n = 5000
|
n = 5000
|
||||||
n = 254 # SyntaxError: more than 255 arguments:
|
|
||||||
names = list(set(''.join([choice(string.ascii_letters)
|
names = list(set(''.join([choice(string.ascii_letters)
|
||||||
for j in range(10)]) for i in range(n)))
|
for j in range(10)]) for i in range(n)))
|
||||||
n = len(names)
|
n = len(names)
|
||||||
|
|
|
@ -401,16 +401,9 @@ if 1:
|
||||||
self.assertNotIn((Ellipsis, Ellipsis), d)
|
self.assertNotIn((Ellipsis, Ellipsis), d)
|
||||||
|
|
||||||
def test_annotation_limit(self):
|
def test_annotation_limit(self):
|
||||||
# 16 bits are available for # of annotations, but only 8 bits are
|
# more than 255 annotations, should compile ok
|
||||||
# available for the parameter count, hence 255
|
|
||||||
# is the max. Ensure the result of too many annotations is a
|
|
||||||
# SyntaxError.
|
|
||||||
s = "def f(%s): pass"
|
s = "def f(%s): pass"
|
||||||
s %= ', '.join('a%d:%d' % (i,i) for i in range(256))
|
s %= ', '.join('a%d:%d' % (i,i) for i in range(300))
|
||||||
self.assertRaises(SyntaxError, compile, s, '?', 'exec')
|
|
||||||
# Test that the max # of annotations compiles.
|
|
||||||
s = "def f(%s): pass"
|
|
||||||
s %= ', '.join('a%d:%d' % (i,i) for i in range(255))
|
|
||||||
compile(s, '?', 'exec')
|
compile(s, '?', 'exec')
|
||||||
|
|
||||||
def test_mangling(self):
|
def test_mangling(self):
|
||||||
|
|
|
@ -51,24 +51,12 @@ class KeywordOnlyArgTestCase(unittest.TestCase):
|
||||||
self.assertRaisesSyntaxError("def f(p, *, (k1, k2), **kw):\n pass\n")
|
self.assertRaisesSyntaxError("def f(p, *, (k1, k2), **kw):\n pass\n")
|
||||||
|
|
||||||
def testSyntaxForManyArguments(self):
|
def testSyntaxForManyArguments(self):
|
||||||
fundef = "def f("
|
# more than 255 positional arguments, should compile ok
|
||||||
for i in range(255):
|
fundef = "def f(%s):\n pass\n" % ', '.join('i%d' % i for i in range(300))
|
||||||
fundef += "i%d, "%i
|
compile(fundef, "<test>", "single")
|
||||||
fundef += "*, key=100):\n pass\n"
|
# more than 255 keyword-only arguments, should compile ok
|
||||||
self.assertRaisesSyntaxError(fundef)
|
fundef = "def f(*, %s):\n pass\n" % ', '.join('i%d' % i for i in range(300))
|
||||||
|
compile(fundef, "<test>", "single")
|
||||||
fundef2 = "def foo(i,*,"
|
|
||||||
for i in range(255):
|
|
||||||
fundef2 += "i%d, "%i
|
|
||||||
fundef2 += "lastarg):\n pass\n"
|
|
||||||
self.assertRaisesSyntaxError(fundef2)
|
|
||||||
|
|
||||||
# exactly 255 arguments, should compile ok
|
|
||||||
fundef3 = "def f(i,*,"
|
|
||||||
for i in range(253):
|
|
||||||
fundef3 += "i%d, "%i
|
|
||||||
fundef3 += "lastarg):\n pass\n"
|
|
||||||
compile(fundef3, "<test>", "single")
|
|
||||||
|
|
||||||
def testTooManyPositionalErrorMessage(self):
|
def testTooManyPositionalErrorMessage(self):
|
||||||
def f(a, b=None, *, c=None):
|
def f(a, b=None, *, c=None):
|
||||||
|
|
|
@ -926,7 +926,7 @@ class SizeofTest(unittest.TestCase):
|
||||||
def inner():
|
def inner():
|
||||||
return x
|
return x
|
||||||
return inner
|
return inner
|
||||||
check(get_cell2.__code__, size('6i13P') + 1)
|
check(get_cell2.__code__, size('6i13P') + calcsize('n'))
|
||||||
# complex
|
# complex
|
||||||
check(complex(0,1), size('2d'))
|
check(complex(0,1), size('2d'))
|
||||||
# method_descriptor (descriptor object)
|
# method_descriptor (descriptor object)
|
||||||
|
|
|
@ -10,6 +10,9 @@ What's New in Python 3.7.0 alpha 1
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #18896: Python function can now have more than 255 parameters.
|
||||||
|
collections.namedtuple() now supports tuples with more than 255 elements.
|
||||||
|
|
||||||
- Issue #26919: On Android, operating system data is now always encoded/decoded
|
- Issue #26919: On Android, operating system data is now always encoded/decoded
|
||||||
to/from UTF-8, instead of the locale encoding to avoid inconsistencies with
|
to/from UTF-8, instead of the locale encoding to avoid inconsistencies with
|
||||||
os.fsencode() and os.fsdecode() which are already using UTF-8.
|
os.fsencode() and os.fsdecode() which are already using UTF-8.
|
||||||
|
|
|
@ -110,7 +110,7 @@ PyCode_New(int argcount, int kwonlyargcount,
|
||||||
PyObject *lnotab)
|
PyObject *lnotab)
|
||||||
{
|
{
|
||||||
PyCodeObject *co;
|
PyCodeObject *co;
|
||||||
unsigned char *cell2arg = NULL;
|
Py_ssize_t *cell2arg = NULL;
|
||||||
Py_ssize_t i, n_cellvars;
|
Py_ssize_t i, n_cellvars;
|
||||||
|
|
||||||
/* Check argument types */
|
/* Check argument types */
|
||||||
|
@ -142,19 +142,25 @@ PyCode_New(int argcount, int kwonlyargcount,
|
||||||
if (n_cellvars) {
|
if (n_cellvars) {
|
||||||
Py_ssize_t total_args = argcount + kwonlyargcount +
|
Py_ssize_t total_args = argcount + kwonlyargcount +
|
||||||
((flags & CO_VARARGS) != 0) + ((flags & CO_VARKEYWORDS) != 0);
|
((flags & CO_VARARGS) != 0) + ((flags & CO_VARKEYWORDS) != 0);
|
||||||
Py_ssize_t alloc_size = sizeof(unsigned char) * n_cellvars;
|
|
||||||
bool used_cell2arg = false;
|
bool used_cell2arg = false;
|
||||||
cell2arg = PyMem_MALLOC(alloc_size);
|
cell2arg = PyMem_NEW(Py_ssize_t, n_cellvars);
|
||||||
if (cell2arg == NULL)
|
if (cell2arg == NULL) {
|
||||||
|
PyErr_NoMemory();
|
||||||
return NULL;
|
return NULL;
|
||||||
memset(cell2arg, CO_CELL_NOT_AN_ARG, alloc_size);
|
}
|
||||||
/* Find cells which are also arguments. */
|
/* Find cells which are also arguments. */
|
||||||
for (i = 0; i < n_cellvars; i++) {
|
for (i = 0; i < n_cellvars; i++) {
|
||||||
Py_ssize_t j;
|
Py_ssize_t j;
|
||||||
PyObject *cell = PyTuple_GET_ITEM(cellvars, i);
|
PyObject *cell = PyTuple_GET_ITEM(cellvars, i);
|
||||||
|
cell2arg[i] = CO_CELL_NOT_AN_ARG;
|
||||||
for (j = 0; j < total_args; j++) {
|
for (j = 0; j < total_args; j++) {
|
||||||
PyObject *arg = PyTuple_GET_ITEM(varnames, j);
|
PyObject *arg = PyTuple_GET_ITEM(varnames, j);
|
||||||
if (!PyUnicode_Compare(cell, arg)) {
|
int cmp = PyUnicode_Compare(cell, arg);
|
||||||
|
if (cmp == -1 && PyErr_Occurred()) {
|
||||||
|
PyMem_FREE(cell2arg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (cmp == 0) {
|
||||||
cell2arg[i] = j;
|
cell2arg[i] = j;
|
||||||
used_cell2arg = true;
|
used_cell2arg = true;
|
||||||
break;
|
break;
|
||||||
|
@ -449,7 +455,7 @@ code_sizeof(PyCodeObject *co, void *unused)
|
||||||
|
|
||||||
res = _PyObject_SIZE(Py_TYPE(co));
|
res = _PyObject_SIZE(Py_TYPE(co));
|
||||||
if (co->co_cell2arg != NULL && co->co_cellvars != NULL)
|
if (co->co_cell2arg != NULL && co->co_cellvars != NULL)
|
||||||
res += PyTuple_GET_SIZE(co->co_cellvars) * sizeof(unsigned char);
|
res += PyTuple_GET_SIZE(co->co_cellvars) * sizeof(Py_ssize_t);
|
||||||
return PyLong_FromSsize_t(res);
|
return PyLong_FromSsize_t(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1411,11 +1411,6 @@ ast_for_arguments(struct compiling *c, const node *n)
|
||||||
if (!kwdefaults && nkwonlyargs)
|
if (!kwdefaults && nkwonlyargs)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (nposargs + nkwonlyargs > 255) {
|
|
||||||
ast_error(c, n, "more than 255 arguments");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* tfpdef: NAME [':' test]
|
/* tfpdef: NAME [':' test]
|
||||||
vfpdef: NAME
|
vfpdef: NAME
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4100,7 +4100,7 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
|
||||||
vars into frame. */
|
vars into frame. */
|
||||||
for (i = 0; i < PyTuple_GET_SIZE(co->co_cellvars); ++i) {
|
for (i = 0; i < PyTuple_GET_SIZE(co->co_cellvars); ++i) {
|
||||||
PyObject *c;
|
PyObject *c;
|
||||||
int arg;
|
Py_ssize_t arg;
|
||||||
/* Possibly account for the cell variable being an argument. */
|
/* Possibly account for the cell variable being an argument. */
|
||||||
if (co->co_cell2arg != NULL &&
|
if (co->co_cell2arg != NULL &&
|
||||||
(arg = co->co_cell2arg[i]) != CO_CELL_NOT_AN_ARG) {
|
(arg = co->co_cell2arg[i]) != CO_CELL_NOT_AN_ARG) {
|
||||||
|
|
Loading…
Reference in New Issue