Skip to content
This page has been auto-translated and may contain errors.View in English

튜플과 집합

docs.scrimba.com

이제 리스트를 알고 있습니다. 파이썬에는 리스트로 해결할 수 없는 문제를 푸는 두 가지 컬렉션 타입이 더 있습니다. 튜플은 절대 변하지 않을 값들의 고정된 그룹을 보유합니다. 집합은 오직 고유한 값만 보유하며 컬렉션이 아무리 커도 멤버십을 즉시 확인할 수 있습니다.

파이썬의 컬렉션 도구 상자에는 네 가지 타입이 있습니다. 리스트딕셔너리는 대부분의 일반적인 경우를 처리합니다. 튜플과 집합은 특정 경우를 해결합니다: 불변성이 장점인 고정된 레코드, 그리고 O(1) 멤버십 테스팅이 우선인 고유값 컬렉션입니다.

listdict 외에도 파이썬은 tuple(생성 후 변경할 수 없는 고정 길이 시퀀스)과 set(해시 테이블 기반으로 구축된 고유값의 순서 없는 컬렉션, dict를 빠르게 만드는 콘텐츠 기반 조회 구조)을 제공합니다. 모든 결정을 주도하는 분할: 튜플은 해시 가능(그 콘텐츠가 단일 숫자로 축약되어 dict 키나 set 멤버로 작동할 수 있음), 리스트는 아닙니다. 습관적으로 어느 것을 선택하는지가 아닌, 컬렉션이 해야 할 일을 기반으로 선택하세요.

튜플

튜플은 생성 후 변경할 수 없는 순서가 있는 값들의 그룹입니다. 괄호는 튜플을 정의하지만 선택 사항입니다. 쉼표가 실제로 튜플을 만드는 것입니다. 단일 항목 튜플은 끝에 쉼표가 필요합니다.

튜플은 불변 시퀀스입니다. 괄호가 아닌 쉼표가 튜플을 생성합니다. 모든 요소도 해시 가능할 때 불변성이 해시 가능하게 만들어서, 리스트로는 채울 수 없는 사용 사례를 엽니다: dict 키, set 멤버, 그리고 고정 구조 레코드입니다.

tuple은 생성된 후 변경할 수 없는 고정 길이 시퀀스입니다. 그 안의 아무것도 움직이지 않으므로, 파이썬은 모든 요소가 자신도 해시 가능할 때마다 그것에 대한 단일 해시(그 콘텐츠에서 파생된 숫자)를 계산할 수 있으며, 이것이 튜플이 리스트가 할 수 없는 dict 키나 set 멤버로 작동할 수 있게 합니다. 인덱싱과 슬라이싱은 리스트와 정확히 동일하게 작동합니다; 항목 할당이 없으므로 point[0] = 99는 그 줄이 실행될 때 TypeError를 발생시킵니다. 단일 항목 형식 (42,)는 끝에 쉼표가 필요합니다. 없으면 괄호가 단지 그룹화만 하고 맨 값 42를 돌려받습니다.

python
point = (10, 20)
rgb = (255, 128, 0)
dimensions = (1920, 1080)
single = (42,)            # 단일 항목 튜플에 필수인 끝의 쉼표
also_tuple = 42, 99       # 괄호는 선택 사항; 쉼표가 튜플을 만듭니다

인덱스로 접근하는 것은 리스트와 정확히 동일하게 작동합니다. 항목을 변경하려고 시도하면 TypeError가 발생합니다:

인덱싱, 슬라이싱, 음수 인덱스는 모두 리스트와 동일하게 작동합니다. 인덱스를 통한 할당 시도는 TypeError를 발생시킵니다; 이는 의도적이지 제약이 아닙니다.

튜플에서 읽기는 인덱스, 음수 인덱스 또는 슬라이스로 리스트와 정확히 동일하게 작동합니다. 쓰기가 다른 점입니다: 항목 할당이 없으므로 point[0] = 99는 그 줄이 실행되는 즉시 TypeError를 발생시킵니다. 이것이 튜플을 리스트 위에 선택하는 전체 요점입니다. 이는 귀하와 나중의 모든 독자가 그 아래에서 변하지 않는다고 신뢰할 수 있는 값입니다.

python
point = (10, 20)
point[0]    # 10
point[1]    # 20
point[-1]   # 20

point[0] = 99    # TypeError: 'tuple' object does not support item assignment
Juno튜플 튜플은 생성 후 변경할 수 없는 순서가 있는 값들의 그룹입니다. 괄호가 아닌 쉼표가 이를 생성합니다. 그렇기 때문에 (42,)는 그 외로운 끝의 쉼표가 필요합니다. 항목을 다시 할당하려고 시도하면 TypeError를 얻으며, 그 잠긴 느낌이 정확히 튜플을 선택하는 이유입니다.
Juno튜플 튜플은 불변 시퀀스이며, 괄호가 아닌 쉼표가 이를 만듭니다. 그 불변성은 기능입니다: 그 콘텐츠가 불변일 때 튜플을 해시 가능하게 만들어서, 리스트가 할 수 없는 dict 키나 set 멤버가 될 수 있습니다. 항목 할당은 의도적으로 TypeError를 발생시킵니다.
Juno튜플 튜플에서 읽기는 리스트와 일치합니다; 쓰기가 누락되어 있어서 `point[0] = 99`는 런타임에 `TypeError`를 발생시킵니다. 이에 의존하세요: 튜플은 다운스트림에서 아무도 다시 쓰지 않을 것이라는 보장이 필요할 때 주위에 전달하는 값입니다. 단일 항목 `(42,)` 함정은 모두를 한 번 잡습니다.

튜플을 언제 사용할지

작은 관련 값 그룹을 가지고 있고 변하지 않을 때 튜플을 사용하세요. 좌표 (x, y), 색상 (r, g, b), 이름-점수 쌍 ("민준", 87). 고정 구조는 코드를 읽는 누구에게나 이 그룹이 단일 단위로 취급된다는 신호를 보냅니다.

튜플은 고정 구조를 통신합니다: 위치가 의미를 전달하고 그룹이 단위로 취급되는 값 그룹. 그들의 해시 가능성은 리스트가 할 수 없는 딕셔너리 키로 유효합니다. 튜플이 신호하는 계약은: 이 값들은 함께 속하고 변경되지 않아야 합니다.

튜플이 고정 형태의 레코드를 가지고 있을 때 사용하세요: 각 위치가 특정 의미를 가진 알려진 수의 필드. 튜플이 해시 가능하므로(그 콘텐츠가 단일 숫자로 축약됨), 그것은 해시 가능한 값이 필요한 모든 곳에 위치합니다: dict 키, set 멤버, 또는 함수의 결과를 호출한 인수로 키된 기억하는 functools.lru_cache 뒤의 캐시된 인수. 의미론적 신호도 리스트와 다릅니다. 튜플은 "이 필드들은 함께 속하고 각 위치는 의미를 가집니다"라고 말합니다(좌표, 색상), 여기서 리스트는 "길이가 변할 수 있는 유사한 것들의 실행"이라고 말합니다.

Juno튜플을 언제 사용할지 각 자리가 무언가를 의미하는 고정된 작은 그룹을 가지고 있을 때 튜플을 사용하세요: 좌표, (r, g, b) 색상, 이름-점수 쌍. 튜플이 해시 가능하므로 dict 키로도 사용할 수 있습니다. 리스트는 할 수 없으며, 이는 처음 시도할 때 사람들을 곤란하게 합니다.
Juno튜플을 언제 사용할지 튜플은 고정 구조를 신호합니다: 위치가 의미를 전달하고 그룹이 하나의 단위로 이동합니다. 이것이 리스트와의 차이점입니다. 리스트는 "길이가 변할 수 있는 시퀀스"라고 말합니다. 그리고 튜플이 해시 가능하므로, 리스트가 `TypeError`를 발생시키는 dict 키로 작동합니다.
Juno튜플을 언제 사용할지 고정 형태 레코드에는 튜플, 가변 길이의 유사한 것들의 실행에는 리스트. 보상은 해시 가능성입니다: 튜플은 dict 키, set 또는 `lru_cache` 키에 떨어집니다. 모두 리스트가 갈 수 없는 곳입니다. 댓글 대신 타입에 그 계약을 전달하세요.
python
locations = {}
locations[(40, -74)] = "서울"   # dict 키로서의 튜플, 작동함
locations[[40, -74]] = "서울"   # dict 키로서의 리스트, TypeError

언팩

언팩은 튜플에서 값을 꺼내 각각을 한 줄에서 고유한 이름에 할당합니다. 이름의 수는 값의 수와 일치해야 합니다. *를 사용하여 남은 항목들을 리스트로 캡처하세요.

언팩은 모든 반복 가능한 것: 튜플, 리스트, 문자열에 작동합니다. 대상 이름의 개수는 반복 가능한 것의 길이와 일치해야 합니다. 별이 붙은 대상이 가변 길이 슬라이스를 캡처하지 않으면 말입니다. 불일치는 ValueError를 발생시킵니다. 언팩은 함수에서 여러 반환 값을 소비하는 관례적 방법입니다.

언팩은 반복 가능한 모든 것(루프할 수 있는 모든 것)에 작동하며, 튜플만이 아닙니다. 오른쪽을 걸어서 각 값을 순서대로 대상 이름에 바인딩합니다. 별이 붙은 대상(*rest)은 남은 항목들을 list로 흡수합니다. 그래서 개수가 정확히 일치할 필요가 없습니다. 평문 개수 불일치는 런타임에 ValueError를 발생시킵니다. 가장 자주 사용하는 형식은 for 헤더: for name, score in pairs는 루프할 때 각 항목을 언팩하며, 손으로 각 쌍에 인덱싱하는 것보다 훨씬 더 깔끔하게 읽힙니다.

Juno언팩 언팩은 튜플이나 리스트에서 각 값을 꺼내 한 줄에서 고유한 이름을 부여합니다. 예를 들어 `x, y = point`. 이름의 수는 값의 수와 일치해야 합니다. 남은 항목들을 집어올 `*rest`를 추가하지 않으면 말입니다. `point[0]`과 `point[1]`을 모든 곳에 쓰기를 멈추던 날 이것이 저에게 클릭했습니다.
Juno언팩 언팩은 각 값을 고유한 이름에 한 줄로 할당하며, `*rest` 같은 별 붙은 대상이 가변 길이 슬라이스를 캡처합니다. 줄이 서지 않는 개수는 `ValueError`를 발생시킵니다. 함수에서 여러 반환 값을 반환 결과에 인덱싱하는 대신 취하는 깨끗한 방법입니다.
Juno언팩 언팩은 반복 가능한 모든 것에서 실행되며 왼쪽에서 오른쪽으로 바인딩합니다; `*rest`는 여유분을 흡수합니다. 평문 불일치는 `ValueError`를 발생시킵니다. 그것이 가장 많이 지불되는 곳은 `for` 헤더입니다. `for name, score in pairs`는 인덱스에 의해 각 쌍을 도달하는 것을 이깁니다.
python
point = (10, 20)
x, y = point

print(x)   # 10
print(y)   # 20

first, *rest = [1, 2, 3, 4, 5]
# first = 1, rest = [2, 3, 4, 5]

head, *middle, tail = [1, 2, 3, 4, 5]
# head = 1, middle = [2, 3, 4], tail = 5

이름 붙은 튜플

이름 붙은 튜플은 각 위치가 이름을 가진 튜플입니다. point[0]이 x 좌표라는 것을 기억하는 대신 point.x를 작성합니다. 값은 여전히 불변입니다; 수치 위치 대신 읽을 수 있는 속성 이름을 얻습니다.

namedtuple은 정확히 튜플처럼 작동하지만 이름이 붙은 속성 접근을 추가하는 클래스를 생성합니다. 전체 클래스보다 가볍고, 불변이며, 스스로 설명합니다. 평문 튜플의 위치 접근에 주석이 필요할 때 사용하세요.

collections.namedtuple클래스 팩토리(당신이 사용할 새로운 클래스를 구축하고 전달하는 함수)입니다. 반환하는 클래스는 이름이 붙은 필드가 있는 tuple이므로 평문 튜플과 같은 메모리 비용이 들면서 훨씬 더 잘 읽힙니다. _asdict()(그것을 dict로 변환), _replace()(한 필드를 변경한 사본을 만듭니다. 변경할 수 없으므로), 그리고 _fields를 무료로 얻습니다. 더 필요할 때, 기본값이나 타입 어노테이션, typing.NamedTuple은 어노테이션된 경우를 처리하며, dataclasses.dataclass는 메서드나 선택적 변경성을 원할 때 현대적 선택입니다.

Juno이름 붙은 튜플 이름 붙은 튜플은 모든 위치에 이름을 부여합니다. 그래서 `point[0]`이 x라는 것을 기억하는 대신 `point.x`를 작성합니다. 여전히 완전히 불변이며 다른 모든 방법으로 일반 튜플처럼 작동합니다. 코드를 읽는 향후 자신이 이름에 감사할 것입니다.
Juno이름 붙은 튜플namedtuple은 이름이 붙은 속성 접근을 가진 튜플 같은 클래스를 구축하며, 불변이고 스스로 설명합니다. 평문 튜플의 위치에 주석이 필요할 때마다 그것을 사용하세요. 그 이상일 때 dataclass는 현대적 한 발짝입니다.
Juno이름 붙은 튜플namedtuple은 같은 메모리 비용으로 이름이 붙은 필드가 있는 튜플 서브클래스를 제공하며, _replace()_asdict()는 무료입니다. 기본값, 메서드, 또는 실제 타입 힌트를 원할 때 팩토리와 싸우는 대신 typing.NamedTuple 또는 dataclass로 점프하세요.

namedtuple은 표준 라이브러리에 있으므로 먼저 임포트가 필요합니다: from collections import namedtuple. 임포트는 모듈 장에서 전체 처리를 얻습니다.

python
from collections import namedtuple

Point = namedtuple("Point", ["x", "y"])
Player = namedtuple("Player", ["name", "score", "level"])

p = Point(10, 20)
p.x    # 10
p.y    # 20

alice = Player("민준", 87, 5)
alice.name    # "민준"
alice.score   # 87

집합

집합은 보장된 순서가 없는 고유값 컬렉션입니다. 같은 값을 두 번 추가하면 아무것도 하지 않습니다: 집합은 각 항목의 복사본 하나만 유지합니다. 항목이 있는 집합에는 중괄호를 사용하거나, 빈 집합을 만들려면 set()를 사용합니다.

set은 자동으로 중복을 거부하는 순서 없는 컬렉션입니다. 멤버십 테스팅은 크기와 관계없이 O(1)이며, 큰 컬렉션에서 값이 존재하는지 확인해야 할 때마다 올바른 도구가 됩니다. 참고: {}는 빈 집합이 아니라 빈 딕셔너리를 생성합니다; 그것을 위해 set()을 사용하세요.

set은 고유하고 해시 가능한 값을 보유하며 dict와 같은 콘텐츠 기반 조회 구조인 해시 테이블 위에 구축됩니다. 이는 O(1) 평균 멤버십, 삽입 및 삭제를 제공합니다(비용은 집합이 증가함에 따라 올라가는 대신 평탄하게 유지됩니다). 계획할 두 가지 결과: 해시 가능한 값만 들어갈 수 있습니다. 그래서 int, str, 그리고 tuple은 괜찮지만 list, dict, 그리고 set은 아닙니다. 반복 순서는 내부 해시 위치를 따르므로 절대 안정적이어야 한다고 의존하지 마세요. 한 가지 문법 함정: {}는 빈 집합이 아니라 빈 딕셔너리입니다; set()을 사용하세요.

Juno집합 집합은 오직 고유한 값만 유지합니다. 그래서 이미 그 안에 있는 것을 추가하면 아무것도 하지 않습니다. 오류도 없고, 중복도 없습니다. 중괄호와 항목이 있는 것으로 하나를 구축하세요. 하지만 빈 것을 위해 set()을 사용하세요. 왜냐하면 {}는 비밀스럽게 빈 딕셔너리이기 때문입니다. 그 마지막 비트는 거의 모두를 잡습니다.
Juno집합 집합은 자동으로 중복을 떨어뜨리고 크기가 크더라도 O(1)에서 멤버십을 테스트합니다. 이것이 큰 컬렉션에서 "이것이 여기 있습니까?"에 대해 올바른 도구입니다. 빈 집합 함정을 조심하세요: {}는 dict이므로 빈 집합을 원할 때 set()을 사용하세요.
Juno집합 집합은 고유 해시 가능값의 해시 테이블입니다: O(1) 멤버십, 삽입 및 삭제, 해시 가능 항목만 들어갈 수 있고 반복 순서는 절대 안정적이지 않다는 비용에서. 그 순서에 의존하지 마세요, 그리고 {}는 dict라는 것을 기억하세요. 그래서 빈 집합을 원할 때 set()에 도달하세요.
python
tags = {"python", "beginner", "tutorial"}
numbers = {1, 2, 3, 4, 5}
empty = set()    # NOT {} (그것은 빈 딕셔너리입니다)

같은 값을 두 번 추가하면 집합을 변경하지 않습니다:

python
tags.add("python")   # tags가 변경되지 않음, "python"은 이미 그것에 있습니다

집합을 언제 사용할지

집합은 세 가지를 위한 올바른 도구입니다: 리스트에서 중복 제거, 빠르게 큰 컬렉션에서 무언가가 있는지 확인, 두 그룹을 비교하여 공유 또는 다른 점 찾기.

세 가지 명확한 사용 사례가 집합 사용을 주도합니다: 중복 제거(삽입 시 자동), O(1) 멤버십 테스팅(list의 O(n) 대비), 그리고 집합 대수(|, &, -, ^). 컬렉션이 크고 자주 멤버십을 확인할 때 성능 차이는 상당합니다.

세 가지 사용 사례는 해시 테이블에서 직접 나옵니다: 고유성(삽입 시 중복 거부), O(1) 멤버십(집합이 증가함에 따라 in의 비용은 평탄하게 유지됨), 그리고 집합 대수(|, &, -, ^). 멤버십 테스트는 실제 코드에서 돈을 지불하는 것입니다: 10,000개 항목의 집합에 대한 in은 10개 집합에 대한 것만큼 빠르며, 여기서 리스트에 대한 같은 확인은 O(n)이며 선형으로 느려집니다. 큰 리스트에 대해 반복된 x in some_list를 자신이 하는 것을 발견할 때, 그것을 한 번 집합으로 변환하는 것이 보통 수정입니다.

Juno집합을 언제 사용할지 세 가지 일은 집합이 훌륭합니다: 리스트에서 중복을 제거하기, 빠르게 큰 컬렉션에서 무언가가 있는지 확인하기, 두 그룹을 비교하여 공유 또는 다른 점을 보기. 그중 어느 것이든 당신이 하는 것이면, 집합이 아마도 도구입니다.
Juno집합을 언제 사용할지 세 가지 드라이버: 삽입 시 중복 제거, 리스트의 O(n) 대비 O(1) 멤버십, 그리고 |, &, -, ^를 가진 집합 대수. 컬렉션이 클수록 그리고 더 자주 in을 확인할수록 집합이 더 앞으로 당깁니다.
Juno집합을 언제 사용할지 고유성, O(1) `in`, 그리고 해시 테이블에서 떨어지는 집합 대수. 멤버십 승리는 실제적인 것입니다: 반복된 `x in big_list`는 매번 O(n)이므로 그 리스트를 한 번 집합으로 변환하는 것이 보통 수정입니다.
python
# 리스트에서 중복 제거
raw = ["cat", "dog", "cat", "bird", "dog", "cat"]
unique = list(set(raw))   # ["cat", "dog", "bird"] (순서 보장되지 않음)
python
# 빠른 멤버십 확인
valid_codes = {"USD", "EUR", "GBP", "JPY"}
code = "EUR"

if code in valid_codes:    # 수천 개 코드가 있어도 즉시 조회
    print("Valid")

집합 연산

집합은 수학에서 배운 같은 연산을 지원합니다: 합집합(두 집합 중 하나의 모든 것), 교집합(두 집합만 공유하는 것), 그리고 차이(하나가 다른 것이 없는 것). 파이썬은 이들에 대해 연산자 기호를 사용하며 각각은 메서드 동등물을 가집니다.

파이썬의 집합 연산자는 수학적 표기법을 반영합니다: |는 합집합, &는 교집합, -는 차이, ^는 대칭 차이. 각 연산자는 메서드 형식(union(), intersection() 등)을 가지며, 이는 집합뿐만 아니라 반복 가능한 모든 것을 수용합니다.

연산자 형식(|, &, -, ^)은 양쪽이 집합이어야 하며 리스트 같은 다른 것이면 TypeError를 발생시킵니다. 메서드 형식(.union(), .intersection() 등)은 더 느슨합니다: 반복 가능한 모든 것을 수용하고 당신을 위해 변환합니다. 그래서 a.union([1, 2])a | [1, 2]가 실패하는 곳에서 작동합니다. 그 차이는 연산이 폭발할 때 기억할 것입니다. 제자리 형식(|=, &=, -=, ^=)도 있습니다. 이는 새로운 것을 반환하는 대신 왼쪽 집합을 업데이트합니다. .update(), .intersection_update() 등을 호출하는 것과 같습니다.

Juno집합 연산 수학 수업 네 가지 연산: |는 합집합(하나), &는 교집합(둘 다), -는 차이(하나가 아님), ^는 대칭 차이(하나가 아닌 것). 각각은 또한 기호보다 단어를 선호하면 .union() 같은 철저한 메서드를 가집니다.
Juno집합 연산| 합집합, & 교집합, - 차이, ^ 대칭 차이. 메서드 형식(.union() 및 친구들)은 같은 일을 하지만 연산자가 아닌 반복 가능한 모든 것을 수용합니다.
Juno집합 연산 연산자는 양쪽이 집합이기를 원하며 그렇지 않으면 `TypeError`를 발생시킵니다; 메서드 형식은 반복 가능한 모든 것을 취하므로 `a.union([1, 2])`는 `a | [1, 2]`가 아닌 곳에서 작동합니다. 제자리 형식(`|=`, `&=`)은 새로운 집합을 반환하는 대신 제자리에서 업데이트합니다.
python
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

a | b    # {1, 2, 3, 4, 5, 6}   (합집합: 하나의 모든 것)
a & b    # {3, 4}               (교집합: 둘 다에만 있음)
a - b    # {1, 2}               (차이: a에 있지만 b에는 없음)
b - a    # {5, 6}               (다른 방향의 차이)
a ^ b    # {1, 2, 5, 6}        (대칭 차이: 하나에 있지만 둘 다에는 없음)

메서드 형식도 있습니다: .union(), .intersection(), .difference(), .symmetric_difference().

집합 수정

집합은 변경 가능합니다. .add()는 항목 하나를 추가합니다. .update()는 리스트나 다른 반복 가능한 것에서 여러 개를 한 번에 추가합니다. .remove()는 항목을 삭제하지만 그것이 없으면 오류를 발생시킵니다. .discard()는 항목이 존재하면 조용히 삭제하고 그렇지 않으면 아무것도 하지 않습니다.

.add()는 O(1) 평균입니다. .update()는 반복 가능한 모든 것을 수용하며 루프에서 .add()를 호출하는 것과 동등합니다. .remove()는 미스에서 KeyError를 발생시키지만, .discard()는 현재가 확실하지 않을 때 안전한 선택입니다. .pop()은 임의의 요소를 제거하며, 집합은 순서가 없으므로 "마지막" 하나는 아닙니다.

.add(x)는 O(1) 평균에 항목 하나를 삽입합니다; .update(iterable)은 많은 것을 추가하며 |=와 동일합니다. 사람들을 물어뜯는 쌍은 .remove().discard()입니다: 둘 다 항목을 삭제하지만, .remove()는 항목이 없을 때 KeyError를 발생시키는 반면 .discard()는 조용히 아무것도 하지 않습니다. 현재가 확실하지 않을 때마다 .discard()에 도달하세요. 그래서 누락된 항목은 당신이 감싸야 할 예외가 아닙니다. .pop()은 어떤 요소를 반환하고 제거합니다. 하지만 어느 것은 정의되지 않습니다: 집합은 순서가 없으므로 절대 .pop()을 "마지막" 항목을 취하는 것으로 취급하지 마세요.

Juno집합 수정.add()는 항목 하나를 넣으며, .update()는 리스트나 다른 반복 가능한 것에서 전체 배치를 추가합니다. 유지할 쌍은 제거입니다: .remove()는 항목이 없으면 오류를 발생시키지만 .discard()는 쌍을 이루고 이동합니다. 당신이 그것이 집합에 있다고 확실하지 않을 때 .discard()는 당신을 미로 오류에서 구합니다.
Juno집합 수정.add()는 하나를, .update()는 반복 가능한 모든 것에서 많은 것을 추가합니다. .remove()는 미스에서 `KeyError`를 발생시킵니다; .discard()는 그것을 무시하는 안전한 버전입니다. 그리고 .pop()은 임의의 요소를 당깁니다. "마지막" 하나가 아닙니다. 집합에는 순서가 없기 때문입니다.
Juno집합 수정.add()는 O(1)이며, .update()는 `|=`입니다. 함정은 `KeyError`를 발생시키는 `.remove()`입니다. 여기서 `.discard()`는 조용합니다. 그래서 현재가 불확실할 때 `.discard()`로 기본값을 정하세요. .pop()은 정의되지 않은 요소를 반환합니다; 절대 마지막 하나로 읽지 마세요.
python
tags = {"python", "beginner"}

tags.add("tutorial")          # 항목 하나 추가
tags.update(["web", "api"])   # 반복 가능한 모든 것에서 여러 항목 추가
tags.remove("beginner")       # 제거, 찾지 못하면 KeyError 발생
tags.discard("missing")       # 제거, 찾지 못하면 오류 없음
tags.pop()                    # 임의의 항목 제거 및 반환
tags.clear()                  # 모든 것 제거

현재 항목이 있는지 확실하지 않을 때 .discard()를 사용하세요.

고정 집합

고정 집합은 생성 후 수정할 수 없는 집합입니다. 하나를 사용하는 주요 이유: 고정 집합은 해시 가능하므로 딕셔너리 키로 사용되거나 다른 집합 내부에 저장될 수 있습니다.

frozensetset의 불변 대응물입니다. 모든 읽기 연산과 집합 대수를 지원하지만 변경은 아닙니다. 그 불변성은 그것을 해시 가능하게 만듭니다. 의미하는 것은 dict 키 또는 다른 집합의 멤버이며, 평문 set은 할 수 없습니다.

frozenset은 생성 후 변경할 수 없는 set입니다. 그 안의 아무것도 움직이지 않으므로, 그것은 안정적인 해시를 얻으며 그 자신이 해시 가능하므로, dict 키나 다른 집합의 멤버가 될 수 있습니다. 평문 set은 둘 다 할 수 없습니다. 읽기나 새 컬렉션을 반환하는 모든 것은 여전히 작동합니다(멤버십, 집합 대수 연산자). 변경 메서드(add, remove 등)는 사라집니다. 이 경우는 깔끔하게 맞습니다: 프로그램 실행 중에 변경되지 말아야 하고 dict나 집합 내부에서 살 필요가 있을 수 있는 상수 조회 테이블.

Juno고정 집합 고정 집합은 생성된 후 변경할 수 없는 집합입니다. 그 잠긴 상태는 그것을 해시 가능하게 만드는 것입니다. 그래서 평문 집합과 달리 dict 키나 다른 집합 내부에 하나를 사용할 수 있습니다. 변경되지 않아야 할 허용 값의 고정 그룹을 가지고 있을 때 그것에 도달하세요.
Juno고정 집합frozenset은 불변 `set`입니다: 모든 읽기와 집합 대수, 변경은 없습니다. 그 불변성은 해시 가능성을 사고, 그래서 평문 `set`이 발생시키는 dict 키나 다른 집합의 멤버로 작동합니다. 상수 조회 테이블에 좋은 적합입니다.
Juno고정 집합frozenset은 안정적인 해시를 가지므로 `set`이 갈 수 없는 곳으로 갑니다: dict 키, 다른 집합의 멤버. 읽기와 집합 대수는 유지되며, 변경 메서드는 사라집니다. 깨끗한 사용은 런타임에 변경되지 않아야 할 상수 조회 테이블입니다.
python
valid_statuses = frozenset({"active", "paused", "deleted"})
valid_statuses.add("archived")    # AttributeError, frozenset은 불변입니다

올바른 컬렉션 선택

네 가지 타입, 각각 명확한 역할. 데이터로 무엇을 해야 하는지 물어보고 올바른 선택이 보통 따릅니다.

컬렉션 타입 간의 선택은 어떤 연산이 중요하고 당신의 데이터가 어떤 제약이 있는가입니다: 변경 가능성, 순서, 중복 처리, 조회 전략.

선택은 일부 성능, 일부 의미입니다. dictset은 해싱을 통해 O(1) 평균 조회를 제공합니다. 그래서 멤버십 확인은 그들이 증가함에 따라 빠르게 유지됩니다. listtuple은 인덱스로 O(1) 접근을 제공하지만 O(n) 멤버십을 제공합니다. 여기서 in은 크기와 함께 느려집니다. 다른 축은 타입이 신호하는 것입니다: tuple은 불변성이 해시 가능성을 구매하는 고정 레코드이며, 여기서 list는 가변 길이 시퀀스입니다. dict나 집합 내부에 중첩하려는 해시 가능한 컬렉션이 필요할 때, tuplefrozenset은 그것을 할 수 있는 두 가지 내장 타입입니다.

Juno올바른 컬렉션 선택 네 가지 타입, 네 가지 명확한 작업: 변경할 순서가 있는 것에는 리스트, 고정 레코드에는 튜플, 고유한 값과 빠른 "이것이 여기 있습니까?" 확인에는 집합, 이름으로 것들을 찾을 때는 딕셔너리. 데이터로 무엇을 해야 하는지 물어보세요. 올바른 것이 보통 떨어집니다.
Juno올바른 컬렉션 선택 데이터가 필요한 것을 선택하세요: 변경 가능성, 순서, 중복이 중요한지 여부, 그리고 당신이 어떻게 것들을 찾습니까. 변경할 순서가 있는 시퀀스에는 리스트, 고정 레코드에는 튜플, 고유 값과 O(1) 멤버십에는 집합, 키-값 조회에는 딕셔너리.
Juno올바른 컬렉션 선택 반반 성능, 반반 의미: `dict`와 `set`은 O(1) 조회를 제공하며, `list`와 `tuple`은 인덱스로 O(1)을 제공하지만 O(n) 멤버십을 제공합니다. `tuple`은 또한 "고정 레코드"를 신호하고 해시 가능성을 구매합니다. 중첩할 해시 가능한 컬렉션이 필요할 때 `tuple`과 `frozenset`이 당신의 두 가지 옵션입니다.
listtuplesetdict
순서아니오예(삽입 순서)
변경 가능아니오
중복아니오아니오(키)
접근인덱스인덱스n/a
사용할 때순서가 있고 변경할 시퀀스고정 레코드고유 값, 빠른 멤버십키-값 조회

빠른 결정 규칙:

  • 이름으로 무언가를 찾아야 합니까? → dict
  • 변경할 순서가 있는 컬렉션이 필요합니까? → list
  • 관련 값의 고정 그룹이 있습니까? → tuple
  • 고유 값이나 빠른 멤버십 테스트가 필요합니까? → set

실제로

고정 레코드를 저장하는 튜플과 고유 값을 추적하는 집합 사용:

python
home = (51.5074, -0.1278)   # 위도, 경도
office = (51.5155, -0.0922)

home_lat, home_lon = home
print(f"Home: {home_lat}, {home_lon}")

# 고유 방문자를 집합으로 추적합니다
visitors = set()
visitors.add("민준")
visitors.add("소현")
visitors.add("민준")    # 이미 집합에 있음, 조용히 무시됨
visitors.add("지원")

print(f"Unique visitors: {len(visitors)}")
print(f"민준 visited: {'민준' in visitors}")
print(f"현준 visited:  {'현준' in visitors}")

이미 처리된 것을 추적하고 남은 작업을 계산하는 집합을 사용:

python
already_processed = {"report_jan.csv", "report_feb.csv"}
all_files = {"report_jan.csv", "report_feb.csv", "report_mar.csv", "report_apr.csv"}

to_process = all_files - already_processed
print(f"Files to process: {sorted(to_process)}")

for filename in sorted(to_process):
    print(f"Processing {filename}...")
    already_processed.add(filename)

print(f"Done. Total processed: {len(already_processed)}")

상수 조회 테이블을 위해 frozenset을 사용하고 집합 대수로 O(1) 멤버십 테스팅을 시연:

python
ALLOWED_METHODS = frozenset({"GET", "POST", "PUT", "PATCH", "DELETE"})
SAFE_METHODS = frozenset({"GET", "HEAD", "OPTIONS"})

# frozenset에 대한 집합 대수는 평문 집합을 반환합니다
unsafe_allowed = ALLOWED_METHODS - SAFE_METHODS
print(f"Non-safe allowed methods: {unsafe_allowed}")

# frozenset은 해시 가능하므로 집합에 저장될 수 있습니다(평문 집합은 할 수 없음)
method_groups = {
    frozenset({"GET", "HEAD", "OPTIONS"}),
    frozenset({"POST", "PUT", "PATCH"}),
    frozenset({"DELETE"}),
}
print(f"Method groups: {len(method_groups)}")

method = "POST"
print(f"Allowed: {method in ALLOWED_METHODS}")
print(f"Safe:    {method in SAFE_METHODS}")

frozenset은 O(1) 조회를 전달하며 해시 가능한 타입이 필요한 곳 어디든 저장될 수 있습니다. 두 개의 frozenset 객체에 대한 집합 대수는 평문 set을 반환합니다; 그것을 불변으로 유지하려면 결과를 frozenset()에 감싸세요.