OSDir


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Python-Dev] The curious case of 255 function arguments


Hello Python Gurus,

TL;DR: 3.7 released functions having greater than 255 arguments.  Despite
explicit checks for this in 2.x, no such limit is actually imposed -- why?

In the 3.7 release notes "Other Language Changes" section (
https://docs.python.org/3.7/whatsnew/3.7.html#other-language-changes), the
first bullet point denotes

> More than 255 arguments can now be passed to a function, and a function
can now have more than 255 parameters. (Contributed by Serhiy Storchaka in
bpo-12844 <https://bugs.python.org/issue12844> and bpo-18896
<https://bugs.python.org/issue18896>.)

Now lets get something straight: unless I want to exclusively support
Python 3.7 or higher, I must make sure I obey the <255 rule.  Use *args //
**kwargs, etc.  I'm totally ok with that, 2020 is already here in my mind ;)

Curiosity is the reason I'm reaching out.  Upon further investigation and
some discussion with like-minded Python enthusiasts, the code being patched
by Serhiy Storchaka is present in e.g., Python 2.7 (
https://github.com/python/cpython/blob/2.7/Python/ast.c#L2013-L2016)

    if (nargs + nkeywords + ngens > 255) {
      ast_error(n, "more than 255 arguments");
      return NULL;
    }

Despite that code, as demonstrated with the supplemental output in the post
script, *no 2.x versions fail with >255 arguments*.  In contrast, 3.x where
x<7 all do fail (as expected) with a SyntaxError.  To test this, I tried
every minor release of python (excluding v1, arbitrarily choosing the
latest patch release of a minor version) with the following snippet via the
-c flag

    /path/to/pythonX.Y -c 'exec("def foo(" + ", ".join(["a" + str(i) for i
in range(1, 300)]) + "): pass")'

Which tries to construct a function

    def foo(a0, a1, ..., a299): pass

I've looked at the C code for a while and it is entirely non-obvious what
would lead to python *2* *allowing* >255 arguments.  Anybody happen to know
how / why the python *2* versions *succeed*?

Thank you for reading, this is not a problem, just a burning desire for
closure (even if anecdotal) as to how this can be.  I deeply love python,
and am not complaining!  I stumbled across this and found it truly
confounding, and thought the gurus here may happen to recall what changed
in 3.x that lead the the error condition actually being asserted :)

Sincerely,

Stephen McDowell

P.S. On a Fedora 25 box using GCC 6.4.1, I lovingly scripted the
installation of all the python versions just to see if it truly was a 2.x /
3.x divide.  The results of running `python -V` followed by the `python -c
'exec("def foo...")'` described above, with some extra prints for clarity
are as follows (script hackily thrown together in ~30minutes not included,
so as not to make your eyes bleed):

********************************************************************************
Python 2.0.1
==> Greater than 255 Arguments supported
********************************************************************************
Python 2.1.3
==> Greater than 255 Arguments supported
********************************************************************************
Python 2.2.3
==> Greater than 255 Arguments supported
********************************************************************************
Python 2.3.7
==> Greater than 255 Arguments supported
********************************************************************************
Python 2.4.6
==> Greater than 255 Arguments supported
********************************************************************************
Python 2.5.6
==> Greater than 255 Arguments supported
********************************************************************************
Python 2.6.9
==> Greater than 255 Arguments supported
********************************************************************************
Python 2.7.15
==> Greater than 255 Arguments supported
********************************************************************************
Python 3.0.1
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "<string>", line 1
SyntaxError: more than 255 arguments
********************************************************************************
Python 3.1.5
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "<string>", line 1
SyntaxError: more than 255 arguments
********************************************************************************
Python 3.2.6
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "<string>", line 1
SyntaxError: more than 255 arguments
********************************************************************************
Python 3.3.7
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "<string>", line 1
SyntaxError: more than 255 arguments
********************************************************************************
Python 3.4.9
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "<string>", line 1
SyntaxError: more than 255 arguments
********************************************************************************
Python 3.5.6
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "<string>", line 1
SyntaxError: more than 255 arguments
********************************************************************************
Python 3.6.6
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "<string>", line 1
SyntaxError: more than 255 arguments
********************************************************************************
Python 3.7.0
==> Greater than 255 Arguments supported

P.P.S. Seriously, I LOVE PYTHON <3  It was so easy to download, configure,
build, and install each of these versions, and run the test!  Thank you :)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20180805/9ddbc2f3/attachment.html>