"문자열은 그냥 문자 배열이야. 유일한 반전은, Python 에선 그걸 편집할 수 없다는 거고 — 그 규칙 하나가 유명한 성능 함정을 만들어."
밑은 배열이야
배열에 대해 배운 모든 게 문자열에 적용돼, 문자열이 문자 배열 이니까. s[3] 은 O(1) 주소 산술. 문자 찾으려 문자열 훑기는 O(n). s[2:7] 슬라이싱은 그 범위를 복사, O(k). "첫 모음 찾기" 나 "이 단어 뒤집기" 를 배열 문제로 대하면, 이 트랙 전체의 기법이 곧장 넘어와.
유일한 반전: 불변성
여기서 문자열이 리스트랑 갈라져: Python 에서 문자열은 불변 (immutable) 이야. 문자를 제자리에서 못 바꿔 — s[0] = 'x' 는 에러야. 어떤 "수정" 이든 사실 완전히 새 문자열을 지어. 무해하게 들리는데 반복문 안에서 하면, 입문 Python 에서 가장 유명한 성능 자폭이 돼.
+= 함정
반복해서 이어붙여 큰 문자열 짓는 걸 생각해: 반복문 안 result += piece. 문자열이 불변이라, 각 += 는 기존 문자열을 못 늘려 — 완전히 새 문자열을 할당하고 지금까지 모든 문자를 복사해. 길이 k 문자열에 append 하면 k 문자를 복사해. 그걸 n 번 하면 1 + 2 + 3 + … + n ≈ n²/2 문자를 복사한 거야. 네 순진한 반복문이 몰래 O(n²) 이야.
고침은 한 줄 반사신경이야: 조각을 리스트에 모으고 (append 가 O(1)), "".join(pieces) 로 한 번에 녹여, 그게 O(n) 한 패스야. 같은 출력, O(n²) 대신 O(n). 이게 배열 렌즈가 값을 하는 거야 — 넌 이미 리스트-append 가 싸고 문자열-재건이 안 싼 걸 알잖아.
대체 왜 불변으로 만들어?
불변성은 벌이 아니야 — 진짜 걸 사줘. 문자열이 절대 안 바뀌어서, 해시 가능 (hashable) 할 수 있어 (그래서 dict 키나 set 멤버가 될 수 있어 — 다음 트랙 전체가 이거에 달림). 누가 밑에서 바꿀까 걱정 없이 프로그램 부분들 사이에 공유해도 안전해. 그리고 똑같은 문자열은 인터닝 될 수 있어 (한 번 저장하고 재사용). += 함정은 그 값이고; 해시 가능하고 공유 가능하고 안전한 문자열이 그걸로 산 거야.
피파의 고백
report += line 으로 거대 리포트를 지었어. 테스트 파일에선 즉시였고; 진짜 export 에선 꼬박 1분을 기었어. 아빠가 한 번 보고: "매 줄마다 리포트 전체를 다시 짓고 있잖아." 리스트랑 끝에 join 하나로 바꾸니 — 1분이 밀리초가 됐어. 어떤 강의보다 단단히 박혔어: 불변성은 제곱이 되기 전까진 안 보여.