C.W.K.
Stream
Lesson 01 of 07 · published

List — Python 의 기본 시퀀스

~22 min · list, indexing, slicing, sequence

Level 0호기심
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete

80% 의 컬렉션

Python 에서 컬렉션 하나만 익히고 살아남으라면 list 야. 순서 있고, 바꿀 수 있고, 크기 자유롭고, 안에 뭐든 들어가. 다른 list 도 들어가. 대괄호로 쓰고, 비어있어도 되고, 같은 종류만 넣어도 되고, 막 섞어도 돼.

list 만드는 세 가지 방법

리터럴 (대괄호 그대로), list() 생성자, 그리고 컴프리헨션 (lesson 6 에서 다룰 거야). 90% 는 리터럴로 짤 거야.

인덱싱 — 그리고 Python 의 음수 인덱스 마법

인덱스는 0 부터 시작. 다른 언어들이랑 똑같애. Python 만의 추가 트릭: 음수 인덱스가 뒤에서부터 센다. my_list[-1] 이 마지막. my_list[-2] 가 끝에서 두 번째. 특별한 문법 따위 없어 — 음수가 그냥 *작동* 해.

슬라이싱 — for 문 세 개분의 일을 한 줄에 끝내는 문법

슬라이싱 형식은 my_list[start:stop:step]. 각 부분 다 생략 가능. my_list[:5] = 앞의 다섯. my_list[-3:] = 뒤의 셋. my_list[::-1] = 통째 뒤집기. 슬라이싱은 새 리스트 를 반환해 — 원본은 그대로. 이거 한 번 익히면 평생 for 문 수십 개를 안 써도 돼. 진짜야.

list 는 mutable — 그 대가

만든 다음에 마음대로 바꿀 수 있어. append, extend, 슬라이스 할당, del. 그게 즐거움. 대가는 — list 는 dict 키로 못 써, set 안에 못 들어가, 그리고 함수에 list 를 넘기면 그 함수가 아빠 list 를 그 자리에서 바꿀 수도 있어.

주의: 클래식 함정 — def f(x=[]). 디폴트 list 는 함수 정의 시점에 한 번만 평가되고, 모든 호출이 같은 list 를 공유해. 대신 def f(x=None): if x is None: x = [] 패턴 써.

복사 — shallow vs deep

list2 = list1 은 복사가 아니야 — 두 이름이 같은 list 를 가리킬 뿐. list2 = list1[:] 또는 list2 = list1.copy()shallow 복사 — 바깥 list 는 새 거지만 안의 객체들은 여전히 공유돼. 중첩 구조 다룰 땐 copy.deepcopy() 손에 닿아.

Pythonic Way: "여러 개의 같은 종류" 가 필요하면 list. 값이 안 바뀔 거니까 tuple 쓰자 는 본능은 틀린 직관이야. tuple 의 진짜 쓸모는 lesson 3 에서.

Code

list 만드는 세 가지 방법·python
# 1. 리터럴 — 90% 는 이거
fruits = ["apple", "banana", "cherry"]

# 2. 생성자 — 어떤 iterable 도 list 로
letters = list("hello")          # ['h', 'e', 'l', 'l', 'o']
range_list = list(range(5))      # [0, 1, 2, 3, 4]

# 3. 빈 list 부터 시작해서 채우기
result = []
result.append(1)
result.append(2)
print(result)                    # [1, 2]
음수 인덱싱 — 뒤에서부터·python
scores = [88, 92, 75, 100, 64]

print(scores[0])    # 88   첫 원소
print(scores[-1])   # 64   마지막
print(scores[-2])   # 100  끝에서 두 번째

# 범위 벗어나면 IndexError — 양/음 양쪽 다
# print(scores[5])   # IndexError
# print(scores[-6])  # IndexError
슬라이싱 — start : stop : step·python
nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

print(nums[2:5])      # [2, 3, 4]      stop 은 EXCLUSIVE (포함 X)
print(nums[:3])       # [0, 1, 2]      처음부터
print(nums[7:])       # [7, 8, 9]      끝까지
print(nums[::2])      # [0, 2, 4, 6, 8]   두 칸씩
print(nums[::-1])     # [9, 8, ..., 0]  뒤집기
print(nums[-3:])      # [7, 8, 9]      뒤 세 개

# 슬라이싱은 항상 새 list. nums 는 그대로.
print(nums)           # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
슬라이스 할당 — 범위를 통째 갈아끼우기·python
data = [10, 20, 30, 40, 50]

# 3 개를 5 개로 교체
data[1:4] = ["a", "b", "c", "d", "e"]
print(data)           # [10, 'a', 'b', 'c', 'd', 'e', 50]

# 슬라이스 삭제
data[1:4] = []
print(data)           # [10, 'd', 'e', 50]

# 안 지우고 끼워넣기 — 길이 0 인 슬라이스
data[2:2] = ["X", "Y"]
print(data)           # [10, 'd', 'X', 'Y', 'e', 50]
alias / shallow / deep — 셋의 차이·python
import copy

original = [[1, 2], [3, 4]]

alias = original                     # 같은 list — 두 이름이 한 객체
shallow = original[:]                # 바깥은 새 거, 안은 공유
deep = copy.deepcopy(original)       # 바깥도 안도 다 새 거

original[0].append(99)

print(alias)    # [[1, 2, 99], [3, 4]]   — original 과 공유
print(shallow)  # [[1, 2, 99], [3, 4]]   — 안의 list 는 공유!
print(deep)     # [[1, 2], [3, 4]]       — 완전 독립
mutable 디폴트 인자 함정·python
# 이렇게 하면 안 돼
def bad(item, history=[]):
    history.append(item)
    return history

print(bad("a"))   # ['a']
print(bad("b"))   # ['a', 'b']    <- history 가 재사용됨
print(bad("c"))   # ['a', 'b', 'c']

# 이렇게
def good(item, history=None):
    if history is None:
        history = []
    history.append(item)
    return history

External links

Exercise

1 부터 10 까지 정수 10 개의 list 를 만들어. 그 다음 *슬라이싱만으로* (loop X, for X, comprehension X): (a) 앞 3 개 출력, (b) 뒤 3 개 출력, (c) 두 번째 원소부터 한 칸 건너 출력, (d) 뒤집어서 출력. 마지막에 원본 list 를 다시 출력해서 *그대로* 인지 확인.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.