Notes

[Python] Effective Python, 2nd | Ch2. 리스트와 딕셔너리 - (1) 리스트

Tigris 2022. 6. 7. 18:41
본 문서는 파이썬 코딩의 기술(원제: Effective Python: 59 Specific Ways to Write Better Python, 브렛 슬라킨 저, 오현석 역, 길벗 2020. 10. 30)을 공부 목적으로 정리한 글입니다. 필요한 부분만 발췌한 개인 정리용 글이기 때문에 보다 상세한 내용을 알고 싶으시다면 책을 직접 읽어보시길 권해드립니다. (네이버 도서 링크)
 

파이썬 코딩의 기술

아마존 파이썬 프로그래밍 분야 베스트셀러, 〈Effective Python〉 전면 개정 증보판! 파이썬의 매력과 강점을 이용해 강력하고 우수한 성능의 코드를 작성하는 90가지 방법!파이썬다운 방식으로 프

book.naver.com


Better Way 11. 시퀀스를 슬라이싱하는 방법을 익혀라

- __getitem__과 __setitem__ Method를 이용하면 어떤 파이썬 클래스라도 슬라이싱을 추가할 수 있다.

- 리스트를 슬라이싱한 결과는 완전히 새로운 리스트이다.

a = ["a", "b", "c", "d", "e"]
b = a[3:]
b[1] = 99

print(a)  # >>> ['a', 'b', 'c', 'd', 'e']
print(b)  # >>> ['d', 99]

- 언패킹 대입과 달리 슬라이스 대입에서는 슬라이스와 대입되는 리스트의 길이가 같을 필요가 없다.

a = ["a", "b", "c", "d", "e", "f", "g", "h"]

a[2:7] = [99, 22, 14]
print(a)  # >>> ['a', 'b', 99, 22, 14, 'h']

a[2:3] = [47, 11]
print(a)  # >>> ['a', 'b'. 48, 11, 22, 14, 'h']

- 슬라이싱의 유무에 따라 동작이 다르다!

a = ["a", "b", "c", "d", "e"]

b = a[:]
print(b == a and b is not a)  # >>> True

c = a
print(c is a)  # >>> True

c[3] = 99
print(a)  # >>> ['a', 'b', 99, 'd', 'e']
print(b)  # >>> ['a', 'b', 'c', 'd', 'e']
print(c)  # >>> ['a', 'b', 99, 'd', 'e']

Better Way 12. 스트라이드와 슬라이스를 한 식에 함께 사용하지 말라

- 슬라이스에 스트라이드를 함께 사용할 경우 코드의 의미를 혼동하기 쉽기 때문에 두 번의 대입(스트라이딩 + 슬라이싱)을 사용하거나 itertools 내장 모듈의 islice를 활용하는 것이 좋다.

- 스트라이드 값이 음수일 경우 시작값과 끝값의 역할을 제대로 파악하기 어렵기 때문에 가급적 양수값을 사용하라

x = ["a", "b", "c", "d", "e", "f"]

# Bad example
z = x[2:5:2]
print(z)  # >>> ['c', 'e']

# Good example
y = x[::2]
z = y[1:] 
print(z)  # >>> ['c', 'e']

Better Way 13. 슬라이싱보다는 나머지를 모두 잡아내는 언패킹을 사용하라

- Better Way 6에서 다룬 기본 언패킹은 언패킹할 시퀀스의 길이를 미리 알고 있어야 한다는 한계점을 지니고 있음. 또한, 슬라이싱을 활용하여 리스트를 하위 집합으로 분리하는 경우 1 차이 나는 인덱스로 인한 오류(off-by-one error)를 만들어내기 쉽다.

- 위 상황을 다루기 위해서 별표 식(starred expression)을 사용해 필수적으로 지정된 부분을 제외한 부분을 언패킹할 수 있다. 단, 별표 식이 포함된 언패킹 대입을 실행하려면 필수인 부분이 적어도 하나 이상 있어야하고, 한 수준의 언패킹 패턴에 별표 식을 두 개 이상 쓸 수 없다. 또한, 별표 식은 항상 리스트를 만들기 때문에 결과 데이터가 모두 메모리에 올라갈 수 있을 때만 사용해야 한다.

car_ages = [0, 9, 4, 8, 7, 20]
car_ages_descending = sorted(car_ages, reverse=True)

# Bad example
oldest = car_ages_descending[0]
second_oldest = car_ages_descending[1]
others = car_ages_descending[2:]

# Good example
oldest, second_oldest, *others = car_ages_descending
print(oldest)  # >>> 20
print(second_oldest)  # >>> 9
print(others)  # >>> [8, 7, 4, 0]

# 시퀀스의 중간을 언패킹하는 것도 가능
oldest, *others, newest = car_ages_descending

# Impossible examples
*others = car_ages_descending
first, *middle, *second_middle, last = [1, 2, 3, 4]

- CSV 파일을 한 줄씩 읽는 제네러이터가 있을 때 다음과 같이 별표 식을 이용하여 깔끔한 코드를 만들 수 있다.

def generate_csv():
    yield ("날짜", "제조사", "모델", "연식", "가격")
    
# Bad example
all_csv_rows = list(generate_csv())
header = all_csv_rows[0]
rows = all_csv_rows[1:]

# Good example
it = generate_csv()
header, *rows = it