본문 바로가기

Python

[Python Skill Up] 고급 리스트 기능

이번 포스팅에서는 파이썬을 활용한 고급 리스트 기능들에 대해 설명해 보도록 하겠다.
 

  • 리스트 복사 vs 리스트 변수 복사
  • 얕은 복사 vs 깊은 복사
  • 리스트 함수 vs 리스트 메서드
  • map, filter, reduce, lambda 함수
  • 언더스코어(_)의 기능

1. 리스트 복사 vs 리스트 변수 복사
- 파이썬의 변수는 한 컬렉션을 제대로 복사하려면 추가 작업이 필요하다.
 

a_list = [2, 4, 8]
b_list = a_list

b_list.append(100)
a_list.append(200)
b_list.append(1)

print(a_list) # [2, 4, 8, 100, 200, 1] 출력

 
- 위 예시 코드를 보면 알 수 있듯이, 둘 중 한 변수의 값을 변경하면 다른 하나도 함께 변경된다.
- 리스트 전체 항목을 별도로 복사하고 싶다면 아래와 같이 항목 간 복사(member-by-member)를 수행해야 한다. (가장 간단한 방법은 슬라이싱을 사용하는 것)
 

test_list = [1, 5, 9]
copy_list = [test_list[:] # 항목 간 복사

 
 
2. 얕은 복사 vs 깊은 복사
- 파이썬을 사용하면서 항상 위 문제로 인한 warning이 종종 발생하곤 했다. 특히 pandas 패키지를 통해 데이터프레임을 다룰 때 그랬는데, 이번 포스팅을 통해 얕은 복사와 깊은 복사의 차이를 명확하게 이해해서 더 이상 warning이 뜨지 않도록 코드를 작성하도록 하자!
- 이해를 돕기 위해, 예시 코드를 통해 두 복사 간 어떠한 차이가 있는지 확인해 보도록 하겠다.
 

# 1. 얕은 복사
chk_list1 = [1, 2, [5, 10]]
chk_list2 = chk_list1[:]

chk_list2[0] = 0
chk_list2[1] = 0
chk_list2[2][0] = 0
chk_list2[2][1] = 0

print(chk_list2) # [0, 0, [0, 0]] 출력
print(chk_list1) # [1, 2, [0, 0]] 출력

 
- 위 "1. 얕은 복사" 부분의 코드를 보면, chk_list2 값을 변경해도 chk_list1에는 반영되지 않을 것이라고 생각할 것이다. 그러나 실제로 결과를 보면 chk_list2 값이 변경되니 chk_list1도 변경됨을 확인할 수 있다.
- 왜 이러한 현상이 발생한 것일까? 이는 깊은 복사를 통해 1, 2를 복사하고 내부 리스트의 참조를 복사했기 때문이다. 항목 간 복사를 시도했지만, 리스트가 품고 있는 리스트는 참조였기 떄문에 두 리스트는 결국 하나의 리스트를 참조하게 된다.

얕은 복사 그림 예시

- 이에 대한 해결책은 아래와 같이 간단하다. 파이썬 copy 패키지deepcopy 함수를 사용해서 깊은 복사를 수행해주면 된다.
 

# 2. 깊은 복사
import copy

chk_list1 = [1, 2, [5, 10]]
chk_list2 = copy.deepcopy(chk_list1)

chk_list2[0] = 0
chk_list2[1] = 0
chk_list2[2][0] = 0
chk_list2[2][1] = 0

print(chk_list2) # [0, 0, [0, 0]] 출력
print(chk_list1) # [1, 2, [5, 10]] 출력

 

깊은 복사 그림 예시

 
 
3. 리스트 함수 vs 리스트 메서드
- 리스트 함수와 메서드의 가장 큰 차이점은 메서드는 리스트 값을 바로 변경해주는 반면, 함수는 새로운 리스트를 생성한다는 점이다.
- 또한 함수와 다르게 메서드점 기호(.)를 사용하여 호출한다.
- ex) sorted(컬렉션) vs 리스트.sort([key = None], [, reverse = False])
 
 
4. map, filter, reduce, lambda 함수
- map 메서드: 주어진 리스트의 전체 항목을 변환한 신규 리스트 생성
- filter 메서드: 구체적인 조건을 만족하는 항목들로 구성된 신규 리스트 생성
- functools 패키지의 reduce 함수 사용법은 아래와 같다.
 

# 사용법
import functools

functools.reduce(함수, 리스트)

 
- lambda 함수: 변수에 대입하지 않는 이상 이름이 존재하지 않는 함수로, 일반적으로 한 번만 사용하기 위해 만들어진다.
 

# 사용법 -> lambda 인수들: 반환값

# 예시
my_func = lambda x, y: x + y

sum1 = my_func(4, 5)
print(sum1) # 9 출력

sum2 = my_func(10, 13)
print(sum2) # 23 출력

 
- 일반적으로 lambda 함수는 아래와 같이 reduce 함수와 함께 유용하게 쓸 수 있다.
 

import functools

# 1부터 5까지 값을 모두 곱하기
chk = functools.reduce(lambda x, y: x * y, [1, 2, 3, 4, 5])

 
 
5. 언더스코어(_)의 기능
- "행 번호"가 중요하지 않고 다시 사용할 필요가 없다면, 기본적으로 변수나 함수 이름을 지을 때 명사를 구분하기 위한 용도로 사용하는 언더스코어(_)로 교체할 수 있다. (아래의 예시 코드를 보면 무슨 말인지 바로 이해가 될 것이다)
 

# 30 x 25의 2차원 리스트 생성
mat = [[0] * 25 for _ in range(30)]