티스토리 뷰

반응형

튜플

튜플(tuple)은 두 개 이상의 값을 하나의 단위로 묶는데 사용된다. 튜플의 각 원소는 순서를 가질 수 있으며, 값의 타입에 구애받지 않는다. 또한 튜플은 리스트와 달리 변경이 불가능한 객체이다. 튜플의 각 원소는 인덱스에 의해 참조 가능하기 때문에, 익명의 자료 구조로서도 활용이 가능하다.


birthday = (1990, 8, 31)
year = birthday[0]
month = birthday[1]
day = birthday[2]

튜플은 "변경할 수 없는" 객체라 하였다. 이는 튜플의 구성 요소에 대해서 원소를 삽입/삭제/교환할 수 없다는 의미이다.


birthday[1] = 9
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-2-584a55758c70> in <module>()
----> 1 birthday[2] = 9

TypeError: 'tuple' object does not support item assignment

하지만, 튜플은 더하거나, 부분열을 발췌하는 것이 가능하다. 그리고 파이썬의 변수는 다른 객체로 바인딩하는 것은 항상 허용되므로, 다음과 같이 birthday를 바꾸는 것은 허용된다.


birthday = birthday[:1] + (9, birthday[-1])
birthday
# (1980, 9, 30)

이 동작은 새로운 튜플 객체를 만들어서 이를 birthday라는 이름에 바인딩하는 것이므로 문법적으로나 기능적으로나 아무런 문제가 없다.

단, 아래와 같은 동작은 허용되지 않는다. 몇 개의 값을 묶어서 튜플로 만들 때에는 해당 객체에 대한 복사가 일어난다. 만약 변수를 포함한 일련의 값을 튜플로 묶은 다음에, 포함되었던 변수를 다른 값에 바인딩하는 것은 튜플에 아무런 영향을 미치지 못한다. (사실 이는 리스트와도 동일한 동작이다.)


a = 1980
b = 2
c = 1
birthday = (a, b, c)
# (1980, 2, 1)
b = 3
brithday
# (1980, 2, 1) :: 값이 변경되지 않았다. 

튜플 언패킹

사실 튜플 언패킹은 연속열 언패킹으로 불러도 된다. 이 테크닉은 사실 모든 연속열에 대해서 사용 가능하다.

튜플 언패킹은 대입 식의 좌/우변에 튜플(혹은 임의의 연속열)이 오고, 다른 쪽에 여러 개의 변수가 오는 패턴을 말한다. 튜플 언패킹으로 튜플의 각 요소를 개별 값으로 간단히 분해할 수 있다.


year = birthday[0]
month = birthday[1]
day = birthday[2]

# 아래 표현은 위 세 구문과 일치한다. 
year, month, day = birthday

튜플이 아닌 연속열은 어떤 것이든 여기에 올 수 있다. 온라인 저지 사이트에서 흔히 한 줄에 공백으로 구분된 몇 개의 정수 값을 입력을 받는 것을 처리할 때에는 다음과 같이 쓸 수 있다.


# 4개의 공백으로 구분된 정수를 입력받는 방법

# 일반적으로 이렇게 구현한다. 
s = [int(x) for x in input().split()]
n = s[0]
p = s[1]
q = s[2]
r = s[3]

# 이는 아래와 같이 한줄에 단축할 수 있다. 
n, p, q, r = [int(x) for x in input().split()][:4]

대입식에서 변수 이름 앞에 *를 붙이면 이는 튜플 혹은 리스트라는 의미이다.


year, *month_day = birthday
year
# 1980
month_day
# [8, 30]

튜플 언패킹을 이용하면 두 개의 변수를 중간의 임시 변수 없이 빠르게 교체할 수 있다.


a = 3
b = 5
(a, b) = (b, a)

이는 사실 2개 이상의 변수를 한꺼번에 교체하기에 매우 좋은 방법이다. 이 때, 우변의 괄호는 없어도 된다.


a, b, c, d, e = (b, c, a, e, d)

파라미터 언패킹

파이썬에서 인자의 개수가 정해지지 않은 함수를 정의할 때는, 필수적으로 주어져야 하는 인자를 제외한 인자의 이름 앞에 *을 붙인다. 그러면 함수 내에서 이 인자는 튜플로 취급된다.

다음은 2개 이상의 인자를 받아서 그 합을 구하는 함수이다. (물론 좀 더 파이써닉하게 작성하는 방법이 있다.)


def my_sum(a, b, *c):
    s = a + b
    for i in c:
        s += i
    return s

c는 빈 튜플일 수 있기 때문에 무시할 수 있으며, 따라서 함수를 호출할 때는 (2, 3), (2, 3, 4), (2, 3, 4, 5)와 같이 임의의 개수를 쓰는 것도 가능하다.

거꾸로 어떤 튜플이 있을 때, 이 튜플의 값을 분해해서 특정한 함수의 파라미터로 던지는 것도 거꾸로 가능하다.


x = (2, 3, 4)
my_sum(x)

TypeError                                 Traceback (most recent call last)
<ipython-input-47-13a6e6f3ff70> in <module>()
----> 1 my_sum(x)

TypeError: my_sum() missing 1 required positional argument: 'b'

이 구문은 에러이다. my_sum() 함수는 최소 2개의 인자를 받는데, 위 호출은 x라는 튜플 1개만을 함수에 전달했기 때문에 타입 에러가 난다. 튜플의 각 원소를 함수의 각 인자로 넘기고 싶다면 튜플 앞에 *를 붙이면 된다.


my_sum(*x)
# 9

보너스 : 이름이 있는 인자값

함수 선언시에 디폴트값이 있는 인자를 선언하는 경우가 있다. 이 경우에는 **kwd와 같이 별을 두 개 붙이면, 이는 함수 내부에서 사전으로 참조하게 된다. pyplot의 여러 메소드들은 함수의 그래프를 그리는데 필요한 옵션들을 받게 되는데, 이런 함수들이 이 형식의 파라미터를 쓰게 된다. 참고로 이렇게 이름, 값 쌍이 필요한 함수에 대해서는 사전을 이용해서 **를 붙여서 전달이 가능하다.

그외

원소가 하나인 튜플을 만들 수 있을까? 가능하다. 튜플 선언식은 마지막에 한 개의 컴마로 끝나도 된다.


x = 1
(x) # 1
(x,) # (x,) 원소 1개짜리 튜플

반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
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
글 보관함