[Effective Python] 2. List and Dictionaries

Stop._.bmin·2023년 1월 28일
0

Effective-python

목록 보기
2/5
post-custom-banner

Item 11: Know HOw to Slice Sequences

시퀀스를 슬라이스 하는 방법을 알자

  • 이 파트는 파이썬을 한다면 익히 아는 부분이라 판단되어 생략했다.
    추가적으로 처음본 내용이 있어 한 가지를 쓰자면,
b = a
print('Before a', a)  # ['a', 'b', 99, 22, 14, 'h']
print('Before b', b)  # ['a', 'b', 99, 22, 14, 'h']
a[:] = [101, 102, 103]
assert a is b
print('After a', a)  # [101, 102, 103]
print('After b', b)  # [101, 102, 103]

위의 코드는 a가 가리키는 리스트 객체가 바뀌어서 a와 b가 달라졌음을 보여준다.


Item 12: Avoid Striding and Slicing in a Single Expression

  • item 11은 기초고, 파이썬은 special syntax for the stride of a slice가 있다. 매 시퀀스마다 slicing하는 것이다
x = ['red','orange','yellow','green','blue','purple]
odds = x[::2]
evens = x[1::2]
print(odds)
print(evens)

>>>
['red','yellow', 'blue']
['orange', 'green', 'purple']
  • 또한 교재에서 설명한 바 중 몇가지를 정리해보면,
    • ::2 : 처음부터 시작해서 매 두 번째 아이템을 선택한다
    • ::-2 : 끝부터 시작해서 반대 방향으로 매 두번째 아이템을 선택한다

stride 문법

위와 같은 표기를 stride 문법이라고 하는데, 3가지 인수가 들어가기도 한다
가급적이면 start, end, stride를 세개 다같이 사용하지 않는 것이 좋다.


Item 13: Prefer Catch-All Unpacking Over Slicing

  • item 6 에서 소개한 unpacking하는 방법 중 다른 것으로 runtime를 발생시키는 코드가 있다
car_ages = [0, 9, 4, 8, 7, 20, 19, 1, 6, 15]
car_ages_descending = sorted(car_ages, reverse = True)
oldest, second_oldest = car_ages_descending

>>>
Traceback ...
ValueError: too many values to unpack (expected 2)

이런 경우에는 가장 큰 값과 그다음으로 큰 값을 가져오는데 필자가 소개한 몇가지 방법이 있다.

  • 아래코드도 잘 작동하지만, 시각적으로 지저분하고 실무에서 에러를 가져오기도 한다. 예를 들어 범위를 경계들을 변경하는 경우 한가지를 update하는 것을 잊으면 바로 에러가 뜬다.
oldest = car_ages_descending[0]
second_oldest = car_ages_descending[1]
others = car_ages_descending[2:]
print(oldest, second_oldest, others)
>>>
20 19 [15, 9, 8, 7, 6, 4, 1, 0]
  • 따라서 위를 개선한 코드는 아래와 같다.
    • 아래의 코드는 더 간결하고, 읽기 쉽고, error-prone하지 않다.
oldest, second_oldest, *others = car_ages_descending
print(oldest, second_oldest, others)
>>>
20 19 [15, 9, 8, 7, 6, 4, 1, 0]

Item 14: Sort by Complex Criteria Using the key Parameter

  • 우리는 주로 sort() 매서드를 많이 활용한다.
  • built-in types (strings, floats, etc)에서는 모두 지원한다
  • 그러나 object는 어떻게 할까??
    • item 75를 확인하면 알 수 있다
class Tool:
    def __init__(self, name, weight):
        self.name = name
        self.weight = weight
    def __repr__(self):
        return f'Tool({self.name!r}, {self.weight})'
        
    tools = [
        Tool('level', 3.5),
        Tool('hammer', 1.25),
        Tool('screwdriver', 0.5),
        Tool('chisel', 0.25),
  ]
  • 그런데 어떤 타입의 sorting object는 작동하지 않는다. special한 methods(class로 정의되지 않은)을 비교하도록 call받기 때문이다
    • 이럴 때는 우리가 필요한 특별한 매서드를 정의할 수 있다. (item 73에서 알 수 있다.)
  • 그리고 아래와 같이 lambda키워드로도 list를 정렬할 수 있다! 조프입 때 이거 쓰면 쉽게 풀리는 문제가 있었다..
print('Unsorted:', repr(tools))
tools.sort(key=lambda x: x.name)
print('\nSorted:  ', tools)
>>>
Unsorted: [Tool('level',       3.5),
           Tool('hammer',      1.25),
           Tool('screwdriver', 0.5),
           Tool('chisel',      0.25)]

Sorted:   [Tool('chisel',0.25),
          Tool('hammer',1.25),
          Tool('level',3.5),
          Tool('screwdriver', 0.5)]

Item 15: Be Cautious When Relying on dict Insertion Ordering

  • 파이썬에서 주로 dict에 활용하는 것들
    • .keys()
    • .values()
    • .items()
    • .popitem()
      그런데 popitem()을 제외하고 list()로 묶어 print한다면 알파벳 순으로 정렬되어있음을 확인할 수 있을 것이다.

Item 16: Prefer get Over in and KeyError to Handle Missing Dictionary Keys

  • 만약 존재하지 않는 key를 제거하려고 시도할 때에 관한 이야기이다.
    key가 존재하는지 확인할 때 아래의 함수를 사용했다
try:
	count = counters[key]
except KeyError:
	count = 0

그러나 필자는 더 짧은 코드를 소개했다

count = counters.get(key, 0)
counters[key] = count + 1

그러나 위의 코드는 읽기 좋지 않다. 따라서 최종적으로 추천한 형태는

try:
	counter[key]  += 1
except KeyError:
	counters[key] = 1

이외에도 필자가 detect and handle missing keys in dictionaries를 할 때 추천한 방법에는 4가지가 있다.
counter 을 포함한 가장 기본적인 방법이 딕셔너리를 다룰 때 좋다.
만약 setdefault 방법의 dict이 가장 좋아보일 때는 defaultdict를 대신에 고려해야한다.


Item 17: Prefer defaultdict Over setdefault to Handle Missing Items in Internal State

  • setdefault method to add new cities to the sets
visits.setdefault('France', set()).add('Arles') 	# short

if (japan := visits.get('Japan')) is Non: 			# Long
	visits['Japan'] = japan = set()
print(visits)
>>>
{'Mexico': {'Tulum', 'Puerto Vaallarta'},
'Japan': {'Kyoto', 'Hakone'},
'France': {'Arles'}}
profile
원하는 만큼만
post-custom-banner

0개의 댓글