모두를 위한 파이썬(PY4E) [10. 튜플] 강의

권혁준·2022년 4월 6일
0
post-thumbnail

Charles R. Severance (찰스 R. 세브란스)의 <모두를 위한 파이썬(PY4E)> 수강 내용
https://www.boostcourse.org/cs122/joinLectures/284901

10. 튜플

1) 튜플 개념 및 특징

학습목표

튜플과 리스트의 차이를 이해하고, 튜플의 특성을 활용해 문제를 해결할 수 있다.

핵심키워드

  • 튜플(tuple)
  • immutable

리스트(List)와 비슷한 컬렉션, 튜플(Tuple)
튜플은 리스트와 굉장히 비슷하다.
다음 코드를 보면 리스트와 차이는 단지 대괄호 대신 소괄호를 사용했다는 정도라는 것을 알 수 있다.
리스트와 같이 순서가 있어서 인덱스로 접근이 가능하고, 최대값도 찾을 수 있다.

x = ('Glenn','Sally','Joseph')
print(x[2])
# Joseph
y = (1,9,2)
print(y)
# (1,9,2)
print(max(y))
# 9

뿐만 아니라, for 반복문에서 반복을 시키면 리스트와 같이 원소를 순서대로 출력해준다.

for iter in y :
	print(iter)
# 1
# 9
# 2

변경 불가능한 속성(immutable)
하지만 리스트와 큰 차이가 있는데, 그것은 변경불가능(immutable), 즉, 값을 변경할 수 없다는 특성이다.
ex) 리스트에서는 다음과 같이 원소의 값을 변경할 수 있다.

x = [9,8,7]
x[2] = 6
print(x)
# [9,8,6]

하지만 다음과 같이 튜플일 경우에는 오류가 발생한다.
그 이유가 바로 변경 불가능한 속성 때문이다.

x = (9,8,7)
x[2] = 6
print(x)

# ---------------------------------------------------------------------------
# TypeError                                 Traceback (most recent call last)
# <ipython-input-4-6136e7d6cb90> in <module>()
#       1 x = (9, 8, 7)
# ----> 2 x[2] = 6
#       3 print(x)
# 
# TypeError: 'tuple' object does not support item assignment

이런 변경 불가능한 속성 때문에 튜플은 리스트보다 훨씬 더 효율적으로 동작한다. 용량도 적게 차지하고, 접근도 훨씬 빠르다.
물론, 이런 특성으로 인해 리스트에서 할 수 있는 일을 하지 못하는 경우도 있다.
다음 코드를 보며느, 한 번 생성된 튜플은 정렬하거나, 값을 추가하거나, 순서를 바꿀 수 없다.

x = (3,2,1)
x.sort()
# Traceback:
# AttributeError: 'tuple' object has no attribute 'sort'
x.append(5)
# Traceback:
# AttributeError: 'tuple' object has no attribute 'append'
x.reverse()
# Traceback:
# AttributeError: 'tuple' object has no attribute 'reverse'

이외에도 리스트에서 할 수 있는 것 중 값을 변경하는 것들은 튜플에서 할 수 없다.
구체적으로 리스트에 내장된 함수와 튜플에 내장된 함수를 비교하면 다음과 같다.

l = list()
dir(l)
# ['append','count','extend','index','insert','pop','remove','reverse','sort']

t = tuple()
dir(t)
# ['count','index']

즉, 값을 변경하지 않아도 되는 count, index와 같은 함수만 작동하는 것이다.

튜플의 장점
임시 변술로 활용
이런 변경이 되지는 않은 속성으로 인해 튜플은 파이썬에서 더 효율적으로 동작된다.
하지만 이런 특성은 입문하는 사람들에겐 큰 장점이 아닐 수 있다. 그러면 튜플은 언제 사용하면 좋을까?
튜플은 다음과 같이 좌변에 사용하면 간단하게 여러 변수에 값을 넣을 수 있다.
단, 이럴 경우 좌변과 우변의 갯수는 일치해야 한다.

(x,y) = (4,'fred')
print(y)
# fred
(a,b) = (99,98)
print(a)
# 99

이와 같은 특성을 잘 활용하면 함수에서 여러 개의 값을 한꺼번에 반환할 수 있다.

def r():
	return(10,20)
x,y = t()
print(x,y)

# 10,20

한 가지 팁은, 소괄호를 사용하지 않아도 컴마로 여러 값을 나열하면 파이썬에서는 튜플로 인식하기 때문에 다음과 같이 간단히 사용할 수도 있다.

x,y = 1,10
print(x,y)
# 1,10

x,y = y,x
print(x,y)
# 10,1

딕셔너리를 처리하는데 활용
지난 시간에 본 거처럼 딕셔너리의 items 메소드는 딕셔너리에 저장된 각 키와 값의 한 쌍을 튜플로 이루어진 리스트 형태로 만들어준다.
따라서 다음과 같이 사용할 수도 있다.

d = dict()
d['csev'] = 2
d['cwen'] = 4
for (k,v) in d.items():
	print(k,v)
# csev 2
# cwen 4

tups = d.items()
print(tups)
# dict_items([('csev',2),('cwen',4)])

여러 값에 대해 비교 가능
튜플의 또 다른 장점은 여러 값에 대해 비교가 가능하다는 점이다.
비교의 방법은 각 튜플의 가장 왼쪽 값끼리 비교한 후 둘의 값이 다를 경우에는 나머지 값들을 비교하지 않고 큰지 작은지 여부를 판단한다.
만약 가장 왼쪽 값이 동일한 경우에는 그 다음 값을 비교하고, 그 값도 같으면 또 다음 값을 비교하는 형태로 비교가 진행된다.

(0,1,2)<(5,1,2)
# True 값을 가진다.
(0,1,2000000) < (0,3,4)
# True 값을 가진다.
('Jones','Sally') < ('Jones','Sam')
# True 값을 가진다.
('Jones','Sally') > ('Adams','Sam')
# True 값을 가진다.

2) 튜플을 이용한 딕셔너리 정렬

학습목표

튜플의 특성을 활용해 딕셔너릴를 정렬할 수 있다.

핵심키워드

  • sorted 함수
  • List comprehesion

튜플의 특성을 활용해 딕셔너리 정렬하기
지난 시간에 다음과 같은 튜플의 특성을 배웠다. 튜플끼리 비교가 가능하며, 이때 가장 왼쪽에 있는 값끼리 비교한다는 것이었다.

(0,1,2) < (5,1,2)
# True
(0, 1, 2000000) < (0, 3, 4)
# True
( 'Jones', 'Sally' ) < ('Jones', 'Sam')
# True
( 'Jones', 'Sally') > ('Adams', 'Sam')
# True

그리고 딕셔너리의 items 메소드를 실행하면 키와 값이 쌍을 이루는 튜플로 이루어진 리스트 형태로 반환된다는 것도 배웠다.

tups = d.items()
print(tups)
# dict_items([('csev',2),('cwen',4)])

키를 기준으로 정렬하기
위의 두 가지 특성을 활용하면 키를 기준으로 딕셔너리를 정렬할 수 있다.
1. 딕셔너리에서 items 메소드를 실행해 튜플로 이루어진 리스트 형태로 만든다.
2. 이 리스트를 sorted 함수로 정렬한다. 그러면 각각의 튜플의 왼쪽 값, 즉, 키를 기준으로 정렬이 된다.
즉, 다음과 같은 코드로 딕셔너리를 키를 기준으로 정렬할 수 있다.

d = {'b':1,'a':10,'c':22}
d.items()
# dict_items([('b',1),('a',10),('c'22)])
sorted(d.items())
# [('a',10),('b'1),('c',22)]

여기에서 정렬된 키와 값을 한 줄씩 보기 좋게 출력하려면 이렇게 코드를 작성하면 된다. 여기에서 k, v는 소괄호가 없지만 컴마로 나열되어있기 때문에 튜플이다.

for k,v in sorted(d.items()):
	print(k,v)
# a 10
# b 1
# c 22

값을 기준으로 정렬하기
여기에서 값을 기준으로 정렬하려면 조금의 아이디어만 있으면 된다. 방법은 다음과 같다.
1. 딕셔너리에서 items 메소드를 실행한다.
2. 튜플을 활용해 키와 값을 분리한다.
3. 키와 값의 위치를 바꾼 리스트를 생성한다.
4. 생성된 리스트를 정렬한다.
이 과정을 코드로 표현하면 다음과 같다. 실행결과를 보면 값을 기준으로 오름차순 정렬이 된 것을 볼 수 있다.

c = {'a':10,'b':1,'c':22}
tmp = list()
for k,v in c.items():
	tmp.append((v,k))
    
print(tmp)
# [(10,'a'),(1,'b'),(22,'c')]
tmp = sorted(tmp)
print(tmp)
# [(1,'b'),(10,'a'),(22,'c')]

여기에서 만약 내림차순으로 정렬하고 싶다면 다음과 같이 sorted 함수에 reverse 옵션을 True로 설정하면 된다.

c = {'a':10, 'b':1, 'c':22}
tmp = list()
for k, v in c.items() :
    tmp.append( (v, k) )

print(tmp)
# [(10, 'a'), (1, 'b'), (22, 'c')]
tmp = sorted(tmp, reverse=True)
print(tmp)
# [(22, 'c'), (10, 'a'), (1, 'b')]

가장 많이 등장한 단어 Top 10 출력하기
이제 지난 시간에 배웠던 빈도 수를 출력하는 프로그램을 다시 살펴보자

fhand = open('romeo.txt')
counts = {}
for line in fhand:
	words = line.split()
    for word in words:
    	counts[word] = counts.get(word,0) + 1

이 코드가 실행되면 romeo.txt에 저장된 문장을 단어로 나눈 후, 각 단어와 그 빈도로 이루어진 딕셔너리가 생성되었던 것을 기억할 것이다.
이제 이 딕셔너리에 조금 전에 배웠던 키를 기준으로 내림차순 정렬하는 방법을 적용해보자.

lst = []
for key,val in counts.items():
	newtup = (val,key)
    lst.append(newtup)
    
lst = sorted(lst,reverse=True)

변수 이름이 조금 바뀌었을 뿐 조금 전에 봤던 코드와 동일한 형태이다.
이 코드가 실행되면 [(빈도수, 단어이름),(빈도수,단어이름),\dots,(빈도수,단어이름)]과 같은 형태로 데이터가 정렬된다.
이제 여기에서 빈도수 상위 10개의 단어를 단어, 빈도수 순으로 출력해보자.
지금까지 배운 내용을 활용해 이렇게 간단히 코드로 표현할 수 있다.

for val,key in lst[:10]:
	print(key,val)

조금 전에 작성한 코드의 전체 코드이다.

fhand = open('romeo.txt')
counts = {}
for line in fhand:
	words = line.split()
    for word in words:
    	counts[word] = counts.get(word,0) + 1
        
lst = []
for key,val in counts.items():
	newtup = (val,key)
    lst.append(newtup)
    
lst = sorted(lst,reverse=True)

for val,key in lst[:10]:
	print(key,val)

리스트 컴프리헨션(List comprehension)
마지막으로 리스트 컴프리헨션(List comprehension)이라는 것을 살펴보자.
이것은 조금 전에 작성했던 딕셔너리를 키를 기준으로 정렬해서 출력하는 코드이다.

c = {'a':10,'b':1,'c':22}
tmp = list()
for k,v in c.items():
	tmp.append((v,k))
    
tmp = sorted(tmp)
print(tmp)

# [(1,'b'),(10,'a'),(22,'c')]

그리고 다음의 코드는 정확히 위의 코드와 동일한 역할을 한다.

c = {'a':10,'b':1,'c':22}
print(sorted([(v,k) for k,v in c.items()]))
# [(1,'b'),(10,'a'),(22,'c')]

이러한 방식으로 리스트를 만드는 방식을 리스트 컴프리헨션이라고 부르는데, 지금은 매우 복잡해보지만 어느 시점에서는 이렇게 간결하게 리스트를 만들 수 있는 방법을 배우고 싶을 것이다.


3) <실습> 튜플을 이용한 딕셔너리 정렬

실습
exercise 10
clown.txt 파일 내용
the clown ran after the car and the car ran into the tent and the tent fell down on the clown and the car

fname = input('Enter File: ')
if len(fname) < 1 : fname = 'clown.txt'
hand = open(fname)

di = dict()
for lin in hand:
	lin = lin.rstrip()
    wds = lin.split()
    for w in wds:
		# idiom: retrieve/create/update counter
        di[w] = di.get(w,0) + 1
       
#print(di)

tmp = list()
for k,v in di.items():
    newt = (v,k)
    tmp.append(newt)

# print('Flipped',tmp)
tmp = sorted(tmp,reverse=True)
# print('Sorted',tmp[:5])

for v,k in tmp[:5]:
	print(k,v)
profile
비전공개발자의 개발일지

0개의 댓글

관련 채용 정보