함수 인수로 생성기
왜 생성기를 함수에 대한 유일한 위치 인수로 전달하는 데 특별한 규칙이있는 것처럼 보이는지 설명 할 수 있습니까?
우리가 가지고있는 경우 :
>>> def f(*args):
>>> print "Success!"
>>> print args
예상대로 작동합니다.
>>> f(1, *[2]) Success! (1, 2)
예상대로 작동하지 않습니다.
>>> f(*[2], 1) File "<stdin>", line 1 SyntaxError: only named arguments may follow *expression
예상대로 작동합니다.
>>> f(1 for x in [1], *[2]) Success! (generator object <genexpr> at 0x7effe06bdcd0>, 2)
이것은 작동하지만 이유를 이해하지 못합니다. 2)와 같은 방식으로 실패하지 않아야합니다.
>>> f(*[2], 1 for x in [1]) Success! (generator object <genexpr> at 0x7effe06bdcd0>, 2)
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
현재 작동을 멈춘 곳.
To locate this bug, I tried various Python versions. In 2.5 you'd get 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])
And this was fixed before some prerelease of 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
However, the parenthesized generator expression, it works in Python 3.5, but it does not work not in Python 3.4:
f(*[1], (2 for x in [2]))
And this is the clue. In Python 3.5 the *splatting
is generalized; you can use it anywhere in a function call:
>>> print(*range(5), 42)
0 1 2 3 4 42
So the actual bug (generator working with *star
without parentheses) was indeed fixed in Python 3.5, and the bug could be found in that what changed between Python 3.4 and 3.5
참고URL : https://stackoverflow.com/questions/32521140/generator-as-function-argument
'programing tip' 카테고리의 다른 글
HTML5의 GeoLocation은 정확히 어떻게 작동합니까? (0) | 2020.10.06 |
---|---|
포함 된 컨테이너가있는 실행 가능한 jar와 전쟁 파일 배포에 대한 조언 (0) | 2020.10.06 |
파이썬에서 목록을 dict 키로 사용할 수없는 이유는 무엇입니까? (0) | 2020.10.06 |
webRTC 및 서버 기반 피어 연결을 사용하여 웹캠 및 오디오를 녹음하는 방법 (0) | 2020.10.06 |
Amazon EC2 : 기존 PV AMI를 HVM으로 변환하는 방법 (0) | 2020.10.06 |