Python 기본

파이썬(Python) 리스트 다루기: append와 extend의 차이점

나루하루001 2025. 6. 8. 23:53
반응형



왜 append와 extend의 차이를 알아야 할까?


파이썬을 배우다 보면 리스트를 다루는 방법은 필수적으로 알아야 하는 부분입니다.

 

특히 리스트에 요소를 추가하는 방법으로 자주 사용되는

append와 extend는 언뜻 보면 비슷해 보이지만,

실제로는 완전히 다른 동작 방식을 가지고 있습니다.

 

이 두 메서드의 차이점을 정확히 이해하지 못하면 예상치 못한 결과가 발생하거나,

코드의 효율성이 떨어질 수 있습니다.

 

특히 대용량 데이터를 처리할 때는 올바른 메서드 선택이 성능에 큰 영향을 미칠 수 있습니다. 

💡 이 글을 읽으면 얻을 수 있는 것
- append와 extend의 정확한 차이점 이해
- 각 메서드의 적절한 사용 시점 파악
- 코드 효율성 향상 방법
- 실제 프로젝트에서 자주 발생하는 실수 예방



append와 extend의 기본 개념


파이썬에서 리스트는 가장 많이 사용되는 자료구조 중 하나입니다.

리스트에 새로운 요소를 추가할 때 주로 사용하는 두 가지 메서드가 바로 append와 extend입니다.

 

append 메서드란?

 

`append()` 메서드는

리스트의 끝에 단일 요소를 추가합니다.

 

이때 추가되는 요소는 어떤 자료형이든 가능하며,

그 요소 자체가 리스트의 새로운 항목으로 추가됩니다.

<!-- append 기본 사용법 -->
fruits = ['apple', 'banana']
fruits.append('orange')
print(fruits)  # ['apple', 'banana', 'orange']

# 숫자 추가
fruits.append(100)
print(fruits)  # ['apple', 'banana', 'orange', 100]

# 리스트를 요소로 추가
fruits.append(['cherry', 'grape'])
print(fruits)  # ['apple', 'banana', 'orange', 100, ['cherry', 'grape']]

 

마지막 예시에서 볼 수 있듯이,

`append()`로 리스트를 추가하면 해당 리스트 자체가 하나의 요소로 추가됩니다.

즉, 리스트 안에 리스트가 중첩되는 형태가 됩니다.

 

extend 메서드란?

 

`extend()` 메서드는 리스트의 끝에 여러 요소를 추가합니다.

이때 인자로 전달되는 반복 가능한(iterable) 객체의 각 요소가 리스트에 개별적으로 추가됩니다.

<!-- extend 기본 사용법 -->
fruits = ['apple', 'banana']
fruits.extend(['orange', 'mango'])
print(fruits)  # ['apple', 'banana', 'orange', 'mango']

# 문자열 확장 (문자 하나씩 추가됨)
fruits.extend('kiwi')
print(fruits)  # ['apple', 'banana', 'orange', 'mango', 'k', 'i', 'w', 'i']

# 튜플로 확장
fruits.extend(('pear', 'melon'))
print(fruits)  # ['apple', 'banana', 'orange', 'mango', 'k', 'i', 'w', 'i', 'pear', 'melon']

`extend()`는 인자로 받은 반복 가능한 객체의 각 요소를 풀어서 리스트에 추가합니다.

문자열을 전달하면 문자열의 각 문자가 개별 요소로 추가된다는 점에 주의해야 합니다.

append와 extend의 핵심 차이점


이제 append와 extend의 핵심 차이점을 명확하게 이해해 봅시다.

1. 추가되는 요소의 형태

- append:단일 객체를 그대로 리스트의 새 요소로 추가

- extend:반복 가능한 객체의 각 요소를 풀어서 리스트에 추가

 

2. 리스트의 깊이 변화

- append: 리스트를 추가할 경우 중첩 리스트 생성 (깊이 증가)

- extend: 리스트의 깊이는 변하지 않고 요소만 추가 (깊이 유지)

 

3. 메모리 관점의 차이

- append: 원본 리스트의 ID는 변하지 않고, 새 요소의 참조만 추가

- extend: 원본 리스트의 ID는 변하지 않고, 여러 요소의 참조를 추가

 

4. 인자 타입의 제약

- append: 어떤 타입의 객체든 추가 가능

- extend: 반복 가능한(iterable) 객체만 인자로 사용 가능

<!-- 차이점 명확히 보기 -->
# append로 리스트 추가
list1 = [1, 2, 3]
list1.append([4, 5])
print(list1)  # [1, 2, 3, [4, 5]]

# extend로 리스트 추가
list2 = [1, 2, 3]
list2.extend([4, 5])
print(list2)  # [1, 2, 3, 4, 5]
🔍 핵심 차이점 요약
append([4, 5])는 [4, 5]라는 리스트 자체를 하나의 요소로 추가합니다.
extend([4, 5])는 4와 5를 개별 요소로 풀어서 추가합니다.

 

반응형

다양한 예시로 알아보기


이제 다양한 예시를 통해 append와 extend의 차이점을 더 깊이 이해해 봅시다.

 

예시 1: 다양한 데이터 타입 추가하기

<!-- 다양한 데이터 타입 추가 비교 -->
# 숫자 리스트에 다양한 타입 추가
numbers = [1, 2, 3]

# append 사용
numbers_append = numbers.copy()
numbers_append.append(4)              # 숫자 추가
numbers_append.append("five")         # 문자열 추가
numbers_append.append([6, 7])         # 리스트 추가
numbers_append.append({"key": "value"})  # 딕셔너리 추가

print("append 결과:", numbers_append)
# append 결과: [1, 2, 3, 4, 'five', [6, 7], {'key': 'value'}]

# extend 사용
numbers_extend = numbers.copy()
numbers_extend.extend([4])            # 리스트로 숫자 추가
numbers_extend.extend("five")         # 문자열 추가 (각 문자가 개별 요소로)
numbers_extend.extend([6, 7])         # 리스트 추가 (각 요소가 개별적으로)
# numbers_extend.extend({"key": "value"})  # 딕셔너리는 키만 추가됨

print("extend 결과:", numbers_extend)
# extend 결과: [1, 2, 3, 4, 'f', 'i', 'v', 'e', 6, 7]

 

예시 2: 중첩 리스트 처리하기

<!-- 중첩 리스트 처리 -->
# 초기 리스트
matrix = [[1, 2], [3, 4]]

# append로 행 추가
matrix_append = matrix.copy()
matrix_append.append([5, 6])
print("append로 행 추가:", matrix_append)
# append로 행 추가: [[1, 2], [3, 4], [5, 6]]

# extend로 행 추가 시도
matrix_extend = matrix.copy()
matrix_extend.extend([5, 6])
print("extend로 요소 추가:", matrix_extend)
# extend로 요소 추가: [[1, 2], [3, 4], 5, 6]

# extend로 여러 행 추가
matrix_extend_rows = matrix.copy()
matrix_extend_rows.extend([[5, 6], [7, 8]])
print("extend로 여러 행 추가:", matrix_extend_rows)
# extend로 여러 행 추가: [[1, 2], [3, 4], [5, 6], [7, 8]]

 

예시 3: 데이터 처리 시나리오

<!-- 실제 데이터 처리 시나리오 -->
# 사용자 데이터 수집 예제
users = []

# 새 사용자 추가 (append 사용)
users.append({"name": "Alice", "age": 25, "active": True})
users.append({"name": "Bob", "age": 30, "active": False})

print("사용자 목록:", users)
# 사용자 목록: [{'name': 'Alice', 'age': 25, 'active': True}, {'name': 'Bob', 'age': 30, 'active': False}]

# 여러 사용자를 한 번에 추가 (extend 사용)
new_users = [
    {"name": "Charlie", "age": 22, "active": True},
    {"name": "Diana", "age": 28, "active": True}
]
users.extend(new_users)

print("확장된 사용자 목록:", users)
# 확장된 사용자 목록: [{'name': 'Alice', 'age': 25, 'active': True}, {'name': 'Bob', 'age': 30, 'active': False}, {'name': 'Charlie', 'age': 22, 'active': True}, {'name': 'Diana', 'age': 28, 'active': True}]

 

예시 4: 리스트 ID 확인하기

<!-- 리스트 ID 변화 확인 -->
original = [1, 2, 3]
print("원본 ID:", id(original))  # 메모리 주소 출력

# append 후 ID 확인
original.append(4)
print("append 후 ID:", id(original))  # 동일한 ID 유지

# extend 후 ID 확인
original.extend([5, 6])
print("extend 후 ID:", id(original))  # 동일한 ID 유지

# + 연산자로 결합 (새 객체 생성)
new_list = original + [7, 8]
print("원본 ID:", id(original))  # 원본 ID 유지
print("새 리스트 ID:", id(new_list))  # 새로운 ID 생성
💡 중요 포인트
- append와 extend 모두 in-place 연산입니다. 즉, 원본 리스트를 직접 수정합니다.
- 반면 + 연산자나 슬라이싱은 새로운 리스트 객체를 생성합니다.
- in-place 연산은 메모리 효율이 좋지만, 원본 데이터가 변경된다는 점에 주의해야 합니다.



자주 하는 실수와 주의사항


append와 extend를 사용할 때 자주 발생하는 실수와 주의해야 할 점들을 알아봅시다.

 

실수 1: append로 여러 요소 추가하기

<!-- 잘못된 사용법 -->
numbers = [1, 2, 3]
numbers.append(4, 5, 6)  # TypeError: append() takes exactly one argument (3 given)

# 올바른 사용법
numbers.append([4, 5, 6])  # 리스트 자체를 요소로 추가
print(numbers)  # [1, 2, 3, [4, 5, 6]]

# 의도한 결과를 얻으려면 extend 사용
numbers = [1, 2, 3]
numbers.extend([4, 5, 6])
print(numbers)  # [1, 2, 3, 4, 5, 6]

 

실수 2: extend에 반복 불가능한 객체 전달하기

<!-- 잘못된 사용법 -->
numbers = [1, 2, 3]
numbers.extend(4)  # TypeError: 'int' object is not iterable

# 올바른 사용법
numbers.extend([4])  # 단일 요소도 리스트로 감싸야 함
print(numbers)  # [1, 2, 3, 4]

# 또는 append 사용
numbers = [1, 2, 3]
numbers.append(4)
print(numbers)  # [1, 2, 3, 4]

 

실수 3: 문자열 추가 시 예상치 못한 결과

<!-- 문자열 처리 주의사항 -->
words = ["hello", "world"]

# append로 문자열 추가
words.append("python")
print(words)  # ['hello', 'world', 'python']

# extend로 문자열 추가 (각 문자가 개별 요소로 추가됨)
words.extend("python")
print(words)  # ['hello', 'world', 'python', 'p', 'y', 't', 'h', 'o', 'n']

# 문자열을 하나의 요소로 extend하려면 리스트로 감싸야 함
words = ["hello", "world"]
words.extend(["python"])
print(words)  # ['hello', 'world', 'python']

 

실수 4: += 연산자 오해하기

<!-- += 연산자 이해하기 -->
# 리스트에 += 사용
numbers = [1, 2, 3]
numbers += [4, 5]  # extend와 동일한 효과
print(numbers)  # [1, 2, 3, 4, 5]

# 이것은 다음과 같음
numbers = [1, 2, 3]
numbers.extend([4, 5])
print(numbers)  # [1, 2, 3, 4, 5]

# 단일 요소 추가 시 주의
numbers = [1, 2, 3]
numbers += 4  # TypeError: 'int' object is not iterable
# 올바른 방법: numbers += [4] 또는 numbers.append(4)
⚠️ 주의사항 정리
1. append()는 항상 단일 객체만 추가합니다. 여러 요소를 개별적으로 추가하려면 extend()를 사용하세요.
2. extend()는 반드시 반복 가능한(iterable) 객체를 인자로 받아야 합니다.
3. 문자열을 extend()로 추가할 때는 각 문자가 개별 요소로 추가된다는 점을 기억하세요.
4. += 연산자는 리스트에 사용할 때 extend()와 동일하게 동작합니다.



성능 비교: 어떤 메서드가 더 효율적일까?


append와 extend의 성능 차이를 알아보고, 언제 어떤 메서드를 사용하는 것이 더 효율적인지 살펴봅시다. 

 

1. 단일 요소 vs 여러 요소 추가 성능

<!-- 성능 비교 코드 -->
import timeit

# 단일 요소 추가 성능 비교
append_single = """
my_list = []
for i in range(10000):
    my_list.append(i)
"""

extend_single = """
my_list = []
for i in range(10000):
    my_list.extend([i])
"""

print("단일 요소 10,000개 추가:")
print(f"append 시간: {timeit.timeit(append_single, number=100):.6f}초")
print(f"extend 시간: {timeit.timeit(extend_single, number=100):.6f}초")
# 결과 예시: append가 extend보다 약 20-30% 빠름

# 여러 요소 추가 성능 비교
append_multiple = """
my_list = []
items = list(range(1000))
for i in range(10):
    for item in items:
        my_list.append(item)
"""

extend_multiple = """
my_list = []
items = list(range(1000))
for i in range(10):
    my_list.extend(items)
"""

print("\n여러 요소 추가(1,000개 항목 10번):")
print(f"append 시간: {timeit.timeit(append_multiple, number=10):.6f}초")
print(f"extend 시간: {timeit.timeit(extend_multiple, number=10):.6f}초")
# 결과 예시: extend가 append보다 훨씬 빠름(5-10배)

 

2. 메모리 사용량 비교

<!-- 메모리 사용량 비교 -->
import sys

# append의 메모리 사용량
list_append = []
initial_size = sys.getsizeof(list_append)
list_append.append([1, 2, 3, 4, 5])
append_size = sys.getsizeof(list_append)

# extend의 메모리 사용량
list_extend = []
list_extend.extend([1, 2, 3, 4, 5])
extend_size = sys.getsizeof(list_extend)

print("메모리 사용량:")
print(f"append 후 증가: {append_size - initial_size} 바이트")
print(f"extend 후 증가: {extend_size - initial_size} 바이트")
# 결과: extend가 더 많은 메모리를 사용할 수 있음(요소 수가 많아질수록)

 

3. 다양한 상황별 성능 비교

📊 성능 비교 요약
시나리오 더 효율적인 메서드 이유
단일 요소 추가 append 오버헤드가 적고 목적에 맞게 최적화됨
여러 요소 추가 extend 내부적으로 최적화된 루프 사용
중첩 리스트 생성 append 리스트 구조 유지에 적합
대용량 데이터 병합 extend C 수준에서 최적화된 구현



상황별 최적의 선택 방법


이제 다양한 상황에서 append와 extend 중 어떤 것을 선택해야 하는지 알아봅시다.

 

1. append를 사용해야 하는 경우

  • 단일 요소 추가: 한 번에 하나의 요소만 추가할 때
  • 리스트를 요소로 추가: 리스트 자체를 하나의 항목으로 추가하고 싶을 때
  • 데이터 구조 유지: 중첩 구조를 유지해야 할 때
<!-- append 사용 예시 -->
# 단일 요소 추가
todo_list = ['운동하기', '책 읽기']
todo_list.append('코딩 공부')
print(todo_list)  # ['운동하기', '책 읽기', '코딩 공부']

# 리스트를 요소로 추가
matrix = [[1, 2], [3, 4]]
matrix.append([5, 6])  # 새로운 행 추가
print(matrix)  # [[1, 2], [3, 4], [5, 6]]

# 객체를 요소로 추가
user_data = []
user_data.append({'id': 1, 'name': 'John'})
user_data.append({'id': 2, 'name': 'Jane'})
print(user_data)  # [{'id': 1, 'name': 'John'}, {'id': 2, 'name': 'Jane'}]

 

2. extend를 사용해야 하는 경우

  • 여러 요소 추가: 한 번에 여러 요소를 추가할 때
  • 리스트 병합: 두 리스트를 하나로 합칠 때
  • 대용량 데이터 처리: 많은 양의 데이터를 효율적으로 추가할 때
  • 평탄화(flattening): 중첩 리스트를 평탄화할 때
<!-- extend 사용 예시 -->
# 여러 요소 추가
fruits = ['apple', 'banana']
fruits.extend(['orange', 'grape', 'kiwi'])
print(fruits)  # ['apple', 'banana', 'orange', 'grape', 'kiwi']

# 리스트 병합
list1 = [1, 2, 3]
list2 = [4, 5, 6]
list1.extend(list2)
print(list1)  # [1, 2, 3, 4, 5, 6]

# 데이터베이스 결과 처리 예시
results = [1, 2, 3]
new_results = fetch_more_data()  # [4, 5, 6, 7] 반환 가정
results.extend(new_results)
print(results)  # [1, 2, 3, 4, 5, 6, 7]

# 중첩 리스트 평탄화 예시
nested = [[1, 2], [3, 4], [5, 6]]
flat = []
for sublist in nested:
    flat.extend(sublist)
print(flat)  # [1, 2, 3, 4, 5, 6]

 

3. 다른 대안 고려하기

<!-- 다른 대안 예시 -->
# + 연산자 사용 (새 리스트 생성)
list1 = [1, 2, 3]
list2 = [4, 5, 6]
combined = list1 + list2
print(combined)  # [1, 2, 3, 4, 5, 6]
print(list1)     # [1, 2, 3] (원본 유지)

# * 연산자로 리스트 반복
zeros = [0] * 5
print(zeros)  # [0, 0, 0, 0, 0]

# 리스트 컴프리헨션 사용
numbers = [1, 2, 3]
squared = [x**2 for x in numbers]
print(squared)  # [1, 4, 9]

# 제너레이터 표현식 사용 (메모리 효율적)
large_data = range(1000000)
generator = (x for x in large_data if x % 2 == 0)
# 필요할 때만 값을 생성
🔍 선택 가이드라인
  1. 단일 객체 추가: append() 사용
  2. 여러 요소 추가: extend() 사용
  3. 원본 보존 필요: + 연산자 또는 슬라이싱 사용
  4. 대용량 데이터: 메모리 효율을 위해 제너레이터 고려
  5. 코드 가독성: 목적이 명확하게 드러나는 방법 선택

항상 코드의 의도를 명확하게 표현하는 방법을 선택하세요. 성능 최적화는 그 다음 고려사항입니다.



정리 및 결론


이제 append와 extend의 차이점과 각각의 사용 사례에 대해 자세히 알아보았습니다. 이를 정리해 보겠습니다.

 

핵심 차이점 요약

특성 append() extend()
추가 방식 단일 객체를 그대로 추가 반복 가능한 객체의 각 요소를 개별적으로 추가
리스트 구조 리스트를 추가하면 중첩 구조 생성 리스트 깊이 유지, 요소만 추가
인자 타입 어떤 타입이든 가능 반복 가능한(iterable) 객체만 가능
성능(단일 요소) 더 빠름 약간 느림
성능(다중 요소) 느림(반복 호출 필요) 훨씬 빠름(최적화된 구현)
메모리 변화 원본 리스트 ID 유지 원본 리스트 ID 유지

최종 권장사항

  1. 의도를 명확히 하세요: 코드의 목적에 맞는 메서드를 선택하세요.
  2. 단일 요소는 append: 하나의 객체를 추가할 때는 항상 append를 사용하세요.
  3. 여러 요소는 extend: 여러 요소를 추가할 때는 항상 extend를 사용하세요.
  4. 성능이 중요하다면 벤치마크: 대용량 데이터를 다룰 때는 실제 성능을 측정해보세요.
  5. 가독성을 우선시: 약간의 성능 차이보다 코드 가독성이 더 중요합니다.

마무리

 

append와 extend의 차이점을 이해하는 것은

파이썬 프로그래밍에서 기본적이지만 매우 중요한 부분입니다.

 

이 두 메서드를 올바르게 사용하면 코드의 가독성이 향상되고,

의도하지 않은 버그를 방지할 수 있으며, 경우에 따라 성능도 개선할 수 있습니다.

 

append와 extend의 차이점을 명확히 이해하고 적절한 상황에서 올바르게 사용함으로써,

파이썬 코드는 더욱 강력하고 유지보수하기 쉬워질 것입니다. 이

 

글이 파이썬에서 리스트를 다루는 데 도움이 되었기를 바랍니다.

[ 파이썬 관련 블로그 글 목록 ] 

파이썬(Python) 블로그 목록
반응형