[python] 빈 목록 (예 : [] =“”)에 할당하지 않는 이유는 무엇입니까?

파이썬 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_SEQUENCEop 코드 로 변환됩니다 .

>>> 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_TWOROT_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


답변