다음 표현을 고려하십시오. 일부 표현식은 “컨텍스트”를 나타 내기 위해 반복됩니다.
(이것은 긴 목록입니다)
a, b = 1, 2 # simple sequence assignment
a, b = ['green', 'blue'] # list asqignment
a, b = 'XY' # string assignment
a, b = range(1,5,2) # any iterable will do
# nested sequence assignment
(a,b), c = "XY", "Z" # a = 'X', b = 'Y', c = 'Z'
(a,b), c = "XYZ" # ERROR -- too many values to unpack
(a,b), c = "XY" # ERROR -- need more than 1 value to unpack
(a,b), c, = [1,2],'this' # a = '1', b = '2', c = 'this'
(a,b), (c,) = [1,2],'this' # ERROR -- too many values to unpack
# extended sequence unpacking
a, *b = 1,2,3,4,5 # a = 1, b = [2,3,4,5]
*a, b = 1,2,3,4,5 # a = [1,2,3,4], b = 5
a, *b, c = 1,2,3,4,5 # a = 1, b = [2,3,4], c = 5
a, *b = 'X' # a = 'X', b = []
*a, b = 'X' # a = [], b = 'X'
a, *b, c = "XY" # a = 'X', b = [], c = 'Y'
a, *b, c = "X...Y" # a = 'X', b = ['.','.','.'], c = 'Y'
a, b, *c = 1,2,3 # a = 1, b = 2, c = [3]
a, b, c, *d = 1,2,3 # a = 1, b = 2, c = 3, d = []
a, *b, c, *d = 1,2,3,4,5 # ERROR -- two starred expressions in assignment
(a,b), c = [1,2],'this' # a = '1', b = '2', c = 'this'
(a,b), *c = [1,2],'this' # a = '1', b = '2', c = ['this']
(a,b), c, *d = [1,2],'this' # a = '1', b = '2', c = 'this', d = []
(a,b), *c, d = [1,2],'this' # a = '1', b = '2', c = [], d = 'this'
(a,b), (c, *d) = [1,2],'this' # a = '1', b = '2', c = 't', d = ['h', 'i', 's']
*a = 1 # ERROR -- target must be in a list or tuple
*a = (1,2) # ERROR -- target must be in a list or tuple
*a, = (1,2) # a = [1,2]
*a, = 1 # ERROR -- 'int' object is not iterable
*a, = [1] # a = [1]
*a = [1] # ERROR -- target must be in a list or tuple
*a, = (1,) # a = [1]
*a, = (1) # ERROR -- 'int' object is not iterable
*a, b = [1] # a = [], b = 1
*a, b = (1,) # a = [], b = 1
(a,b),c = 1,2,3 # ERROR -- too many values to unpack
(a,b), *c = 1,2,3 # ERROR - 'int' object is not iterable
(a,b), *c = 'XY', 2, 3 # a = 'X', b = 'Y', c = [2,3]
# extended sequence unpacking -- NESTED
(a,b),c = 1,2,3 # ERROR -- too many values to unpack
*(a,b), c = 1,2,3 # a = 1, b = 2, c = 3
*(a,b) = 1,2 # ERROR -- target must be in a list or tuple
*(a,b), = 1,2 # a = 1, b = 2
*(a,b) = 'XY' # ERROR -- target must be in a list or tuple
*(a,b), = 'XY' # a = 'X', b = 'Y'
*(a, b) = 'this' # ERROR -- target must be in a list or tuple
*(a, b), = 'this' # ERROR -- too many values to unpack
*(a, *b), = 'this' # a = 't', b = ['h', 'i', 's']
*(a, *b), c = 'this' # a = 't', b = ['h', 'i'], c = 's'
*(a,*b), = 1,2,3,3,4,5,6,7 # a = 1, b = [2, 3, 3, 4, 5, 6, 7]
*(a,*b), *c = 1,2,3,3,4,5,6,7 # ERROR -- two starred expressions in assignment
*(a,*b), (*c,) = 1,2,3,3,4,5,6,7 # ERROR -- 'int' object is not iterable
*(a,*b), c = 1,2,3,3,4,5,6,7 # a = 1, b = [2, 3, 3, 4, 5, 6], c = 7
*(a,*b), (*c,) = 1,2,3,4,5,'XY' # a = 1, b = [2, 3, 4, 5], c = ['X', 'Y']
*(a,*b), c, d = 1,2,3,3,4,5,6,7 # a = 1, b = [2, 3, 3, 4, 5], c = 6, d = 7
*(a,*b), (c, d) = 1,2,3,3,4,5,6,7 # ERROR -- 'int' object is not iterable
*(a,*b), (*c, d) = 1,2,3,3,4,5,6,7 # ERROR -- 'int' object is not iterable
*(a,*b), *(c, d) = 1,2,3,3,4,5,6,7 # ERROR -- two starred expressions in assignment
*(a,b), c = 'XY', 3 # ERROR -- need more than 1 value to unpack
*(*a,b), c = 'XY', 3 # a = [], b = 'XY', c = 3
(a,b), c = 'XY', 3 # a = 'X', b = 'Y', c = 3
*(a,b), c = 'XY', 3, 4 # a = 'XY', b = 3, c = 4
*(*a,b), c = 'XY', 3, 4 # a = ['XY'], b = 3, c = 4
(a,b), c = 'XY', 3, 4 # ERROR -- too many values to unpack
그러한 표현의 결과를 손으로 올바르게 추론하는 방법은 무엇입니까?
답변
이 게시물의 길이에 대해 죄송하지만 완전성을 선택하기로 결정했습니다.
몇 가지 기본 규칙을 알고 나면 일반화하는 것이 어렵지 않습니다. 몇 가지 예를 들어 설명하기 위해 최선을 다하겠습니다. 이러한 “손으로”평가하는 것에 대해 이야기하고 있으므로 몇 가지 간단한 대체 규칙을 제안하겠습니다. 기본적으로 모든 이터 러블이 동일한 방식으로 형식화되면 표현식을 이해하는 것이 더 쉬울 수 있습니다.
압축을 풀기 위해서만 다음 대체가 오른쪽에서 유효합니다 =
(예 : rvalues ).
'XY' -> ('X', 'Y')
['X', 'Y'] -> ('X', 'Y')
값의 압축이 풀리지 않는 경우 대체를 실행 취소합니다. (자세한 설명은 아래를 참조하십시오.)
또한 “네이 키드”쉼표가 표시되면 최상위 튜플이있는 것처럼 가장하십시오. 왼쪽과 오른쪽 모두에서이 작업을 수행합니다 (예 : lvalues 및 rvalues ).
'X', 'Y' -> ('X', 'Y')
a, b -> (a, b)
이러한 간단한 규칙을 염두에두고 몇 가지 예를 들면 다음과 같습니다.
(a,b), c = "XY", "Z" # a = 'X', b = 'Y', c = 'Z'
위의 규칙을 적용하여로 변환 "XY"
하고 ('X', 'Y')
괄호 안의 쉼표를 덮습니다.
((a, b), c) = (('X', 'Y'), 'Z')
여기의 시각적 일치는 할당이 어떻게 작동하는지 상당히 분명하게 만듭니다.
다음은 잘못된 예입니다.
(a,b), c = "XYZ"
위의 대체 규칙에 따라 다음과 같은 결과를 얻습니다.
((a, b), c) = ('X', 'Y', 'Z')
이것은 분명히 잘못된 것입니다. 중첩 된 구조가 일치하지 않습니다. 이제 약간 더 복잡한 예제에서 어떻게 작동하는지 살펴 보겠습니다.
(a,b), c, = [1,2],'this' # a = '1', b = '2', c = 'this'
위의 규칙을 적용하면
((a, b), c) = ((1, 2), ('t', 'h', 'i', 's'))
그러나 이제는 'this'
압축이 풀리지 않고 c
. 그래서 우리는 대체를 취소합니다.
((a, b), c) = ((1, 2), 'this')
이제 c
튜플을 래핑 할 때 어떤 일이 발생하는지 살펴 보겠습니다 .
(a,b), (c,) = [1,2],'this' # ERROR -- too many values to unpack
된다
((a, b), (c,)) = ((1, 2), ('t', 'h', 'i', 's'))
다시 말하지만 오류는 분명합니다. c
은 더 이상 네이 키드 변수가 아니라 시퀀스 내의 변수이므로 오른쪽에있는 해당 시퀀스가 (c,)
. 하지만 시퀀스의 길이가 다르기 때문에 오류가 있습니다.
이제 *
연산자를 사용하여 확장 된 포장을 풀 수 있습니다. 이것은 조금 더 복잡하지만 여전히 매우 간단합니다. 앞에 오는 변수 *
는 변수 이름에 할당되지 않은 해당 시퀀스의 항목을 포함하는 목록이됩니다. 매우 간단한 예부터 시작합니다.
a, *b, c = "X...Y" # a = 'X', b = ['.','.','.'], c = 'Y'
이것은
(a, *b, c) = ('X', '.', '.', '.', 'Y')
이를 분석하는 가장 간단한 방법은 끝에서 작업하는 것입니다. 'X'
이에 할당 a
되고 'Y'
에 할당되었습니다 c
. 시퀀스의 나머지 값은 목록에 배치되고에 할당됩니다 b
.
같은 Lvalues (*a, b)
하고 (a, *b)
위의 단지 특별한 경우입니다. *
모호하기 때문에 하나의 lvalue 시퀀스 내에 두 개의 연산자를 사용할 수 없습니다 . 어디 값은 다음과 같이 갈 것입니다 (a, *b, *c, d)
에 – b
나 c
? 잠시 후 중첩 된 경우를 고려하겠습니다.
*a = 1 # ERROR -- target must be in a list or tuple
여기서 오류는 매우 자명합니다. 대상 ( *a
)은 튜플에 있어야합니다.
*a, = (1,2) # a = [1,2]
알몸 쉼표가 있기 때문에 작동합니다. 규칙 적용 중 …
(*a,) = (1, 2)
이외의 변수가 없기 때문에 *a
, *a
r- 수치 시퀀스 내의 모든 값을 slurps. 를 (1, 2)
단일 값으로 바꾸면 어떻게됩니까?
*a, = 1 # ERROR -- 'int' object is not iterable
된다
(*a,) = 1
여기서도 오류는 자명합니다. 시퀀스가 아닌 것은 풀 수 없으며 풀어야 할 것이 *a
필요합니다. 그래서 우리는 그것을 시퀀스에 넣습니다.
*a, = [1] # a = [1]
다음과 같습니다.
(*a,) = (1,)
마지막으로,이 혼란의 공통점은 다음 (1)
과 동일합니다 1
– 당신은 산술 문에서 튜플을 구분하기 위해 쉼표가 필요합니다.
*a, = (1) # ERROR -- 'int' object is not
이제 중첩을 위해. 실제로이 예제는 “NESTED”섹션에 없습니다. 아마도 당신은 그것이 중첩되었다는 것을 몰랐습니까?
(a,b), *c = 'XY', 2, 3 # a = 'X', b = 'Y', c = [2,3]
된다
((a, b), *c) = (('X', 'Y'), 2, 3)
최상위 튜플의 첫 번째 값이 할당되고, 예상대로 최상위 수준 튜플 ( 2
및 3
) 의 나머지 값 이 할당됩니다 c
.
(a,b),c = 1,2,3 # ERROR -- too many values to unpack
*(a,b), c = 1,2,3 # a = 1, b = 2, c = 3
위의 첫 번째 줄에서 오류가 발생하는 이유를 이미 설명했습니다. 두 번째 줄은 어리석지 만 작동하는 이유는 다음과 같습니다.
(*(a, b), c) = (1, 2, 3)
앞서 설명했듯이 우리는 끝에서 일합니다. 3
에 할당 된 c
다음 나머지 값은 *
선행 변수 ( 이 경우)에 할당됩니다 (a, b)
. 그래서 그것은 (a, b) = (1, 2)
올바른 수의 요소가 있기 때문에 작동하는 것과 동일합니다 . 이것이 작업 코드에 나타나는 이유를 생각할 수 없습니다. 비슷하게,
*(a, *b), c = 'this' # a = 't', b = ['h', 'i'], c = 's'
된다
(*(a, *b), c) = ('t', 'h', 'i', 's')
이 ( 's'
가)에 지정 c
되고 ('t', 'h', 'i')
에 지정됩니다 (a, *b)
. 단부에서 다시 작업하기 't'
에 할당 a
한 ('h', 'i')
리스트로서 b에 할당된다. 이것은 작업 코드에서 절대 나타나지 않아야하는 또 다른 어리석은 예입니다.
답변
파이썬 2 튜플을 풀면 꽤 간단합니다. 왼쪽의 각 이름은 전체 시퀀스 또는 오른쪽 시퀀스의 단일 항목에 해당합니다. 이름이 시퀀스의 단일 항목에 해당하는 경우 모든 항목을 포함 할 수있는 충분한 이름이 있어야합니다.
그러나 확장 된 압축 풀기는 매우 강력하기 때문에 확실히 혼란 스러울 수 있습니다. 현실은 당신이 제공 한 마지막 10 개 이상의 유효한 예제를 절대 수행해서는 안된다는 것입니다 dict
.
분명히 새로운 구문은 남용 될 수 있습니다. 귀하의 질문에 대한 대답은 그런 표현을 읽을 필요가 없다는 것입니다.
임의로 복잡한 표현을 쓸 수 있다고해서 그렇게해야한다는 의미는 아닙니다. 당신은 같은 코드를 작성할 수 map(map, iterable_of_transformations, map(map, iterable_of_transformations, iterable_of_iterables_of_iterables))
있지만 그렇지 않습니다 .
답변
귀하의 코드가 다른 형식을 사용하여 오해의 소지가 있다고 생각합니다.
연산자 우선 순위에 대한 질문을 피하기 위해 표현식에 추가 대괄호를 사용하는 것과 같습니다. 나는 당신의 코드를 읽기 쉽게 만들기 위해 항상 좋은 투자입니다.
나는 스왑과 같은 간단한 작업에만 풀기를 사용하는 것을 선호합니다.