Python enumerate() 함수란?
enumerate()는 리스트, 튜플, 문자열처럼 반복 가능한 데이터를 순회하면서 현재 순서인 인덱스와 요소 값을 함께 가져오는 Python 내장 함수입니다.
일반적인 for문은 값만 꺼내지만, enumerate()를 사용하면 순번과 값을 동시에 사용할 수 있습니다. 게시글 번호 출력, 메뉴 번호 표시, 데이터 위치 확인, 오류가 발생한 행 번호 기록 등에 자주 활용됩니다.
직접 인덱스 변수를 만들고 증가시키는 방식보다 코드가 짧고 실수 가능성도 낮습니다. Python다운 반복문을 작성할 때 반드시 알아두면 좋은 함수입니다.
enumerate() 기본 문법
enumerate()의 기본 문법은 다음과 같습니다.
enumerate(반복_가능한_객체, start=0)
| 구성 요소 | 설명 |
|---|---|
| 반복 가능한 객체 | 리스트, 튜플, 문자열, range 객체 등 |
start |
시작 인덱스를 지정하며 기본값은 0 |
| 반환값 | 인덱스와 값을 담은 enumerate 객체 |
가장 기본적인 예제를 살펴보겠습니다.
fruits = ["사과", "바나나", "포도"]
result = enumerate(fruits)
print(result)
print(list(result))
실행 결과
<enumerate object at 0x...>
[(0, '사과'), (1, '바나나'), (2, '포도')]
enumerate()는 각 요소를 (인덱스, 값) 형태의 튜플로 반환합니다. 결과를 바로 확인하려면 list()로 변환할 수 있습니다.
for문에서 enumerate() 사용하기
enumerate()는 보통 for문과 함께 사용합니다. 튜플 언패킹을 활용하면 인덱스와 값을 각각 다른 변수로 받을 수 있습니다.
fruits = ["사과", "바나나", "포도"]
for index, fruit in enumerate(fruits):
print(index, fruit)
실행 결과
0 사과
1 바나나
2 포도
index에는 현재 순서가 들어가고, fruit에는 리스트의 실제 값이 들어갑니다.
| 반복 순서 | index | fruit |
|---|---|---|
| 첫 번째 | 0 | 사과 |
| 두 번째 | 1 | 바나나 |
| 세 번째 | 2 | 포도 |
start 옵션으로 시작 번호 변경하기
enumerate()의 인덱스는 기본적으로 0부터 시작합니다. 사용자에게 보여주는 순번은 보통 1부터 시작하므로 start=1을 자주 사용합니다.
fruits = ["사과", "바나나", "포도"]
for number, fruit in enumerate(fruits, start=1):
print(f"{number}. {fruit}")
실행 결과
1. 사과
2. 바나나
3. 포도
start에는 1뿐 아니라 원하는 정수를 지정할 수 있습니다.
chapters = ["변수", "조건문", "반복문"]
for number, chapter in enumerate(chapters, start=10):
print(number, chapter)
실행 결과
10 변수
11 조건문
12 반복문
| 작성 방식 | 시작 번호 | 추천 상황 |
|---|---|---|
enumerate(data) |
0 | 실제 인덱스가 필요한 경우 |
enumerate(data, start=1) |
1 | 사용자용 순번 출력 |
enumerate(data, start=10) |
10 | 특정 번호부터 이어서 표시 |
일반 for문과 enumerate() 비교
인덱스를 사용하기 위해 직접 변수를 만들 수도 있지만, enumerate()를 사용하는 편이 더 간결하고 안전합니다.
직접 인덱스를 증가시키는 방식
languages = ["Python", "Java", "JavaScript"]
index = 0
for language in languages:
print(index, language)
index += 1
enumerate()를 사용하는 방식
languages = ["Python", "Java", "JavaScript"]
for index, language in enumerate(languages):
print(index, language)
실행 결과
0 Python
1 Java
2 JavaScript
| 항목 | 직접 인덱스 관리 | enumerate() |
|---|---|---|
| 코드 길이 | 상대적으로 길음 | 간결함 |
| 증가 처리 | 직접 작성 | 자동 처리 |
| 실수 가능성 | 증가 코드 누락 가능 | 낮음 |
| 가독성 | 상대적으로 낮음 | 높음 |
반복문에서 순서가 필요하다면 별도의 카운터 변수를 만들기보다 먼저
enumerate()사용을 검토하는 것이 좋습니다.
range(len())과 enumerate() 비교
초보자는 인덱스가 필요할 때 range(len())를 자주 사용합니다.
fruits = ["사과", "바나나", "포도"]
for index in range(len(fruits)):
print(index, fruits[index])
동일한 코드를 enumerate()로 작성하면 다음과 같습니다.
fruits = ["사과", "바나나", "포도"]
for index, fruit in enumerate(fruits):
print(index, fruit)
실행 결과
0 사과
1 바나나
2 포도
| 기준 | range(len()) |
enumerate() |
|---|---|---|
| 값 접근 | data[index] 필요 |
값을 직접 받음 |
| 인덱스 접근 | 가능 | 가능 |
| 가독성 | 상대적으로 장황함 | 간결함 |
| 추천 상황 | 인덱스로 원본을 수정해야 할 때 | 순번과 값을 읽을 때 |
단순히 순번과 값을 읽는 목적이라면 enumerate()가 더 자연스럽습니다. 인덱스를 사용해 리스트 요소를 직접 변경해야 한다면 range(len()) 방식이 필요할 수 있습니다.
enumerate()로 리스트 값 수정하기
enumerate()로 인덱스를 얻으면 해당 위치의 값을 직접 수정할 수 있습니다.
numbers = [10, 20, 30, 40]
for index, number in enumerate(numbers):
numbers[index] = number * 2
print(numbers)
실행 결과
[20, 40, 60, 80]
다만 단순히 새 리스트를 만드는 목적이라면 리스트 컴프리헨션이 더 명확할 수 있습니다.
numbers = [10, 20, 30, 40]
result = [number * 2 for number in numbers]
print(result)
실행 결과
[20, 40, 60, 80]
원본 리스트를 수정해야 하는지, 새로운 리스트를 만들어야 하는지에 따라 방식을 선택해야 합니다.
문자열에서 enumerate() 사용하기
문자열도 반복 가능한 객체이므로 각 문자의 위치와 값을 함께 확인할 수 있습니다.
text = "Python"
for index, character in enumerate(text):
print(index, character)
실행 결과
0 P
1 y
2 t
3 h
4 o
5 n
특정 문자가 위치한 인덱스를 찾는 데도 사용할 수 있습니다.
text = "banana"
for index, character in enumerate(text):
if character == "a":
print(f"a의 위치: {index}")
실행 결과
a의 위치: 1
a의 위치: 3
a의 위치: 5
str.find()는 첫 번째 위치만 반환하지만, enumerate()를 사용하면 조건에 맞는 모든 위치를 찾을 수 있습니다.
튜플과 enumerate() 사용하기
튜플도 리스트와 동일한 방식으로 순회할 수 있습니다.
colors = ("빨강", "초록", "파랑")
for number, color in enumerate(colors, start=1):
print(f"{number}번 색상: {color}")
실행 결과
1번 색상: 빨강
2번 색상: 초록
3번 색상: 파랑
튜플은 수정할 수 없는 자료형이지만, enumerate()로 순서와 값을 읽는 데에는 문제가 없습니다.
딕셔너리에서 enumerate() 사용하기
딕셔너리를 그대로 반복하면 키가 반환됩니다.
user = {
"name": "Kim",
"age": 30,
"job": "Developer"
}
for index, key in enumerate(user, start=1):
print(index, key)
실행 결과
1 name
2 age
3 job
키와 값을 함께 사용하려면 items()를 조합합니다.
user = {
"name": "Kim",
"age": 30,
"job": "Developer"
}
for number, (key, value) in enumerate(
user.items(),
start=1
):
print(f"{number}. {key}: {value}")
실행 결과
1. name: Kim
2. age: 30
3. job: Developer
user.items()가 (키, 값) 튜플을 반환하므로 number, (key, value)처럼 중첩 언패킹을 사용합니다.
enumerate()와 zip() 함께 사용하기
여러 리스트를 동시에 반복하면서 순번까지 필요하다면 enumerate()와 zip()을 함께 사용할 수 있습니다.
names = ["Kim", "Lee", "Park"]
scores = [90, 85, 95]
for number, (name, score) in enumerate(
zip(names, scores),
start=1
):
print(f"{number}. {name} - {score}점")
실행 결과
1. Kim - 90점
2. Lee - 85점
3. Park - 95점
코드의 처리 순서는 다음과 같습니다.
zip()이 이름과 점수를 하나의 튜플로 묶습니다.enumerate()가 각 튜플에 순번을 추가합니다.- 반복문에서 순번, 이름, 점수를 각각 언패킹합니다.
| 생성 결과 | 데이터 형태 |
|---|---|
zip(names, scores) |
("Kim", 90) |
enumerate(zip(...), 1) |
(1, ("Kim", 90)) |
| 반복문 언패킹 | number, (name, score) |
enumerate 객체의 특징
enumerate()는 리스트가 아니라 enumerate 객체를 반환합니다. 값이 필요할 때 하나씩 생성하는 반복자 방식으로 동작합니다.
languages = ["Python", "Java", "Go"]
result = enumerate(languages)
print(type(result))
print(list(result))
print(list(result))
실행 결과
<class 'enumerate'>
[(0, 'Python'), (1, 'Java'), (2, 'Go')]
[]
첫 번째 list(result)에서 모든 요소를 사용했기 때문에 두 번째 결과는 빈 리스트가 됩니다.
| 특징 | 설명 |
|---|---|
| 반환 형식 | enumerate 객체 |
| 각 요소 | (인덱스, 값) 튜플 |
| 기본 시작값 | 0 |
| 재사용 | 한 번 소비하면 다시 사용할 수 없음 |
enumerate 결과를 여러 번 사용해야 한다면 처음부터
list(enumerate(data))로 변환해 저장하세요.
조건문과 enumerate() 함께 사용하기
반복 중 특정 조건을 만족하는 데이터의 위치를 찾을 때 유용합니다.
scores = [45, 78, 92, 58, 88]
for index, score in enumerate(scores):
if score >= 80:
print(f"{index}번 인덱스: {score}점")
실행 결과
2번 인덱스: 92점
4번 인덱스: 88점
조건을 만족하는 첫 번째 위치만 찾고 싶다면 break를 사용할 수 있습니다.
numbers = [3, 7, 12, 18, 25]
for index, number in enumerate(numbers):
if number % 2 == 0:
print(f"첫 번째 짝수 위치: {index}")
print(f"값: {number}")
break
실행 결과
첫 번째 짝수 위치: 2
값: 12
리스트 컴프리헨션과 enumerate() 사용하기
enumerate()는 리스트 컴프리헨션 안에서도 사용할 수 있습니다.
fruits = ["사과", "바나나", "포도"]
result = [
f"{number}. {fruit}"
for number, fruit in enumerate(fruits, start=1)
]
print(result)
실행 결과
['1. 사과', '2. 바나나', '3. 포도']
조건을 추가해 특정 위치의 요소만 선택할 수도 있습니다.
numbers = [10, 20, 30, 40, 50]
result = [
number
for index, number in enumerate(numbers)
if index % 2 == 0
]
print(result)
실행 결과
[10, 30, 50]
위 예제는 값이 아니라 인덱스를 기준으로 짝수 위치의 요소를 선택합니다.
enumerate()로 특정 위치 제외하기
인덱스를 기준으로 특정 위치를 제외한 새 리스트를 만들 수 있습니다.
languages = [
"Python",
"Java",
"JavaScript",
"Go"
]
remove_index = 1
result = [
language
for index, language in enumerate(languages)
if index != remove_index
]
print(result)
실행 결과
['Python', 'JavaScript', 'Go']
리스트에서 값을 기준으로 삭제하면 동일한 값이 여러 개 있을 때 의도하지 않은 결과가 생길 수 있습니다. 특정 위치를 정확히 제외해야 한다면 인덱스를 활용하는 방법이 안전합니다.
실무 활용 예제: 메뉴 번호 출력하기
콘솔 프로그램에서 선택 메뉴를 표시할 때 enumerate()를 활용할 수 있습니다.
menus = [
"회원 조회",
"회원 등록",
"회원 삭제",
"프로그램 종료"
]
for number, menu in enumerate(menus, start=1):
print(f"{number}. {menu}")
실행 결과
1. 회원 조회
2. 회원 등록
3. 회원 삭제
4. 프로그램 종료
사용자 입력과 연결하면 간단한 메뉴 선택 프로그램을 만들 수 있습니다.
menus = [
"회원 조회",
"회원 등록",
"회원 삭제",
"프로그램 종료"
]
for number, menu in enumerate(menus, start=1):
print(f"{number}. {menu}")
choice = int(input("메뉴 번호를 선택하세요: "))
if 1 <= choice <= len(menus):
print(f"선택한 메뉴: {menus[choice - 1]}")
else:
print("올바른 번호를 입력하세요.")
입력 예시
2
실행 결과
선택한 메뉴: 회원 등록
화면에 표시되는 번호는 1부터 시작하지만 실제 리스트 인덱스는 0부터 시작하므로 choice - 1을 사용합니다.
실무 활용 예제: 오류가 있는 데이터 행 찾기
CSV나 API 데이터를 검사할 때 문제가 발생한 행 번호를 함께 기록하면 오류를 수정하기 쉽습니다.
users = [
{"name": "Kim", "email": "kim@example.com"},
{"name": "Lee", "email": ""},
{"name": "Park", "email": "park@example.com"},
{"name": "Choi", "email": None}
]
for row_number, user in enumerate(users, start=1):
email = user.get("email")
if not email:
print(
f"{row_number}번째 데이터 오류: "
f"이메일이 없습니다."
)
실행 결과
2번째 데이터 오류: 이메일이 없습니다.
4번째 데이터 오류: 이메일이 없습니다.
실제 CSV 파일의 첫 번째 행이 제목이라면 데이터 행 번호가 2부터 시작하도록 start=2를 사용할 수도 있습니다.
for row_number, user in enumerate(users, start=2):
print(row_number, user)
실무 활용 예제: 상품 순위 출력하기
판매량 순으로 정렬된 상품에 순위를 표시하는 예제입니다.
products = [
{"name": "키보드", "sales": 350},
{"name": "마우스", "sales": 520},
{"name": "모니터", "sales": 210}
]
sorted_products = sorted(
products,
key=lambda product: product["sales"],
reverse=True
)
for rank, product in enumerate(
sorted_products,
start=1
):
print(
f'{rank}위: {product["name"]} '
f'({product["sales"]}개)'
)
실행 결과
1위: 마우스 (520개)
2위: 키보드 (350개)
3위: 모니터 (210개)
sorted()로 데이터를 정렬하고 enumerate()로 순위를 붙이는 패턴은 통계, 랭킹, 검색 결과 화면에서 활용할 수 있습니다.
실무 활용 예제: 주문 목록 출력하기
상품명과 가격이 담긴 주문 목록에 순번을 붙이고 총금액을 계산해 보겠습니다.
orders = [
{"name": "키보드", "price": 50000},
{"name": "마우스", "price": 30000},
{"name": "USB 허브", "price": 25000}
]
total_price = 0
for number, order in enumerate(orders, start=1):
total_price += order["price"]
print(
f'{number}. {order["name"]} - '
f'{order["price"]:,}원'
)
print(f"총 주문 금액: {total_price:,}원")
실행 결과
1. 키보드 - 50,000원
2. 마우스 - 30,000원
3. USB 허브 - 25,000원
총 주문 금액: 105,000원
화면에 출력되는 순번과 내부 데이터 인덱스를 구분하면 사용자 인터페이스를 더 자연스럽게 구성할 수 있습니다.
enumerate() 사용 중 발생하는 대표적인 오류
인덱스와 값을 반대로 받는 실수
fruits = ["사과", "바나나", "포도"]
for fruit, index in enumerate(fruits):
print(fruit, index)
실행 결과
0 사과
1 바나나
2 포도
오류는 발생하지 않지만 변수 이름과 실제 값의 의미가 반대가 됩니다. 첫 번째 변수는 인덱스, 두 번째 변수는 값으로 작성하는 것이 일반적입니다.
for index, fruit in enumerate(fruits):
print(index, fruit)
start를 위치 인자로 오해하는 경우
start는 시작 번호를 정하는 옵션이며, 특정 위치부터 반복을 시작하는 기능이 아닙니다.
numbers = [10, 20, 30]
for index, number in enumerate(numbers, start=2):
print(index, number)
실행 결과
2 10
3 20
4 30
첫 번째와 두 번째 요소를 건너뛰는 것이 아니라, 표시되는 인덱스만 2부터 시작합니다. 실제 두 번째 위치부터 반복하려면 슬라이싱을 사용해야 합니다.
numbers = [10, 20, 30, 40]
for index, number in enumerate(
numbers[2:],
start=2
):
print(index, number)
실행 결과
2 30
3 40
enumerate 객체를 두 번 사용하는 실수
languages = ["Python", "Java"]
result = enumerate(languages)
print(list(result))
print(list(result))
실행 결과
[(0, 'Python'), (1, 'Java')]
[]
여러 번 사용해야 한다면 리스트로 변환한 결과를 저장합니다.
result = list(enumerate(languages))
print(result)
print(result)
튜플 언패킹 개수가 맞지 않는 경우
fruits = ["사과", "바나나"]
for item in enumerate(fruits):
print(item)
실행 결과
(0, '사과')
(1, '바나나')
이 방식은 정상적으로 동작하지만 item에는 튜플 전체가 들어갑니다. 인덱스와 값을 별도로 사용하려면 두 변수로 언패킹해야 합니다.
for index, fruit in enumerate(fruits):
print(index, fruit)
초보자가 자주 하는 실수
enumerate()가 리스트를 바로 반환한다고 생각하는 경우- 첫 번째 값과 두 번째 값의 순서를 반대로 이해하는 경우
start가 반복 시작 위치를 변경한다고 오해하는 경우- 사용자에게 보여주는 번호와 실제 리스트 인덱스를 혼동하는 경우
- enumerate 객체를 한 번 사용한 뒤 다시 사용하려는 경우
- 딕셔너리의 키와 값을 함께 사용할 때
items()를 빠뜨리는 경우 range(len())를 불필요하게 사용해 코드를 복잡하게 만드는 경우
enumerate() 사용 시 권장 방법
- 반복문에서 값과 순서가 모두 필요할 때 사용합니다.
- 사용자에게 보여주는 순번은
start=1로 작성합니다. - 실제 데이터 인덱스가 필요하다면 기본값인 0부터 시작합니다.
- 딕셔너리는
enumerate(dictionary.items())형태로 사용합니다. - 여러 리스트와 순번이 필요하면
enumerate(zip(...))를 활용합니다. - 결과를 여러 번 사용할 경우 리스트로 변환해 저장합니다.
- 변수 이름은
index,number,row_number,rank처럼 목적을 드러내게 작성합니다.
실무 팁: 화면용 순번과 내부 인덱스는 의미가 다릅니다. 화면 번호는 1부터, 리스트 인덱스는 0부터 시작하는 경우가 많으므로 변수 이름을 구분해 사용하세요.
VS Code에서 enumerate() 예제 실행하기
VS Code에서 간단한 Python 파일을 만들어 enumerate 예제를 실행해 보겠습니다.
- VS Code에서
enumerate_example.py파일을 만듭니다. - Python 확장 프로그램이 설치되어 있는지 확인합니다.
- 사용할 Python 인터프리터를 선택합니다.
- 아래 코드를 입력합니다.
- 터미널에서
python enumerate_example.py를 실행합니다.
tasks = [
{"title": "요구사항 정리", "done": True},
{"title": "기능 개발", "done": False},
{"title": "테스트 작성", "done": False}
]
for number, task in enumerate(tasks, start=1):
status = "완료" if task["done"] else "진행 중"
print(
f'{number}. {task["title"]} - {status}'
)
실행 결과
1. 요구사항 정리 - 완료
2. 기능 개발 - 진행 중
3. 테스트 작성 - 진행 중
GitHub 협업 시 주의할 점
협업 프로젝트에서는 인덱스가 실제 데이터 위치인지, 화면용 순번인지 명확하게 표현해야 합니다.
- 실제 위치는
index, 화면 순번은number나rank로 구분합니다. start값을 임의로 지정했다면 그 이유가 코드에 드러나야 합니다.- 복잡한 중첩 언패킹은 줄바꿈을 활용해 읽기 쉽게 작성합니다.
- enumerate 결과를 함수 밖으로 반환할 때는 필요한 자료형을 명확히 정합니다.
- 빈 데이터, 첫 번째 요소, 마지막 요소의 경계값을 테스트합니다.
- 리스트 수정이 필요한지 단순 조회가 필요한지 구분해 반복 방식을 선택합니다.
from collections.abc import Iterable
def create_numbered_items(
items: Iterable[str],
start: int = 1
) -> list[tuple[int, str]]:
return list(enumerate(items, start=start))
result = create_numbered_items(
["Python", "Java", "Go"]
)
print(result)
실행 결과
[(1, 'Python'), (2, 'Java'), (3, 'Go')]
enumerate() 핵심 정리
| 항목 | 핵심 내용 |
|---|---|
| 기본 문법 | enumerate(iterable, start=0) |
| 반환값 | enumerate 객체 |
| 각 요소 구조 | (인덱스, 값) |
| 기본 시작 번호 | 0 |
| 1부터 시작 | enumerate(data, start=1) |
| 딕셔너리 활용 | enumerate(data.items()) |
| 여러 리스트 활용 | enumerate(zip(...)) |
| 대표 대안 | range(len(data)) |
마무리
Python enumerate()는 반복 가능한 데이터를 순회하면서 인덱스와 값을 동시에 사용할 수 있게 해주는 내장 함수입니다. 별도의 카운터 변수를 만들거나 range(len())를 반복해서 작성하지 않아도 되어 코드가 더 짧고 명확해집니다.
실제 데이터 인덱스가 필요하다면 기본값인 0부터 시작하고, 메뉴 번호나 순위처럼 사용자에게 보여주는 순번은 start=1을 활용하면 좋습니다.
또한 zip(), 딕셔너리의 items(), 리스트 컴프리헨션과 조합하면 여러 데이터 처리 작업을 효율적으로 작성할 수 있습니다. 화면용 번호와 내부 인덱스를 구분하고 변수 이름을 명확하게 작성하는 것이 실무에서 특히 중요합니다.
FAQ
Q1. Python enumerate()는 무엇을 반환하나요?
enumerate()는 인덱스와 값을 담은 튜플을 차례로 생성하는 enumerate 객체를 반환합니다. 리스트가 필요하면 list(enumerate(data))로 변환할 수 있습니다.
Q2. enumerate()의 인덱스를 1부터 시작하려면 어떻게 하나요?
enumerate(data, start=1)처럼 start 옵션을 사용하면 됩니다.
Q3. enumerate()와 range(len()) 중 무엇이 더 좋은가요?
순번과 값을 읽는 목적이라면 enumerate()가 더 간결합니다. 인덱스를 이용해 원본 리스트를 직접 수정해야 한다면 range(len())가 필요한 경우도 있습니다.
Q4. 딕셔너리에도 enumerate()를 사용할 수 있나요?
네. 딕셔너리를 그대로 전달하면 키를 순회합니다. 키와 값을 함께 사용하려면 enumerate(dictionary.items()) 형태로 작성합니다.
Q5. enumerate()와 zip()을 함께 사용할 수 있나요?
네. enumerate(zip(list1, list2), start=1) 형태로 작성하면 여러 리스트의 값과 순번을 동시에 사용할 수 있습니다.
Q6. start 옵션은 반복 시작 위치를 변경하나요?
아니요. start는 반환되는 번호의 시작값만 변경합니다. 실제 데이터의 특정 위치부터 반복하려면 슬라이싱이나 itertools.islice()를 사용해야 합니다.
Q7. enumerate 객체를 두 번 사용할 수 있나요?
모든 요소를 한 번 소비한 enumerate 객체는 다시 사용할 수 없습니다. 여러 번 필요하다면 리스트나 튜플로 변환해 저장하세요.
함께 읽으면 좋은 글
'python' 카테고리의 다른 글
| Python raise 사용법 (0) | 2026.08.04 |
|---|---|
| Python 예외 처리 try-except (0) | 2026.07.30 |
| Python zip() 사용법 (0) | 2026.07.27 |
| Python filter() 사용법 (1) | 2026.07.22 |
| Python map() 사용법 (0) | 2026.07.20 |