리스트(List)
25명의 학생들의 시험 점수를 계산하는 프로그램을 작성한다고 해보자. 개인별 점수를 저장할 변수를 score1
, score2
, ..., score25
까지 25개의 변수가 필요하다. 학생이 100명, 1000명 증가한다면 인원에 맞는 변수의 선언은 비효율적이다.
C언어나 Java와 같은 언어에서는 다음과 같이 배열을 사용한다.
// 자료형 변수명[크기];
int score[25];
// 자료형[] 변수명 = new 자료형[크기];
int[] score = new int[25];
C, C++, Java는 배열을 선언한 후 같은 자료형을 저장하여 사용하는 방식이다. 파이썬에서는 리스트(list)를 사용한다.
score = [90, 92, ..., 88, 74]
리스트는 자료형을 선언하지 않고 리스트 이름을 선언한 후에 대괄호([]
) 사이에 값을 늘여놓고 사용하거나 list()
를 사용한다. 다른 프로그래밍 언어와 다르게 리스트에는 여러 자료형을 저장할 수 있다.
a = [90, 92, 84, 88, 74]
b = list((90, 92, 84, 88, 74))
c = ["파이썬", 900, 30.5, "자바", 850, 78.75]
d = list(("파이썬", 900, 30.5, "자바", 850, 78.75))
e = list("프로그래밍")
print(a, b, c, d, e, sep="\n") # print할 내용마다 줄 바꿈
[90, 92, 84, 88, 74]
[90, 92, 84, 88, 74]
['파이썬', 900, 30.5, '자바', 850, 78.75]
['파이썬', 900, 30.5, '자바', 850, 78.75]
['프', '로', '그', '래', '밍']
인덱싱(Indexing)
리스트의 값을 사용하기 위해서 인덱스를 이해해야 한다. C, C++, Java와 마찬가지로 처음 값의 인덱스는 0이다.
a = [90, 91, 92, 93, 94, 95, 96]
print(a[0])
90
값 | 90 | 91 | 92 | 93 | 94 | 95 | 96 |
인덱스 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
-7 | -6 | -5 | -4 | -3 | -2 | -1 |
파이썬에서 리스트에 접근하는 인덱스는 음수를 지정할 수 있다. 음수로 지정한 경우 마지막 요소부터 접근한다. a[-1]
인 경우 마지막 값인 96
을 가져온다.
슬라이싱(Slicing)
순회가능한 객체의 일부를 가져오는 방법을 슬라이싱이라고 한다. 슬라이싱은 인덱싱과 비슷하게 사용한다. a[시작:끝]
의 형태로 사용하며, 시작 인덱스는 포함하고 끝 인덱스는 포함하지 않는다. 즉, a[0:3]
은 a[0]
, a[1]
, a[2]
를 가져온다.
리스트 a
의 슬라이싱 결과는 다음과 같다.
슬라이싱 | 결과 | 설명 |
---|---|---|
a[0:3] | [90, 91, 92] | a[0]부터 a[2]까지 값 |
a[3:5] | [93, 94] | a[3]부터 a[4]까지 값 |
a[0:] | [90, 91, 92, 93, 94, 95, 96] | a[0]부터 마지막까지 |
a[3:] | [93, 94, 95, 96] | a[3]부터 마지막까지 |
a[:] | [90, 91, 92, 93, 94, 95, 96] | 리스트 a 전체 |
a[1:5:2] | [91, 93] | a[1]부터 a[4]까지 2씩 건너뜀 |
a[::2] | [90, 92, 94, 96] | 처음부터 마지막까지 2씩 건너뜀 |
a[1::2] | [91, 93, 95] | a[1]부터 마지막까지 2씩 건너뜀 |
a[-4:-2] | [93, 94] | a[-4]부터 a[-3]까지 값 |
a[-4:] | [93, 94, 95, 96] | a[-4]부터 마지막까지 |
a[100] | IndexError | 인덱스 범위를 벗어남 |
a[5:100] | [95, 96] | a[5]부터 마지막까지(인덱스가 범위를 초과한 경우 마지막까지) |
슬라이싱은 문자열에도 동일하게 적용된다.
ct = "프로그래밍"
print(ct[1], ct[-1])
로 밍
리스트 요소 수정하기
리스트 prog
에는 프로그래밍 언어 4가지를 저장하였다. 첫 번째 언어인 C
를 C++
로 수정하려면 prog
에 해당 인덱스를 표시하고 값을 할당하여 수정한다.
prog = ["C", "Java", "Python", "Go"]
prog[0] = "C++"
print(prog)
['C++', 'Java', 'Python', 'Go']
그러나 인덱스를 벗어나 prog[4] = "Ruby"
를 실행할 경우 에러(IndexError
)가 발생한다.
IndexError: list assignment index out of range
리스트 내 요소의 값을 수정하는 것은 다른 언어의 배열 값을 수정하는 방법과 같지만 다음 예제를 통해 리스트의 특징을 알아보자.
리스트 복사 1
prog = ["C", "Python", "Java"]
myprog = prog
print("prog:", prog)
print("myprog:", myprog)
prog[0] = "C++"
print("prog:", prog)
print("myprog:", myprog)
prog: ['C', 'Python', 'Java']
myprog: ['C', 'Python', 'Java']
prog: ['C++', 'Python', 'Java']
myprog: ['C++', 'Python', 'Java']
리스트 복사 2
prog = ["C", "Python", "Java"]
myprog = prog[:]
print("prog:", prog)
print("myprog:", myprog)
prog[0] = "C++"
print("prog:", prog)
print("myprog:", myprog)
prog: ['C', 'Python', 'Java']
myprog: ['C', 'Python', 'Java']
prog: ['C++', 'Python', 'Java']
myprog: ['C', 'Python', 'Java']
myprog=prog
라고 하면 myprog
가 prog
를 복제했다고 생각했을 것이다. 하지만 prog[0]
값을 수정하고 prog
와 myprog
를 출력하면 내용이 모두 변경된 것을 확인할 수 있다.
메모리 상에 있는 리스트를 여러 변수가 함께 사용하기 때문에 이와 같은 현상이 발생한다. 이 같은 현상을 얕은 복사(shallow copy)라고 한다. 리스트 값 전체를 다른 리스트에 복사하려면 myprog = prog[:]
를 사용하여 리스트 prog
안에 모든 값을 myprog
에 저장하는 것이다. 실행 결과를 확인하면 리스트 prog
와 myprog
의 요소 값들이 서로 다르다는 것을 알 수 있다.
리스트 연산
리스트 자료형도 몇 가지 연산을 지원한다. 별도의 함수를 사용하지 않고 연산자를 통한 예제를 통해 리스트 연산을 알아보자.
prog = ["C", "Python", "Java", "Go"]
webp = ["HTML", "PHP", "JavaScript"]
myprog = prog + webp
prog[0] = "D"
print(prog)
print(myprog)
['D', 'Python', 'Java', 'Go']
['C', 'Python', 'Java', 'Go', 'HTML', 'PHP', 'JavaScript']
리스트 prog
와 webp
를 concatenate(연결)하여 myprog
에 저장하였다. prog + webp
연산 이후 prog[0]
값을 수정했지만 리스트 myprog
에는 영향이 없다.
이번에는 리스트 myprog
에 prog
의 값과 "HTML"
을 연결하는 연산을 하려고 한다.
prog = ["C", "Python", "Java"]
myprog = prog + "HTML"
print(myprog)
TypeError: can only concatenate list (not "str") to list
하지만 리스트는 리스트끼리만 연결할 수 있다. int
(정수)나 str
(문자) 자료형은 리스트와 연결할 수 없기 때문에 myprog = prog + ["HTML"]
로 변경해보자
prog = ["C", "Python", "Java"]
myprog = prog + "HTML"
myprog = prog + ["HTML"]
print(myprog)
['C', 'Python', 'Java', 'HTML']
리스트 요소 값을 반복하기 위해서는 곱 연산자(*
)를 사용한다.
prog = ["C", "Python", "Java"]
data = [1, 2, 3]
print(prog * 2)
print(data * 3)
['C', 'Python', 'Java', 'C', 'Python', 'Java']
[1, 2, 3, 1, 2, 3, 1, 2, 3]
만약에 리스트끼리 곱한다면 어떻게 될까? print(prog * data)
를 실행할 경우 다음과 같은 에러(TypeError
)가 발생한다.
TypeError: can't multiply sequence by non-int of type 'list'
리스트 메서드(Method)
리스트는 다양한 메서드를 제공한다. 리스트 메서드는 리스트 객체에 적용할 수 있는 함수이다. 리스트 메서드는 리스트_변수.메서드()
의 형태로 사용한다. 다음은 자주 사용하는 리스트 메서드이다.
📍 index()
리스트에서 특정 값의 인덱스를 찾는 메서드이다. 리스트에 해당 값이 없으면 에러(ValueError
)가 발생한다.
prog = ["C", "Python", "Java", "Go"]
print(prog.index("Java"))
2
리스트에 없는 값의 index를 찾으려고 하면 에러가 발생한다.
prog = ["C", "Python", "Java", "Go"]
print(prog.index("HTML"))
ValueError: 'HTML' is not in list
다음과 같이 대소문자를 변경한 경우는 어떻게 될까?
prog = ["C", "Python", "Java", "Go"]
print(prog.index("java"))
ValueError: 'java' is not in list
리스트에 있는 값과 대소문자가 다르면 에러가 발생한다. 리스트에 있는 값과 대소문자가 다르면 ValueError
가 발생한다.
index()
는 대소문자를 구별한다는 것을 기억하자.
➕ append()
리스트의 마지막에 값을 추가하는 메서드이다. 리스트는 자료형의 제한이 없기 때문에 모든 자료형을 추가할 수 있다.
a = [1, 2, 3, 4]
b = ["C", "Python", "Java"]
a.append(5)
print(a)
a.append("Go")
print(a)
a.append([6, 7])
print(a)
a.append(b)
print(a)
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 'Go']
[1, 2, 3, 4, 5, 'Go', [6, 7]]
[1, 2, 3, 4, 5, 'Go', [6, 7], ['C', 'Python', 'Java']]
↔️ extend()
리스트의 마지막에 값을 추가하는 메서드이다. 하지만 append()
와는 다르게 두 개의 리스트를 하나로 합치는 역할을 한다.
a = [1, 2, 3, 4]
b = ["C", "Python", "Java"]
a.extend(b)
print(a)
[1, 2, 3, 4, 'C', 'Python', 'Java']
info 참고
리스트 a
, b
와 튜플 c
를 사용하여 extend()
의 사용 예제를 확인해보자.
a = [1, 2]
b = ["C", "Python"]
c = ("a", "b")
메서드 | 결과 |
---|---|
a.extend(3) | extend() 는 리스트끼리 사용하는 함수이다. 왼쪽과 같이 실행할 경우 에러(TypeError )가 발생한다. TypeError: 'int' object is not iterable3를 추가하려면 a.extend([3]) 로 사용해야 한다. |
a.extend(b) |
append() 와 달리 리스트 요소의 값만 추가한다.a.append(b) 는 다음과 같은 리스트 내에 리스트를 삽입한다.
|
a.extend(c) |
extend() 는 리스트와 튜플을 연결할 수 있다.a.append(c) 는 다음과 같은 리스트 내에 튜플을 삽입한다.
|
🧩 insert()
리스트_변수.insert(인덱스, 값)
의 형태로 사용한다. 리스트의 특정 인덱스에 값을 삽입할 수 있다. 인덱스는 0부터 시작하며, 인덱스에 해당하는 값은 뒤로 밀려난다.
a = [1, 2, 3, 4]
a.insert(2, 5)
print(a)
[1, 2, 5, 3, 4]
📤 pop()
리스트_변수.pop(인덱스)
의 형태로 사용한다. 인덱스를 지정하면 리스트에서 해당 인덱스의 값을 삭제하고 삭제한 값을 반환한다. 인덱스를 지정하지 않으면 마지막 요소를 삭제한다. 인덱스가 범위를 벗어나면 에러(IndexError
)가 발생한다.
a = ["C", "Python", "Java", "Go"]
a.pop()
print(a)
b = a.pop(1)
print(b, a)
['C', 'Python', 'Java']
Python ['C', 'Java']
🗑️ remove()
리스트_변수.remove(값)
의 형태로 사용한다. 리스트에서 해당 값을 삭제한다. 리스트에 중복된 값이 있을 경우 첫 번째 값만 삭제한다.
a = ["C", "Python", "Java", "Go", "Python"]
a.remove("Python")
print(a)
['C', 'Java', 'Go', 'Python']
remove()
를 사용할 경우 리스트내에 해당 값이 존재하지 않을 경우 에러(ValueError
)가 발생한다.
ValueError: list.remove(x): x not in list
info 참고
in
연산자를 사용하여 리스트에 해당 값이 있는지 확인할 수 있다. in
연산자는 리스트에 해당 값이 있으면 True
, 없으면 False
를 반환한다.
a = ["C", "Python", "Java"]
print("Python" in a)
print("Go" in a)
True
False
in
연산자를 사용하여 삭제 에러를 방지할 수 있다.
a = ["C", "Python", "Java"]
if "Go" in a:
a.remove("Go")
else:
print("리스트에 Go가 없습니다.")
리스트에 Go가 없습니다.
🔢 count()
리스트_변수.count(값)
의 형태로 사용한다. 리스트에서 해당 값이 몇 개 있는지 세는 메서드이다.
a = ["C", "Python", "Java", "Go", "Python"]
print(a.count("Python"))
2
🔀 sort()
리스트_변수.sort()
의 형태로 사용한다. 리스트를 정렬하는 메서드이다. 기본적으로 오름차순으로 정렬한다.
a = [7, 9, 5, 1, 4, 8, 3, 2, 6]
a.sort()
print(a)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
a = [7, 9, 5, 1, 4, 8, 3, 2, 6]
print(a.sort())
None
sort()
는 리스트 자체를 변경시키기 때문에 다시 되돌릴 수 없다. sort()
는 반환 값이 없기 때문에 None
이 출력된다.
🔄 reverse()
리스트_변수.reverse()
의 형태로 사용한다. 리스트를 역순으로 정렬하는 메서드이다. 리스트를 역순으로 정렬할 때는 sort()
와 마찬가지로 리스트 자체를 변경한다. reverse()
는 반환 값이 없기 때문에 None
이 출력된다.
a = [7, 9, 5, 1, 4, 8, 3, 2, 6]
a.reverse()
print(a)
[6, 2, 3, 8, 4, 1, 5, 9, 7]
리스트를 내림차순으로 정렬하기 위해 sort()
를 적용한 후에 reverse()
를 사용하면 내림차순으로 정렬할 수 있다.
a = [7, 9, 5, 1, 4, 8, 3, 2, 6]
a.sort()
a.reverse()
print(a)
[9, 8, 7, 6, 5, 4, 3, 2, 1]
간결한 코딩을 원한다면 다음과 같이 작성할 수 있다.
a = [7, 9, 5, 1, 4, 8, 3, 2, 6]
a.sort(reverse=True)
print(a)
[9, 8, 7, 6, 5, 4, 3, 2, 1]
이차원 리스트
리스트 안에 리스트나 튜플(tuple)이 여러 개 있을 때 다음과 같이 리스트로 묶을 수 있다.
a = [[1, 2, 3], ["a", "b"], (10, 20, 30)]
리스트 a
안에는 3개의 요소가 있다. 다음 출력문을 통해 이차원 리스트의 요소를 확인해보자.
a = [[1, 2, 3], ["a", "b"], (10, 20, 30)]
print(a[0], a[0][1])
print(a[1][1])
print(a[2][1])
[1, 2, 3] 2
b
20
a[0]
은 [1, 2, 3]
, a[1]
은 ["a", "b"]
, a[2]
는 (10, 20, 30)
이다.
print(a[0][1])
은 a[0]
값인 [1, 2, 3]
의 인덱스 1
에 해당하는 값인 2
를 출력한다.