파이썬 3.4에서는 다음을 입력합니다.
[] = ""
잘 작동하고 예외가 발생하지 않습니다. 물론 나중에 []
같지는 않지만 ""
.
[] = ()
또한 잘 작동합니다.
"" = []
예상대로 예외가 발생합니다.
() = ""
그래도 예상대로 예외가 발생합니다. 그래서 무슨 일이야?
답변
평등을 비교하는 것이 아닙니다. 을 할당하고 있습니다.
Python을 사용하면 여러 대상에 할당 할 수 있습니다.
foo, bar = 1, 2
두 값을 각각 foo
및에 할당합니다 bar
. 필요한 것은 오른쪽에 시퀀스 또는 반복 가능 하고 왼쪽에 이름 목록 또는 튜플뿐입니다.
당신이 할 때 :
[] = ""
빈 시퀀스 (빈 문자열은 여전히 시퀀스 임)를 빈 이름 목록에 할당했습니다 .
본질적으로 다음과 같은 작업을 수행합니다.
[foo, bar, baz] = "abc"
foo = "a"
, bar = "b"
및 baz = "c"
로 끝나지만 더 적은 문자로 끝납니다 .
그러나 문자열에 할당 할 수 없으므로 할당 ""
의 왼쪽은 작동하지 않으며 항상 구문 오류입니다.
지정 문 문서를 참조하십시오 .
할당 문은 식 목록을 평가하고 (단일 식 또는 쉼표로 구분 된 목록 일 수 있으며 후자는 튜플을 생성 함) 단일 결과 개체를 각 대상 목록에 왼쪽에서 오른쪽으로 할당합니다.
과
선택적으로 괄호 또는 대괄호로 묶인 대상 목록에 대한 개체 할당은 다음과 같이 재귀 적으로 정의됩니다.
내 강조 .
파이썬이 빈 목록에 대한 구문 오류를 던지지 않는다는 것은 실제로 약간의 버그입니다! 공식적으로 문서화 된 문법은 빈 대상 목록을 허용하지 않으며 비어 ()
있는 경우 오류가 발생합니다. bug 23275 참조 ; 무해한 버그로 간주됩니다.
시작점은 이것이 매우 오랫동안 존재했으며 무해하다는 것을 인식하는 것입니다.
또한 빈 목록에 할당하는 것이 유효하지만 빈 튜플에는 할당하지 않는 이유를 참조하십시오 .
답변
문서 의 할당 문 섹션 규칙을 따릅니다.
assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)
(가) 경우
target list
대상의 쉼표로 구분 된 목록이다 : 이 대상 목록 대상이며, 해당 대상으로, 왼쪽에서 오른쪽으로 항목이 할당됨에 따라 개체 동일한 항목 수와 반복 가능해야한다.개체는 대상 목록에있는 대상과 동일한 수의 항목을 가진 시퀀스 여야하며 항목은 왼쪽에서 오른쪽으로 해당 대상에 할당됩니다.
그래서 당신이 말할 때
[] = ""
""
이터 러블 (유효한 파이썬 문자열은 이터 러블)이며 목록의 요소에 대해 압축이 풀립니다.
예를 들면
>>> [a, b, c] = "123"
>>> a, b, c
('1', '2', '3')
빈 문자열과 빈 목록이 있으므로 압축을 풀 필요가 없습니다. 따라서 오류가 없습니다.
그러나 이것을 시도하십시오
>>> [] = "1"
Traceback (most recent call last):
File "<input>", line 1, in <module>
ValueError: too many values to unpack (expected 0)
>>> [a] = ""
Traceback (most recent call last):
File "<input>", line 1, in <module>
ValueError: need more than 0 values to unpack
이 [] = "1"
경우 "1"
빈 변수 목록 에서 문자열의 압축을 풀려고 합니다. 따라서 “압축을 풀기에 너무 많은 값 (0이 예상 됨)”이라고 불평합니다.
같은 방식으로, [a] = ""
빈 문자열이있어서 실제로 압축을 풀지 않지만 하나의 변수에 대해 압축을 풀고 있습니다. 다시 말하면 불가능합니다. 이것이 “포장을 풀려면 0 개 이상의 값이 필요하다”고 불평하는 이유입니다.
그 외에는 아시다시피
>>> [] = ()
()
빈 튜플 이기 때문에 오류도 발생하지 않습니다 .
>>> ()
()
>>> type(())
<class 'tuple'>
빈 목록을 통해 압축을 풀면 압축을 풀 수 없습니다. 그래서 오류가 없습니다.
그러나 당신이 할 때
>>> "" = []
File "<input>", line 1
SyntaxError: can't assign to literal
>>> "" = ()
File "<input>", line 1
SyntaxError: can't assign to literal
오류 메시지에서 알 수 있듯이 문자열 리터럴에 할당하려고합니다. 불가능합니다. 이것이 오류가 발생하는 이유입니다. 그것은 말하는 것과 같습니다
>>> 1 = "one"
File "<input>", line 1
SyntaxError: can't assign to literal
내부
내부적으로이 할당 작업은 UNPACK_SEQUENCE
op 코드 로 변환됩니다 .
>>> dis(compile('[] = ""', "string", "exec"))
1 0 LOAD_CONST 0 ('')
3 UNPACK_SEQUENCE 0
6 LOAD_CONST 1 (None)
여기에서는 문자열이 비어 있으므로 시간을 UNPACK_SEQUENCE
압축 해제 0
합니다. 근데 이런게 있으면
>>> dis(compile('[a, b, c] = "123"', "string", "exec"))
1 0 LOAD_CONST 0 ('123')
3 UNPACK_SEQUENCE 3
6 STORE_NAME 0 (a)
9 STORE_NAME 1 (b)
12 STORE_NAME 2 (c)
15 LOAD_CONST 1 (None)
18 RETURN_VALUE
시퀀스 123
는 오른쪽에서 왼쪽으로 스택에 압축 해제됩니다. 따라서 스택의 맨 위는 1
이고 다음은 2
이고 마지막은 3
. 그런 다음 스택의 맨 위에서 왼쪽 표현식의 변수에 하나씩 할당합니다.
BTW, Python에서 이것은 동일한 표현식에서 여러 할당을 수행하는 방법입니다. 예를 들면
a, b, c, d, e, f = u, v, w, x, y, z
이것은 오른쪽 값이 튜플을 구성하는 데 사용 된 다음 왼쪽 값 위에 압축이 풀리기 때문에 작동합니다.
>>> dis(compile('a, b, c, d, e, f = u, v, w, x, y, z', "string", "exec"))
1 0 LOAD_NAME 0 (u)
3 LOAD_NAME 1 (v)
6 LOAD_NAME 2 (w)
9 LOAD_NAME 3 (x)
12 LOAD_NAME 4 (y)
15 LOAD_NAME 5 (z)
18 BUILD_TUPLE 6
21 UNPACK_SEQUENCE 6
24 STORE_NAME 6 (a)
27 STORE_NAME 7 (b)
30 STORE_NAME 8 (c)
33 STORE_NAME 9 (d)
36 STORE_NAME 10 (e)
39 STORE_NAME 11 (f)
42 LOAD_CONST 0 (None)
45 RETURN_VALUE
그러나 고전적인 스와핑 기술 a, b = b, a
은 스택 상단에있는 요소의 회전을 사용합니다. 두 개 또는 세 개의 요소 만있는 경우 튜플을 구성하고 압축을 푸는 대신 특수 ROT_TWO
및 ROT_THREE
지침으로 처리됩니다 .
>>> dis(compile('a, b = b, a', "string", "exec"))
1 0 LOAD_NAME 0 (b)
3 LOAD_NAME 1 (a)
6 ROT_TWO
7 STORE_NAME 1 (a)
10 STORE_NAME 0 (b)
13 LOAD_CONST 0 (None)
16 RETURN_VALUE