파이썬에서 왜 튜플 이해가 없는가?


340

우리 모두 알고 있듯이 다음과 같은 목록 이해가 있습니다.

[i for i in [1, 2, 3, 4]]

그리고 사전 이해력이 있습니다.

{i:j for i, j in {1: 'a', 2: 'b'}.items()}

그러나

(i for i in (1, 2, 3))

tuple이해력이 아닌 발전기로 끝납니다 . 왜 그런 겁니까?

내 생각에 a tuple는 변경할 수 없지만 이것이 답이 아닌 것 같습니다.


15
또한 독해 이해력과 비슷하게 보이는 이해력도 있습니다.
mgilson

3
코드에 구문 오류 {i:j for i,j in {1:'a', 2:'b'}}가 있습니다.{i:j for i,j in {1:'a', 2:'b'}.items()}
Inbar Rose

@InbarRose 지적 해 주셔서 감사합니다 -.-
Shady Xu

후손을 위해, 파이썬 채팅
Inbar Rose

답변:


471

생성기 표현식을 사용할 수 있습니다.

tuple(i for i in (1, 2, 3))

그러나 괄호는 이미 ... 발전기 표현에 사용되었습니다.


15
이 주장에 의해 우리는 목록 이해력이 필요하지 않다고 말할 수있다 list(i for i in (1,2,3)). 나는 그것이 단지 그것에 대한 명확한 문법이 없기 때문이라고 생각한다. (또는 적어도 아무도 생각하지 않았다)
mgilson

79
목록 또는 세트 또는 독해 이해는 특정 유형을 출력하는 생성기 표현식을 사용하는 구문 설탕입니다. list(i for i in (1, 2, 3))목록을 set(i for i in (1, 2, 3))출력하고 세트 를 출력하는 생성기 표현식입니다 . 이것은 이해 구문이 필요하지 않다는 것을 의미합니까? 아마도 그렇지는 않지만 매우 편리합니다. 드문 경우이지만 대신 튜플이 필요합니다. 제너레이터 표현식이 수행하고 명확하며 또 다른 괄호 또는 괄호가 필요하지 않습니다.
Martijn Pieters

16
대답은 튜플 구문과 괄호가 모호하기 때문에 분명히
찰스 샐비어

19
이해를 사용하는 것과 생성자 + 생성자를 사용하는 것의 차이점은 성능에 관심이 있다면 미묘합니다. 이해력은 생성자에 전달 된 생성기를 사용하는 것과 비교하여 더 빠른 구성을 제공합니다. 후자의 경우 함수를 작성하고 실행하면 Python에서 비용이 많이 듭니다. [thing for thing in things]보다 훨씬 빠른 목록을 구성합니다 list(thing for thing in things). 튜플 이해력은 쓸모가 없습니다. tuple(thing for thing in things)대기 시간 문제가 있고 tuple([thing for thing in things])메모리 문제가있을 수 있습니다.
저스틴 터너 아서

9
@MartijnPieters, 당신은 잠재적으로 reword 할 수 있습니까 A list or set or dict comprehension is just syntactic sugar to use a generator expression? 그것은 일으키는 혼란을 이러한 보는 사람들이 동등한 끝을 의미합니다. 최종 제품이 동일하더라도 프로세스가 실제로 다르기 때문에 기술적으로 구문 설탕이 아닙니다.
jpp

77

Raymond Hettinger (Python 핵심 개발자 중 하나)는 최근 트윗 에서 튜플에 대해 다음과 같이 말했습니다 .

#python tip : 일반적으로리스트는 루핑을위한 것입니다. 구조체에 대한 튜플. 목록은 동종입니다. 이종 튜플. 가변 길이 목록.

이것은 (나에게) 시퀀스의 항목이 생성기에 의해 생성 될만큼 충분히 관련되어 있다면 목록이어야한다는 아이디어를 지원합니다. 튜플은 반복 가능하고 단순히 불변 목록처럼 보이지만 실제로는 C 구조체와 동등한 Python입니다.

struct {
    int a;
    char b;
    float c;
} foo;

struct foo x = { 3, 'g', 5.9 };

파이썬이된다

x = (3, 'g', 5.9)

26
불변 속성은 중요하지만 일반적으로 목록을 사용할 때 튜플을 사용해야하는 좋은 이유가 될 수 있습니다. 예를 들어, dict의 열쇠로 사용하려는 5 개의 숫자 목록이 있으면 튜플이 좋습니다.
pavon December

Raymond Hettinger의 유용한 팁입니다. 여전히 튜플 생성자로 튜플 생성자로 사용하는 경우 (예 : 튜플 레코드로 변환하려는 attrs를 반복하여 더 큰 다른 구조를 더 작은 구조로 압축 풀기)와 같은 사용 사례가 있다고 말합니다.
dave

2
@dave 아마도이 operator.itemgetter경우에 사용할 수 있습니다 .
chepner

@ chepner, 알겠습니다. 그것은 내가 의미하는 바에 가깝습니다. 호출 가능을 반환하므로 한 번만 수행하면 tuple(obj[item] for item in items)직접 사용하는 것보다 많은 승리를 보지 못합니다 . 내 경우에는 이것을 튜플 레코드 목록을 만들기 위해 목록 이해에 포함시키고있었습니다. 코드 전체 에서이 작업을 반복적으로 수행 해야하는 경우 itemgetter가 좋습니다. 아마도 itemgetter는 더 관용적일까요?
dave

frozenset과 set의 관계는 tuple과 list의 관계와 비슷합니다. 불균일성에 관한 것이 아니라 불변성에 관한 것입니다. 고정 세트와 튜플은 사전, 목록 및 세트의 핵심이 될 수 있기 때문에 변경 가능성이 없습니다.
polyglot

56

Python 3.5부터 splat *unpacking 구문을 사용하여 생성기 expresion을 풀 수 있습니다 .

*(x for x in range(10)),

2
이것은 훌륭하지만 작동하지만 문서화 된 곳을 찾을 수 없습니다! 당신은 링크가 있습니까?
felixphew

8
주 : 구현 세부 같이, 이것은 기본적으로하고 동일하다 tuple(list(x for x in range(10)))( 코드 경로가 동일한 둘은 건물과, list유일한 차이점은 최종 단계는를 생성하는 것을 인 상태 tuple로부터 list상기 버릴 listtuple출력 필요합니다). 실제로 한 쌍의 임시를 피하지 않음을 의미합니다.
ShadowRanger

4
@ShadowRanger의 주석을 확장하기 위해 splat + tuple 리터럴 구문이 실제로 생성기 표현식을 튜플 생성자에 전달하는 것보다 약간 느리다는 것을 보여주는 질문 이 있습니다.
Lucubrator

파이썬 3.7.3에서 이것을 시도하고 *(x for x in range(10))작동하지 않습니다. 나는 얻는다 SyntaxError: can't use starred expression here. 그러나 tuple(x for x in range(10))작동합니다.
Ryan H.

4
@RyanH. 끝에 쉼표를 넣어야합니다.
czheo

27

다른 포스터에서 macm언급했듯이 발전기에서 튜플을 만드는 가장 빠른 방법은 tuple([generator])입니다.


성능 비교

  • 목록 이해 :

    $ python3 -m timeit "a = [i for i in range(1000)]"
    10000 loops, best of 3: 27.4 usec per loop
  • 목록 이해에서 튜플 :

    $ python3 -m timeit "a = tuple([i for i in range(1000)])"
    10000 loops, best of 3: 30.2 usec per loop
  • 발전기에서 튜플 :

    $ python3 -m timeit "a = tuple(i for i in range(1000))"
    10000 loops, best of 3: 50.4 usec per loop
  • 포장 풀기에서 튜플 :

    $ python3 -m timeit "a = *(i for i in range(1000)),"
    10000 loops, best of 3: 52.7 usec per loop

내 파이썬 버전 :

$ python3 --version
Python 3.6.3

따라서 성능이 문제가되지 않는 한 목록 이해력에서 항상 튜플을 만들어야합니다.


10
참고 : tupleof listcomp에는 최종 tuple및 의 결합 된 크기에 따라 최대 메모리 사용량이 필요합니다 list. tuplegenexpr의 느린 동안, 당신에게 마지막에 대해서만 지불을 의미 하는가 tuple, 어떤 일시적 list합니다 (genexpr 자체는 거의 고정 된 메모리를 점유 없음). 일반적으로 의미가 없지만 관련된 크기가 클 때 중요 할 수 있습니다.
ShadowRanger

25

이해는 항목을 반복하거나 반복하여 컨테이너에 할당하여 작동합니다. Tuple은 할당을받을 수 없습니다.

튜플이 생성되면 추가, 확장 또는 할당 할 수 없습니다. Tuple을 수정하는 유일한 방법은 객체 중 하나를 자체에 할당 할 수있는 경우 (비 튜플 컨테이너)입니다. Tuple은 해당 종류의 객체에 대한 참조 만 보유하기 때문입니다.

또한-튜플에는 tuple()반복자를 제공 할 수있는 자체 생성자 가 있습니다. 튜플을 만들려면 다음을 수행 할 수 있습니다.

tuple(i for i in (1,2,3))

9
어떤면에서 나는 (목록이 필요하기 때문에 필요하지 않다는 것에 대해) 동의하지만 다른 방법으로는 (불변이기 때문에 추론에 대해) 동의하지 않습니다. 어떤면에서는 불변의 객체에 대한 이해가 더 합리적입니다. 누가합니까 lst = [x for x in ...]; x.append()?
mgilson

@ mgilson 나는 그것이 내가 말한 것과 어떻게 관련되어 있는지 잘 모르겠습니까?
인바 로즈

2
튜플이 불변 인 경우 @mgilson 기본 구현 이 튜플을 "생성" 할 수 없음 을 의미합니다 ( "한 번에 한 조각 씩 빌드하는 것을 의미"). 불변은 3 조각으로 변경하여 4 조각으로 만들 수 없다는 것을 의미합니다. 대신, 생성을 위해 설계된 목록을 작성하여 튜플 "생성"을 구현 한 다음 마지막 단계로 튜플을 빌드하고 목록을 버립니다. 언어는이 현실을 반영합니다. 튜플을 C 구조체로 생각하십시오.
Scott

2
이해력이 회복 될 때까지 튜플을 사용할 수 없기 때문에 이해력의 구문 설탕이 튜플에 대해 작동하는 것이 합리적이지만. 실제로 그것은 가변처럼 작동하지 않으며, 튜플 이해는 문자열 추가와 매우 유사하게 작동 할 수 있습니다.
uchuugaka

12

내 최선의 추측은 대괄호가 부족하고 "추악한"구문을 추가하는 것이 유용 할 것이라고 생각하지 않았다는 것입니다 ...


1
앵글 브래킷은 사용하지 않습니다.
uchuugaka

@uchuugaka-완전히는 아닙니다. 비교 연산자에 사용됩니다. 아마도 모호함없이 여전히 이루어질 수 있지만 노력할 가치는 없을 것입니다.
mgilson

3
@uchuugaka 가치가 {*()}있지만 추악하지만 빈 세트 리터럴로 작동합니다!
MI Wright

1
어. 미적 관점에서, 나는 내가 부분적으로 생각합니다 set():)
mgilson

1
@QuantumMechanic : 네, 요점입니다. 압축 풀기 일반화로 인해 빈 "set literal"이 가능해졌습니다. {*[]}다른 옵션보다 열등 하다는 점 에 유의하십시오 . tuple불변 의 빈 캐릭터 라인과 empty 는 싱글 톤이므로 empty를 구축하기 위해서 일시적인 필요는 없습니다 set. 대조적으로, empty list는 싱글 톤이 아니기 때문에 실제로 그것을 구축하고 그것을 사용하여을 구축 한 set다음 파기해야합니다.
ShadowRanger

8

튜플은 목록처럼 효율적으로 추가 할 수 없습니다.

따라서 튜플 이해력은 내부적으로 목록을 사용한 다음 튜플로 변환해야합니다.

그것은 당신이 지금하는 것과 똑같을 것입니다 : tuple (


3

괄호는 튜플을 만들지 않습니다. 일명 one = (two)는 튜플이 아닙니다. 유일한 방법은 one = (two,) 또는 one = tuple (two)입니다. 해결책은 다음과 같습니다.

tuple(i for i in myothertupleorlistordict) 

좋은. 거의 동일합니다.
uchuugaka

-1

나는 그것이 명확성을 위해 단순히 있다고 생각합니다. 우리는 너무 많은 다른 기호로 언어를 어지럽히고 싶지 않습니다. 또한 tuple이해는 필요 하지 않습니다 .리스트 이해와 반대되는 dict 이해와는 달리 무시할 수있는 속도 차이로리스트를 대신 사용할 수 있습니다.


-2

리스트 이해력으로부터 튜플을 생성 할 수 있습니다. 다음은 튜플에 두 개의 숫자를 순차적으로 추가하고 숫자 0-9의 목록을 제공합니다.

>>> print k
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
>>> r= [tuple(k[i:i+2]) for i in xrange(10) if not i%2]
>>> print r
[(0, 1), (2, 3), (4, 5), (6, 7), (8, 9)]
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.