I never fully understood Python for loops until I grasped the range function. Here is what I learnt
C 개발자가 Python for 루프를 이해하게 된 순간 — range 함수를 파헤치며 배운 것들
C 언어 배경의 개발자가 Python의 for 루프를 낯설어하다가 range 함수의 구조를 이해하면서 루프의 동작 방식을 파악하게 된 과정을 정리한 글입니다. range가 start·stop·step 인자를 받는 불변 시퀀스 객체이며, 크기와 무관하게 O(1)의 시간과 공간으로 생성된다는 사실을 설명하고, 비선형 반복은 while 루프가 더 적합하다는 점을 짚습니다.
- 주제
본문
C 언어에서 프로그래밍을 시작한 개발자에게 Python의 for 루프는 직관적이지 않을 수 있습니다. 저자는 C의 for(int i = 0; i < n; i++) 구조가 초기화, 조건 검사, 증감이라는 세 요소로 명확하게 나뉘어 있어 이해하기 쉬웠다고 회고합니다. 반면 Python의 for i in range(10):은 어디서 시작하는지, 무엇을 검사하는지, 누가 무엇을 증가시키는지가 드러나지 않아 혼란스러웠다고 말합니다.
range의 정체 — 뒤에 숨은 세 인자
저자는 Python의 for 루프가 사실상 문법적 편의에 가깝다고 설명합니다. range(10)은 내부적으로 range(0, 10, 1)과 동일하며, 첫 번째 인자는 시작값(포함), 두 번째 인자는 종료값(불포함), 세 번째 인자는 증가폭(step)을 의미합니다. 실제로 REPL에서 range(10) == range(0, 10, 1)이 True로 평가됩니다.
range는 Python 3.0부터 range 타입의 객체를 생성하는데, 이는 단순한 자리 표시자가 아니라 범위 내 숫자를 실제로 메모리에 모두 저장하지 않고 표현하는 불변(immutable) 시퀀스 객체입니다. 따라서 range 객체를 만드는 데는 범위가 아무리 커도 O(1)의 시간과 공간만 필요합니다.
list로 시각화하기
개념을 눈으로 확인하는 가장 쉬운 방법은 list()로 변환하는 것입니다. list(range(0, 10, 1))은 [0, 1, ..., 9]를, list(range(1, 10, 2))는 한 자릿수 홀수 [1, 3, 5, 7, 9]를, list(range(0, 10, 2))는 짝수 [0, 2, 4, 6, 8]를 반환합니다. step에 음수를 주면 감소하는 반복도 가능해서, list(range(10, 0, -1))은 [10, 9, ..., 1]이 됩니다. 또한 Python의 for..in은 list, tuple, dict, str 같은 컬렉션을 직접 순회할 수 있으며, dict의 경우 각 키를 방문합니다.
O(log n) 루프는 어디로 갔나
C에서는 for(int i = 1; i < n; i = i * 2)처럼 지수적으로 증가하는 O(log n) 루프나 i = i * i 형태의 O(log log n) 루프를 간단히 표현할 수 있습니다. Python에서 이를 구현하려면 while 루프가 더 자연스럽습니다. i = 1로 시작해 while i <= n: 조건 아래 i *= 2로 갱신하는 방식입니다. for 루프로도 가능하지만 훨씬 복잡해진다고 저자는 덧붙입니다.
저자는 이 글이 Python을 비판하려는 것이 아니라고 강조합니다. 오히려 Python의 for 루프는 C보다 할 수 있는 일이 많지만, range 함수를 제대로 이해하고 나서야 그 구조가 머릿속에 들어왔다고 말합니다. C처럼 인덱스를 직접 조작하는 언어에서 온 개발자에게 Python 반복의 진입점이 어디에 있는지를 보여주는 입문자 친화적 해설입니다.
원문: dev.to / 번역·요약: Trawling