
이미지 출처: Pexels · Eva Bronzini · Pexels License
회원 가입 폼에서 넘어온 이름과 메일 주소를 다듬는 코드입니다. 8줄인데 그중 3줄이 틀렸고, 에러는 한 줄도 나지 않습니다.
name = " Hong Gildong "
email = "HONG@Example.COM"
name.strip()
email = email.lower
first = name[0:4]
print("이름:[" + name + "]")
print("메일:", email)
print("성:[" + first + "]")
돌려 보면 이렇게 나옵니다.
이름:[ Hong Gildong ]
메일: <built-in method lower of str object at 0x7f2a1c0b5230>
성:[ Ho]
세 줄 모두 틀렸습니다. 이름의 공백은 그대로고, 메일 자리에는 주소 대신 알 수 없는 문장이 찍혔고, 성은 Hong이 아니라 공백 두 칸에 Ho입니다.
그런데 에러는 한 줄도 나지 않았습니다. 빨간 글씨가 떴다면 그 자리를 봤을 텐데, 프로그램은 조용히 끝까지 돌았습니다. 이런 실수는 출력을 눈으로 확인하기 전까지 모릅니다.
세 개를 하나씩 잡아 보겠습니다.
실수 하나 — 메서드를 불렀는데 원본이 그대로입니다
name.strip()을 분명히 썼는데 공백이 남아 있습니다. 오타도 아니고 철자도 맞습니다.
name = " Hong Gildong "
name.strip()
print("[" + name + "]")
print("[" + name.strip() + "]")📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.
세 번째 줄에서 strip()을 불렀는데 네 번째 줄 출력에는 공백이 그대로입니다. 그런데 여섯 번째 줄처럼 name.strip()을 출력 자리에 바로 넣으면 공백이 사라진 값이 나옵니다.
파이썬 문자열은 한 번 만들어지면 고칠 수 없습니다. 그래서 strip()은 원본을 다듬는 것이 아니라, 공백을 뗀 새 문자열을 만들어 돌려줍니다. 돌려준 값을 아무도 받지 않으면 그 새 문자열은 만들어지자마자 버려집니다. 원본 name은 처음부터 끝까지 손대지 않은 채로 남습니다.

위 갈래가 지금 코드입니다. 새 값은 만들어졌지만 받는 곳이 없어 사라집니다. 아래 갈래처럼 이름표를 옮겨 붙여야 남습니다.
고치는 방법은 한 글자도 아니고 이름표를 다시 붙이는 것입니다.
name = name.strip()
upper(), lower(), replace(), title() 전부 같습니다. 문자열 메서드는 하나도 빠짐없이 새 값을 돌려주고 원본은 그대로 둡니다. 그래서 결과를 쓰려면 변수에 받거나, 받은 자리에서 바로 써야 합니다.
리스트를 배웠다면 헷갈릴 수 있습니다. list.append(3)은 리스트 자체를 바꿉니다. 리스트는 고칠 수 있고 문자열은 고칠 수 없습니다. 같은 점 표기법이라 같아 보이지만 동작이 반대입니다.
실수 둘 — 괄호를 빠뜨리면 기능 자체가 담깁니다
메일 자리에 찍힌 문장을 다시 보겠습니다.
<built-in method lower of str object at 0x7f2a1c0b5230>
email = email.lower에서 괄호를 빠뜨렸습니다. 괄호가 없으면 파이썬은 lower라는 기능 자체를 가리키는 것으로 읽습니다. 실행하라는 말이 아니라 "그 기능이 여기 있다"는 뜻입니다. 그 기능 덩어리가 email에 담겼고, 출력하니 위 문장이 나왔습니다.
email = "HONG@Example.COM"
print(email.lower)
print(email.lower())📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.
첫 줄은 기능을, 둘째 줄은 그 기능을 실행한 결과를 찍습니다. 괄호는 "지금 실행해"라는 신호입니다.
이 실수도 에러가 나지 않습니다. email에 뭔가 담기긴 했으니까요. 다만 그다음에 문자열인 줄 알고 쓰면 그때 가서 터집니다.
email = email.lower
print(email + "@")
TypeError: unsupported operand type(s) for +: 'builtin_function_or_method' and 'str'
에러가 실수한 줄이 아니라 한참 뒤에서 납니다. 이런 에러를 만나면 그 줄이 아니라 그 변수에 값이 담긴 자리를 거슬러 올라가야 합니다.
실수 셋 — 슬라이싱은 다듬기 전 문자열을 자릅니다
first = name[0:4]가 Hong이 아니라 공백 두 칸에 Ho를 가져온 이유는 둘입니다.
첫째, 자른 대상이 다듬기 전 문자열입니다. 실수 하나 때문에 name은 여전히 " Hong Gildong "이고, 그 0번 칸은 H가 아니라 공백입니다.
둘째, 끝 번호는 포함되지 않습니다. [0:4]는 0번부터 4번까지가 아니라 0번부터 3번까지 넉 자입니다.

칸마다 번호가 붙어 있고 번호는 0부터입니다. [0:4]는 색칠된 네 칸이고, 4번 칸은 들어가지 않습니다.
name = " Hong Gildong "
clean = name.strip()
print("[" + name[0:4] + "]")
print("[" + clean[0:4] + "]")
print(clean[-1])
print(clean[5:])
print(clean[::-1])📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.
다듬은 뒤에 자르면 Hong이 제대로 나옵니다. 나머지 셋은 자주 쓰는 모양입니다.
clean[-1]— 음수는 뒤에서 셉니다.-1이 마지막 글자입니다.clean[5:]— 끝 번호를 비우면 끝까지입니다.[:5]는 처음부터입니다.clean[::-1]— 간격을-1로 주면 거꾸로 읽습니다. 뒤집기의 관용 표현입니다.
여기서 순서 하나가 남습니다. 다듬고 나서 자르는 것과 자르고 나서 다듬는 것은 결과가 다릅니다. 지금 코드는 자르기가 먼저였고, 그래서 공백이 딸려 왔습니다.
고친 코드 여덟 줄
세 곳을 고칩니다. 줄 수는 그대로입니다.
name = " Hong Gildong "
email = "HONG@Example.COM"
name = name.strip()
email = email.lower()
first = name[0:4]
print("이름:[" + name + "]")
print("메일:", email)
print("성:[" + first + "]")📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.
이름:[Hong Gildong]
메일: hong@example.com
성:[Hong]

바뀐 것은 이름표 하나와 괄호 한 쌍입니다. 셋째 줄은 코드가 그대로인데 결과만 달라졌습니다 — 앞 줄이 고쳐졌기 때문입니다.
셋째 줄이 이 글에서 가장 중요한 자리입니다. 그 줄은 한 글자도 건드리지 않았는데 출력이 달라졌습니다. 문자열을 다루는 코드는 이렇게 앞 줄의 결과를 물려받습니다. 한 줄이 어긋나면 그 아래가 전부 조용히 어긋납니다.
자주 쓰는 메서드 여덟 개
오늘 쓴 것과 바로 옆에 붙어 다니는 것만 모았습니다. 전부 새 값을 돌려주고 원본은 그대로 둡니다.
| 메서드 | 하는 일 | 예 | 결과 |
|---|---|---|---|
strip() | 양 끝 공백을 뗀다 | " hi ".strip() | "hi" |
lower() / upper() | 소문자 / 대문자로 | "Hi".lower() | "hi" |
replace(a, b) | a를 b로 전부 바꾼다 | "a-b-c".replace("-", "") | "abc" |
split(구분자) | 잘라서 리스트로 | "a,b,c".split(",") | ["a", "b", "c"] |
"구분자".join(리스트) | 리스트를 붙여 문자열로 | "-".join(["a", "b"]) | "a-b" |
find(글자) | 몇 번 칸인지. 없으면 -1 | "hello".find("l") | 2 |
startswith(글자) | 그 글자로 시작하는지 | "hi.py".startswith("hi") | True |
count(글자) | 몇 번 나오는지 | "hello".count("l") | 2 |
두 가지만 더 짚겠습니다.
strip()은 양 끝만 뗍니다. 가운데 공백은 건드리지 않습니다. " Hong Gildong ".strip()은 "Hong Gildong"이고 가운데 두 칸은 남습니다. 가운데까지 없애려면 replace(" ", "")를 쓰는데, 이러면 이름이 HongGildong으로 붙어 버립니다. 하나로 줄이고 싶으면 " ".join(name.split())이 관용 표현입니다.
join은 방향이 헷갈립니다. 붙이는 쪽이 아니라 사이에 끼울 글자가 앞에 옵니다. ["a", "b"].join("-")이 아니라 "-".join(["a", "b"])입니다. 반대로 쓰면 AttributeError가 납니다.
raw = " Hong Gildong "
print("[" + raw.strip() + "]")
print("[" + raw.replace(" ", "") + "]")
print("[" + " ".join(raw.split()) + "]")📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.
한 글자만 바꾸면 결과는 어떻게 될까요
미니 퀴즈
참고 자료
- 파이썬 공식 자습서 3.1.2 "텍스트" — 문자열은 변경할 수 없다(immutable)는 설명과 인덱싱·슬라이싱 https://docs.python.org/ko/3/tutorial/introduction.html
- 파이썬 표준 라이브러리 4.7.1 "문자열 메서드" — strip·split·join·find 등 전체 목록 https://docs.python.org/ko/3/library/stdtypes.html
- 파이썬 공식 FAQ "문자열을 어떻게 수정하나요" https://docs.python.org/ko/3/faq/programming.html
포켓코딩(PYTHON2) 1편 · PYTHON1 총정리에서 이어집니다. 예제 코드는 강사 개인 GitHub 저장소의 강의 자료를 바탕으로 다시 썼습니다. 다음 편은 딕셔너리입니다. 순서가 아니라 이름표로 값을 꺼내는 {}와, 없는 열쇠를 물었을 때 나는 KeyError를 다룹니다.