3.와 4. 모두 모든 Python 버전에서 구문 오류 여야 합니다. 그러나 Python 버전 2.5-3.4에 영향을 미치는 버그를 발견했으며 이후 에 Python 문제 추적기에 게시되었습니다 . 버그로 인해 괄호로 묶지 않은 생성기 표현식이 *args
및 / 또는 만 동반 된 경우 함수에 대한 인수로 허용되었습니다 **kwargs
. Python 2.6+는 케이스 3과 4를 모두 허용했지만 Python 2.5는 케이스 3 만 허용했지만 둘 다 문서화 된 문법 에 위배되었습니다 .
call ::= primary "(" [argument_list [","]
| expression genexpr_for] ")"
즉, 문서를 말한다의 함수 호출 단계는 primary
, 괄호로 이어 (a 호출 평가가 표현) 중 인수 목록 또는 단지 호로 -이지 발생기 식; 인수 목록 내에서 모든 생성기 표현식은 괄호 안에 있어야합니다.
이 버그는 (알려지지 않은 것처럼 보이지만) Python 3.5 프리 릴리즈에서 수정되었습니다. 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 for i in [42], *a)
File "<stdin>", line 1
SyntaxError: Generator expression must be parenthesized if not sole argument
이 버그는 DeTeReR이 발견 한 덕분 에 Python 3.5의 새로운 기능에 문서화되었습니다 .
버그 분석
다음 과 같은 키워드 인수를 사용할 수 있도록 *args
Python 2.6이 변경 되었습니다 .
함수 호출에 * args 인수 뒤에 키워드 인수를 제공하는 것도 합법적입니다.
>>> def f(*args, **kw):
... print args, kw
...
>>> f(1,2,3, *(4,5,6), keyword=13)
(1, 2, 3, 4, 5, 6) {'keyword': 13}
이전에는 이것은 구문 오류였습니다. (Amaury Forgeot d' Arc 기고; 3473 호)
그러나 Python 2.6 문법 은 키워드 인수, 위치 인수 또는 베어 생성기 표현식을 구분하지 않습니다. 모두 argument
파서에 대한 유형 입니다.
Python 규칙에 따라 생성기 표현식이 함수에 대한 유일한 인수가 아닌 경우 괄호로 묶어야합니다. 이것은에서 확인됩니다 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;
}
그러나이 함수는 전혀 고려 하지 않습니다.*args
특히 일반적인 위치 인수와 키워드 인수 만 찾습니다.
동일한 함수에서 더 아래 로 키워드 arg 뒤에 비 키워드 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;
}
...
그러나 이것은 다음 명령문에 의해 입증 된 것처럼 괄호로 묶이지 않은 생성기 표현식 이 아닌 인수에 다시 적용됩니다 .else if
else if (TYPE(CHILD(ch, 1)) == gen_for) {
e = ast_for_genexp(c, ch);
if (!e)
return NULL;
asdl_seq_SET(args, nargs++, e);
}
따라서 괄호로 묶지 않은 생성기 표현식은 통과가 허용되었습니다.
이제 Python 3.5 *args
에서는 함수 호출 의 어느 곳에서나 사용할 수 있으므로 이를 수용하기 위해 문법 이 변경되었습니다.
arglist: argument (',' argument)* [',']
과
argument: ( test [comp_for] |
test '=' test |
'**' test |
'*' test )
상기 for
루프는 변경된 에
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++;
}
}
따라서 버그를 수정합니다.
그러나 우연한 변화는 유효한 보이는 구조가
func(i for i in [42], *args)
과
func(i for i in [42], **kwargs)
괄호로 묶지 않은 생성기가 선행 *args
하거나 **kwargs
현재 작동을 멈춘 곳.
이 버그를 찾기 위해 다양한 Python 버전을 시도했습니다. 2.5에서는 다음을 얻을 수 있습니다 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])
그리고 이것은 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
그러나 괄호로 묶인 생성기 표현식은 Python 3.5에서 작동하지만 Python 3.4에서는 작동하지 않습니다.
f(*[1], (2 for x in [2]))
그리고 이것이 단서입니다. Python 3.5에서는 *splatting
일반화됩니다. 함수 호출의 어느 곳에서나 사용할 수 있습니다.
>>> print(*range(5), 42)
0 1 2 3 4 42
따라서 실제 버그 ( *star
괄호없이 작동하는 생성기 ) 는 실제로 Python 3.5에서 수정되었으며, 버그는 Python 3.4와 3.5 사이에서 변경된 점에서 발견 될 수 있습니다.
f((*[2, 3]), 1)
구문 오류가*
있습니다. 제안 사항을 더 자세히 설명해 주시겠습니까? 또한 질문은 "어떻게 작동 하는가"가 아니라 "왜 이렇게 작동 하는가?"입니다.