개발 공부 - Tools and Language/파이썬

[파이썬] 시퀀스 자료형 종합 정리

포리셔 2023. 6. 12. 17:42

시퀀스 자료형

우리가 파이썬에서 흔히 사용하는 자료형인 리스트, 튜플, 문자열, range 객체 등을 통틀어서 시퀀스 자료형이라고 일컫기도 합니다. 이 친구들은 공통적으로 값이 연속적(sequentially)으로 이어져 있다는 특징이 있습니다. 이러한 특징 때문에 파이썬에서 제공되는 메서드, 그 외에 코딩할 때 사용되는 테크닉 등이 여럿 겹치기도 합니다.

공통 기능 1. 특정한 값(요소, element)이 안에 있는지 확인하는 기능

시퀀스 자료형에 어떤 값이나 요소가 포함되어 있는지를 확인하고 싶을 때 in이라는 방법을 사용합니다. {요소 이름} in {시퀀스 자료}의 폼으로 작성하면 됩니다.
앞서 리스트, 튜플, 문자열, range 객체 등을 통틀어서 시퀀스 자료형이라고 했는데, 실제 예제에서도 같은 방법을 적용할 수 있는지 알아보죠. 먼저 리스트입니다.

shoes = ["아디다스", "나이키", "뉴발"]
print("shoes:", shoes)
print("'아디다스' in shoes:", "아디다스" in shoes) # in도 일종의 연산자 취급, True
print("'프로스펙스' in shoes:", "프로스펙스" in shoes) # False
print("'푸마' not in shoes:", "푸마" not in shoes, not '푸마' in shoes) # True, True

튜플과 range 객체도 같은 방식으로 적용됩니다.

t = ("마제소바", "토리동", "부타동", "점보부타동", "반숙계란")
print("t:", t) # 튜플
print("'쌀국수' in t:", '쌀국수' in t)
r = range(500, 100, -25)
print("r: ", list(r))
print("200 not in r", 200 not in r)

특이하게도 문자열은 연속된 부분집합의 형태로 단어를 검색할 수 있습니다. 오로지 문자열에서만 가능한 기능이고, 기초 코딩 테스트에서 굉장히 자주 쓰이는 테크닉이니 참고하시면 좋습니다.

phone_number = "010-9999-9999"
print("'0' in phone_number:", '0' in phone_number)
print("'010' in phone_number:", '010' in phone_number)
print("'011' in phone_number:", '011' in phone_number)

공통 기능 2. 연결 (concatenate)

넘파이나 판다스를 먼저 접하고 온 몇몇 분들은 이미 해당 라이브러리에서 concatenate 또는 concat이라는 이름의 메서드를 접해보셨을 겁니다. 사실 이름만 다를 뿐, 파이썬의 시퀀스 자료형에도 같은 기능이 있습니다. 간단하게 + 연산자를 이용하면 두 시퀀스 객체를 연결할 수 있습니다.

a = [0, 1, 2, 3] # a = list(range(4))
b = [4, 5, 6, 7] # b = list(range(4, 8))
# [0, 1, 2, 3, 4, 5, 6, 7]
print('a + b:', a + b)
a = tuple("abcd") # a = ("a", "b", "c", "d")와 동일
b = tuple("efgh") # b = ("e", "f", "g", "h")
print('a + b:', a + b)
greeting = '안녕하세요! '
my_name = input('당신의 이름:')
print(greeting + my_name)

Tip: 실무에서는 사실 + 연산자를 이용한 문자열 연결을 그리 권장하지 않습니다. 포맷 기능이나 f-string을 쓰는 것을 추천한다고 합니다.

range 객체에서의 연결 (안 됨)

공통 기능이지만 range 객체는 연결을 할 수 없습니다. 이유인 즉, range 객체는 시작점과 끝점, 간격이라는 세 인수에 기반을 둔 객체인데, 여러 개의 range 객체가 이 세 인수를 모두 만족시킨다는 보장이 없거니와, 그걸 파이썬에서 일일이 처리하기에는 연산 상에서 이득 볼 게 없다고 판단했나 봅니다. 하여튼 그런 이유로 range 객체는 연결할 수 없다는 점 알고 가시면 되겠습니다.

문자와 숫자 연결

money = int(input("받고 싶은 돈:"))
print("당신의 계좌에 " + str(money) + "만원이 입력되었습니다.")

문자열은 문자열끼리만 연결할 수 있기 때문에, 숫자는 str 자료형으로 다시 변환해야 합니다. 자료형 변환을 해주지 않으면 TypeError가 발생합니다.

이럴 거면 그냥 input()만 쓰지 그랬어그냥 포맷(%)이나 f-string 쓰면 편합니다

참고: 같은 구문을 Java에서 돌리면, 여기서는 또 Java가 알아서 포맷 변환을 해주기 때문에 자료형을 굳이 안 바꿔도 됩니다.

공통 기능 3. 반복

한 시퀀스 자료형을 반복할 때는 * 연산자를 이용하면 됩니다. 연산자 앞 또는 뒤에 붙어있는 숫자만큼 시퀀스 자료를 반복해줍니다. 단, 0이나 음의 정수를 넣으면 빈 시퀀스 객체가 반환됩니다. 또한 이 기능 역시 range 객체에는 적용 불가합니다. 이름만 공통인 기능

Tip: 넘파이의 브로드캐스팅과 자주 혼동되는 개념입니다! 넘파이에서의 스칼라 곱은 벡터와 같은 크기를 갖는 또 다른 ndarray 객체를 만든 뒤 요소별(element-wise) 연산을 수행하는 것으로 시퀀스 객체의 반복과는 다른 연산입니다.

k = [0, 10, 20, 30]
print("k를 3번 반복한다", k + k + k)
print("k를 3번 반복한다", k * 3)
print("k를 0번 반복한다", k * 0)

k *= 3
print(k) # 산술 연산자 적용 가능
hello = "안녕"
print(hello * 100)

공통 기능 4. 길이 구하기

파이썬에서는 영단어 length의 약자를 써서 len()라는 함수를 사용합니다.

타 언어의 경우, 객체의 길이는 객체에 딸린 메서드/함수이기 때문에 {변수 이름}.len 등으로 표현되기 때문에 다른 언어에서 파이썬으로 넘어오면 어떻게 길이를 구해야 하는지 혼동한는 경우가 있다고 합니다.

a = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
print(len(a))
b = ("a", 1, True, 1.5)
print(len(b))

range 객체의 경우 생성되는 숫자의 개수를 반환합니다.

print(len(range(75, 20, -4)))

문자열 객체는 포함된 글자의 개수를 반환합니다.

s = "오늘은 점심으로 마제소바를 먹을 것이다" # 주의: 따옴표의 개수는 제외됨.
print(len(s))

공통 기능 5. 인덱싱 (indexing)

시퀀스 객체는 여러 개의 데이터들이 묶여 있는 형태인 고로, 그 안의 요소들의 순서가 정해져 있습니다. 이때 시퀀스의 제일 앞에 있는 첫 번째 요소의 인덱스는 0부터 시작합니다. 이러한 순서를 반환해주는 인덱싱 기능을 사용하겠습니다.

a = [100, 200, 300, 400, 500]
print(a[1])
print(a[0])

print(a[2], a[4])
print("len(a):", len(a))

b = (5, 13, 21, 34, 55)
print("b[0]", b[0])
print("b[1]", b[1])
# range
r = range(2, 5)
print("r[2]",  r[2])
# 문자열 (string)
s = "오늘의 날씨를 알려드리겠습니다."
print(s[0])
print(s[7])

print(s)

음수 인덱스

파이썬에서 인덱스를 할 때는 시퀀스 객체의 맨 뒤 요소부터 인덱싱을 하는 경우도 있습니다. 이를 음수 인덱싱이라고 하며, -1부터 시작해 -len(a)까지의 인덱싱을 합니다. 

얘는 또 왜 1부터 시작을...

print("a[-1]", a[-1])
print("a[-3]", a[-3])

print(a[len(a)-1])

s = "마제소바"
print(s[-1])
sn = "991111-1234567"
print(sn[-7])

인덱스를 통해 요소에 값 할당 및 수정

print(a)
print(a[0]) 

b = [0] * 5
print("b", b)
b[0] = 137
b[1] = 44
b[2] = 9
b[3] = 13
b[4] = 88
print("b", b)

인덱스를 통해서 요소의 값을 재할당하는 것은 리스트에서만 가능합니다. 리스트 외에 튜플, 문자열, range 등은 read-only이고 수치 재할당이 불가능합니다. 앞의 두 개는 immutable 객체니까 그렇다 치고, range는....

요소 삭제

비슷한 논리로, 자주 사용되지는 않지만 요소 삭제도 가능합니다.

a = ["바나나", "키위", "콩"]
print(a)
del a[1] # 특정한 변수를 지울 때도 사용할 수 있는 기능
print(a)

참고로 이것도 튜플, 문자열, range는 안 먹힙니다.