Tanto 3. como 4. deberían ser errores de sintaxis en todas las versiones de Python. Sin embargo, ha encontrado un error que afecta a las versiones 2.5 - 3.4 de Python y que posteriormente se publicó en el rastreador de problemas de Python . Debido al error, se aceptó una expresión generadora sin paréntesis como argumento para una función si estaba acompañada solo por *args
y / o **kwargs
. Mientras que Python 2.6+ permitía ambos casos 3. y 4., Python 2.5 solo permitía el caso 3. - sin embargo, ambos estaban en contra de la gramática documentada :
call ::= primary "(" [argument_list [","]
| expression genexpr_for] ")"
es decir, la documentación dice una llamada de función dispone de primary
(la expresión que se evalúa como una opción de rescate), seguidos por, entre paréntesis, o bien una lista de argumentos o sólo una expresión generador unparenthesized; y dentro de la lista de argumentos, todas las expresiones del generador deben estar entre paréntesis.
Este error (aunque parece que no se conocía), se había corregido en las versiones preliminares de Python 3.5. En Python 3.5 siempre se requieren paréntesis alrededor de una expresión generadora, a menos que sea el único argumento para la función:
Python 3.5.0a4+ (default:a3f2b171b765, May 19 2015, 16:14:41)
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> f(1 for i in [42], *a)
File "<stdin>", line 1
SyntaxError: Generator expression must be parenthesized if not sole argument
Esto ahora está documentado en Novedades de Python 3.5 , gracias a que DeTeReR detectó este error.
Análisis del error
Se realizó un cambio en Python 2.6 que permitió el uso de argumentos de palabras clave después de *args
:
También es legal proporcionar argumentos de palabras clave después de un argumento * args a una llamada de función.
>>> def f(*args, **kw):
... print args, kw
...
>>> f(1,2,3, *(4,5,6), keyword=13)
(1, 2, 3, 4, 5, 6) {'keyword': 13}
Anteriormente, esto habría sido un error de sintaxis. (Contribuido por Amaury Forgeot d'Arc; número 3473.)
Sin embargo, la gramática de Python 2.6 no hace ninguna distinción entre argumentos de palabras clave, argumentos posicionales o expresiones generadoras simples; todos son de tipo argument
para el analizador.
Según las reglas de Python, una expresión generadora debe estar entre paréntesis si no es el único argumento de la función. Esto está validado en Python/ast.c
:
for (i = 0; i < NCH(n); i++) {
node *ch = CHILD(n, i);
if (TYPE(ch) == argument) {
if (NCH(ch) == 1)
nargs++;
else if (TYPE(CHILD(ch, 1)) == gen_for)
ngens++;
else
nkeywords++;
}
}
if (ngens > 1 || (ngens && (nargs || nkeywords))) {
ast_error(n, "Generator expression must be parenthesized "
"if not sole argument");
return NULL;
}
Sin embargo, esta función no tiene en cuenta *args
en absoluto; específicamente, solo busca argumentos posicionales ordinarios y argumentos de palabras clave.
Más abajo en la misma función, hay un mensaje de error generado para arg que no son palabras clave después de la palabra clave arg :
if (TYPE(ch) == argument) {
expr_ty e;
if (NCH(ch) == 1) {
if (nkeywords) {
ast_error(CHILD(ch, 0),
"non-keyword arg after keyword arg");
return NULL;
}
...
Pero esto nuevamente se aplica a argumentos que no son expresiones generadoras sin paréntesis, como lo demuestra la else if
declaración :
else if (TYPE(CHILD(ch, 1)) == gen_for) {
e = ast_for_genexp(c, ch);
if (!e)
return NULL;
asdl_seq_SET(args, nargs++, e);
}
Por tanto, se permitió que pasara una expresión generadora sin paréntesis.
Ahora, en Python 3.5, se puede usar *args
en cualquier lugar de una llamada de función, por lo que se cambió la gramática para adaptarse a esto:
arglist: argument (',' argument)* [',']
y
argument: ( test [comp_for] |
test '=' test |
'**' test |
'*' test )
y el for
bucle se cambió a
for (i = 0; i < NCH(n); i++) {
node *ch = CHILD(n, i);
if (TYPE(ch) == argument) {
if (NCH(ch) == 1)
nargs++;
else if (TYPE(CHILD(ch, 1)) == comp_for)
ngens++;
else if (TYPE(CHILD(ch, 0)) == STAR)
nargs++;
else
/* TYPE(CHILD(ch, 0)) == DOUBLESTAR or keyword argument */
nkeywords++;
}
}
Arreglando así el error.
Sin embargo, el cambio inadvertido es que las construcciones de aspecto válido
func(i for i in [42], *args)
y
func(i for i in [42], **kwargs)
donde un generador sin paréntesis precede *args
o **kwargs
ahora dejó de funcionar.
Para localizar este error, probé varias versiones de Python. En 2.5 obtendrías SyntaxError
:
Python 2.5.5 (r255:77872, Nov 28 2010, 16:43:48)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> f(*[1], 2 for x in [2])
File "<stdin>", line 1
f(*[1], 2 for x in [2])
Y esto se solucionó antes de alguna versión preliminar de Python 3.5:
Python 3.5.0a4+ (default:a3f2b171b765, May 19 2015, 16:14:41)
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> f(*[1], 2 for x in [2])
File "<stdin>", line 1
SyntaxError: Generator expression must be parenthesized if not sole argument
Sin embargo, la expresión generadora entre paréntesis, funciona en Python 3.5, pero no funciona en Python 3.4:
f(*[1], (2 for x in [2]))
Y esta es la pista. En Python 3.5 el *splatting
está generalizado; puede usarlo en cualquier lugar en una llamada de función:
>>> print(*range(5), 42)
0 1 2 3 4 42
Entonces, el error real (el generador funciona *star
sin paréntesis) se corrigió en Python 3.5, y el error se pudo encontrar en lo que cambió entre Python 3.4 y 3.5
f((*[2, 3]), 1)
da un error de sintaxis en*
- ¿podría explicar más su sugerencia? Además, la pregunta no es "cómo hacer que funcione", sino "¿por qué funciona así?"