파이썬 프로그래밍 기초 2부 2편

주요 내용

모음 자료형 2편

튜플과 리스트에 이어 사전과 집합에 대해 설명한다.

사전

현대 프로그래밍 언어 분야에서 가장 중요하게 사용되는 자료형이 사전(dict)이다. 특히, 데이터 분석 분야에서 더욱 그러하다. 언어에 따라 해시맵(hash map), 연관배열(associative array) 등으로 불리기도 하며, 조금씩 다른 성질을 갖기도 하지만 기본적으로 파이썬의 사전 자료형과 동일하게 작동한다.

참고: 사전 자료형을 사람에 따라 딕셔너리(dictionary)라고 부르기도 하지만 여기서는 사전이라 부른다.

사전 자료형은 모음 자료형이며 따라서 여러 개의 항목을 갖는다. 각 항목은 키(key)값(value)의 쌍으로 이루어지며 아래 형식으로 키-값의 관계를 지정한다.

(key) : (value)

사전 객체는 중괄호를 사용한다. 집합에 사용되는 기호와 동일하지만 항목이 키:값 형식이라면 사전 객체로 인식된다.

주의: 키:값 형식의 사전 항목은 파이썬에서 인정하는 제1종 객체가 아니며, 따라서 사전 객체의 항목으로만 사용된다.

비어 있는 사전

항목이 전혀 없는 빈 사전은 아래와 같이 표기한다.

참고: 공집합은 아래와 같이 선언한다.

항목 추가

사전은 변경 가능하다.

예를 들어, d1은 아래와 같이 두 개의 항목을 갖는 사전을 가리킨다.

7 : 'an integer' 를 새로운 항목을 추가하려면 아래와 같이 진행한다.

다음은 'language' : 'python' 을 추가해보자.

항목 확인

특정 키가 사전에 사용되었는지 여부를 확인할 때 in 연산자를 활용한다.

사용되지 않은 키를 확인하면 오류가 발생한다.

특정 키와 연관된 값을 확인하려면 인덱싱 방식처럼 사용한다. 단, 키를 인덱스 대신 지정하면 된다.

없는 키의 값을 확인하려고 시도하면 KeyError 오류가 발생한다.

따라서 사전의 키-값을 확인할 때 발생할 수 있는 오류를 방지하기 위해 보통 아래처럼 if ... else ... 조건문을 사용한다.

그런데 get() 메서드는 대괄호 기호와 동일한 일을 하면서 오류를 발생시키지 않는다.

get() 메서드는 키가 존재하자 않으면 오류를 발생시키는 대신에 None을 반환한다. 또한, 키가 존재하지 않을 때 지정된 값을 반환하도록 할 수도 있다. 지정할 값을 둘째 인자로 정해놓으면 된다.

결론적으로, 인덱싱 방식으로 키와 관련된 값을 확인하는 것 보다는 get() 메서드를 사용하면 오류 발생 가능성을 줄일 수 있다.

defaultdict 클래스

문자열 맨 처음에 위치한 알파벳을 기준으로 하여 문자열을 정리하고자 한다. 주어진 단어는 다음과 같다.

위 설명을 코드로 구현하면 다음과 같다.

잘 작동한다. 하지만 알파벳이 이미 사전에 키로 포함되어 있는가를 먼저 확인해야 하는 불편함이 존재한다. 만약에 if ... else ...를 사용하지 않으면 오류가 발생한다.

이유는 'apple' 단어에서 'a' : ['apple']을 추가 해야 하는데 'a'가 아직 키로 지정되지 않았기에 오류가 나는 것이다.

반면에 아래와 같이 하면 오류가 발생하진 않지만 제대로 작동하지 않는다.

이유는 새로운 단어로 매번 키의 값이 업데이트되기 때문이다. 이와 같이 키가 기존에 사용되었는지 여부를 매번 확인하는 불편함을 한 번에 해결하려면 collections 모듈의 defaultdict 클래스를 활용한다. 즉, 굳이 키의 사용여부를 확인할 필요가 없다. 이유는 만약에 키로 사용된 적이 없다면 키의 값으로 비어있는 리스트를 만들어서 항목을 추가해주기 때문이다.

참고: 사전 자료형의 setdefault() 메서드가 유사한 기능을 지원한다. 하지만 defaultdict 클래스를 보다 많이 사용한다.

항목 삭제

del 예약어와 pop() 메서드를 이용하여 특정 키가 사용된 항목을 삭제할 수 있다.

del 예약어는 함수가 아니라 파이썬 자체에서 지원하는 특별한 기능을 가진 명령문이다. 아래 명령문은 5를 키워드로 갖는 5: 'some value'를 사전에서 삭제한다.

반면에 pop() 메서드는 지정 항목을 삭제하면서 동시에 지정된 키와 연관된 값을 반환한다.

keys() 메서드

키만 모아 놓은 리스트를 구할 수 있다.

values() 메서드

값만 모아 놓은 리스트를 구할 수 있다.

사전 합치기

하나의 사전에 포함된 항목 전체를 다른 사전에 추가할 수 있다. 아래 코드는 d1 사전에 두 개의 항목을 추가한다.

주의사항: 동일한 키가 추가될 경우 기존에 사용된 값이 새로운 값으로 업데이트 된다.

항목 업데이트

기존에 포함된 키-값 에서 값을 변경하려면 다음과 같이 한다. 리스트에서 항목을 수정하는 방식과 유사하며, 인덱스 대신에 키를 이용한다. 예를 들어, 아래 코드는 'language'의 값을 'python' 에서 'python3'로 업데이트한다.

dict() 함수

모든 항목이 길이가 2인 튜플 또는 리스트인 모음 자료형을 인자로 사용하여 새로운 사전을 생성한다.

zip() 함수를 이용하여 두 개의 리스트 또는 튜플을 엮어 사전을 쉽게 생성할 수 있다.

키로 사용될 수 있는 자료형

변경 불가능한 객체만 사전의 키로 사용될 수 있다. 예를 들어, 문자열, 정수, 실수, 튜플 등이다. 단, 튜플의 항목에 리스트 등 변경 가능한 값이 사용되지 않아야 한다.

이렇게 사전의 키로 사용될 수 있는 값은 해시 가능(hashable)하다고 하며 hash() 함수를 이용하여 해시 가능 여부를 판단할 수 있다. hash() 함수의 반환값은 두 종류이다.

문자열과 정수로만 이루어진 튜플은 해시 가능이다.

따라서 튜플도 사전의 키로 사용할 수 있다.

반면에 리스트를 포함한 튜플은 해시 불가능이다.

따라서 (1, 2, [2, 3])을 키로 사용하면 오류가 발생한다.

집합

집합 자료형은 수학에서 배운 집합과 동일한 개념이다. 중괄호 기호를 사용하지만 사전 자료형과 혼동되지는 않을 것이다. 집합의 항목들 사이에는 순서가 없으며, 중복도 허용하지 않는다.

참고: 사전과 집합은 순차 자료형이 아니다.

순서와 원소의 중첩 여부와 상관 없이 동일한 원소를 포함하면 동일한 집합으로 간주한다.

set() 함수

set() 함수를 이용하여 리스트, 튜플 등을 집합으로 변환시킬 수 있다.

이 기법은 리스트와 튜플에서 중복된 항목을 제거하고자 할 때 유용하다.

항목 추가/삭제

집합은 변경이 가능하다. 항목 추가는 add() 메서드를 활용한다.

항목 삭제는 remove() 메서드를 이용한다. remove() 메서드는 원소를 삭제하지만, 삭제된 값을 반환하지는 않는다. 실제 반환값은 None이다.

없는 항목을 삭제하려 하면 오류가 발생한다.

집합 연산

합집합 연산

union() 메서드는 두 집합의 합집합을 반환한다.

참고: 엄밀히 따지면 a.union(b)는 집합 a에 집합 b의 원소를 추가하는 방식으로 새로운 집합을 생성한다.

이항 연산자 |가 합집합 연산을수행한다.

교집합 연산

intersection() 메서드는 두 집합의 교집합을 반환한다.

참고: 엄밀히 따지면 a.intersection(b)는 집합 a의 원소 중에서 집합 b에 속한 원소만을 모아 새로운 집합을 생성한다.

이항 연산자 &가 교집합 연산을수행한다.

주의사항: 합집합, 교집합 연산은 기존의 집합은 변경하지 않으면서 새로운 집합을 생성한다.

부분집합 여부 판단

issubset() 메서드를 이용한다.

issuperset() 메서드는 상위집합(superset) 여부를 판단한다.

원소의 자료형

사전의 키의 경우처럼 집합의 원소는 모두 해시 가능이어야 한다. 즉, 리스트는 집합의 원소가 될 수 없다.

조건제시법

리스트, 집합, 사전을 수학 시간에 배운 조건제시법(comprehension)을 이용하여 정의할 수 있다. 이 기법은 특히 리스트와 함께 매우 유용하게 활용된다.

리스트 조건제시법

예를 들어, 0부터 9 까지의 자연수 중에서 짝수로 이루어진 집합을 수학에서 조건제시법으로 아래와 같이 정의한다.

{ x | 0 < x < 10, 단 x는 짝수 } = { 0, 2, 4, 6, 8 }

여기서 집합 기호를 대괄호로 바꾸면 거의 바로 리스트 조건제시법이 된다.

'위 조건제시법은 아래 for 반복문을 활용한 아래 코드와 동일하다.

예제

문자열로 이루어진 리스트를 이용하여 모두 대문자로 전환된 문자열들의 리스트를 생성할 수 있다. 단, 문자열의 길이가 2보다 커야 한다.

집합 조건제시법

집합에 대한 조건제시법 사용도 유사하다. 아래 코드는 앞서 사용된 문자열들의 길이를 원소로 갖는 집합을 생성한다.

사전 조건제시법

조건제시법을 이용하여 사전을 생성하는 과정도 유사하다. 아래 코드는 앞서 사용된 문자열을 키로, 문자열의 길이를 값으로 하는 사전을 생성한다.

아래 코드는 앞서 사용된 문자열을 키로, 문자열의 인덱스를 값으로 하는 사전을 생성한다.

중첩 조건제시법

예제

아래 리스트는 중첩 리스트이다.

all_data에 포함된 이름 중에서 알파벳 n이 사용된 이름으로만 구성된 리스트를 작성하고자 한다. 먼저, 각 리스트에서 조건을 만족하는 이름으로 구성된 리스트를 조건제시법으로 구현하면 다음과 같다.

먼저, 첫째 리스트를 대상으로 한다.

둘째 리스트가 대상이면 다음과 같다.

위 과정을 한 번에 진행하려면 아래와 같이 for 반복문을 이용하면 된다. 단, 이번에는 이름을 담을 리스트를 미리 준비한다.

이와 같이 for 반복문 안에 리스트 조건제시법이 사용된 경우 이중 조건제시법을 사용할 수 있다.

예제

중첩 리스트, 중첩 튜플, 또는 아래와 같이 튜플과 리스트가 중첩으로 사용된 경우 모든 중첩을 제거하고 사용된 항목으로만 이루어진 리스트 또는 튜플을 생성할 때 중첩 조건제시법이 매우 유용하다.

참고: 이렇게 중첩 사용된 모음 자료형을 1차원 리스트로 단순화 시키는 작업을 영어로 flatten이라 한다.

위 조건제시법이 작동하는 과정을 아래 for 반복문이 설명한다.

예제

아래 코드는 항목으로 사용된 튜플을 모두 리스트로 변환하여 중첩 리스트를 생성한다.