Python Bad Practices to Avoid

1 minute read

내가 왜 이걸 이제 알았을까. 코딩 테스트하면서 불편했던 부분들을 싹싹 긁어 주는 꿀 팁.

original : Tech With Tim

실제로 이번 주말에 3번의 코딩 테스트(LINE, 카카오, NEXON) 보면서 정말 날 당황하게 했던.. python 이라서 껄끄러웠던 문제들이다..

Mutable Default Parameter

아래 코드를 살펴보자. 언뜻보면 처음 x 는 ‘numbers’에 1만 들어갔으니 [1], y는 [1, 2], z는 [1, 2, 3] 일 것 같다. 하지만, ‘append_number’ 함수에서 return 되는 numbers는 리스트의 주소값으로 참조하기 때문에, 이후의 함수들이 이전 값에 전부 영향을 준다.

따라서, 결국 x, y, z는 전부 [1, 2, 3] 이 되어 버린다..

이를 피하기 위해서는 전에 다루었던 리스트 카피 문제를 이해하고 사용해야 한다.

def append_number(num, numbers=[]):
    numbers.append(num)
    print(num)
    print(numbers)
    return numbers

x = append_number(1)
y = append_number(2)
z = append_number(3)
print(x is y and y is z)

Default Dictionary

문제를 풀다 보면, 비어 있는 딕셔너리를 정의하고 해당 key가 있으면 그 값에 count 같은거를 더하고, 없으면 해당 key로 하는 아이템을 생성해서 넣어야하는 경우가 있다.

count = defaultdict(lambda: 0)
numbers = [1, 2, 3, 1, 2, 2, 3, 4, 5]
for number in numbers:
    if count.get(number):
        count[number] += 1
    else:
        count[number] = 1

그런 경우 나는 계속 위 처럼 if dicA.get('key'): 로 검사해서 있으면 ‘+=’, 없으면 ‘=’으로 딕셔너리를 다뤘다. key가 없다면 count[number] 이런식의 인덱싱은 에러가 나기 때문이다. 하지만 그럴 필요가 없었다.

  • 방법 1 : defaultdict

defaultdict은 키가 생성 될 때 지정해준 함수로 세팅을 해준다. defaultdict의 사용 자체는 원래의 딕셔너리랑 거의 같지만, print시 리턴되는 모습이나. 약간의 사용방법이 다른게 있어서 쓰다가 불편함을 느낄수도 있다. 그러니 나는 방법 2를 사용하겠다..

from collections import defaultdict

count = defaultdict(lambda: 0)
numbers = [1, 2, 3, 1, 2, 2, 3, 4, 5]
for number in numbers:
    count[number] += 1
  • 방법 2 : setdefault()

신세계. 진짜 정말 아래와 같이 코드하는 경우가 많았는데, 한 줄로 해결 가능하다.

key가 있다면 해당 value를 반환하고, 만약 key가 없다면 입력한 인자로 default 값을 넣어주고, 그 값을 반환한다. (굉장히 멋지다…)

d = {}

if 'list' not in d:
    d['list'] = []

d['list'].append(3)

# setdefault!!
d.setdefault('list', []).append(3)

with open

그냥 open을 쓰면 꼭 ‘f.close()’로 닫아줘야하는데 with open으로 열면 그럴 필요 없다.

enumerate

이건 알고 있던 내용인데, for문에서 index와 value 값을 동시에 쓰고 싶을 때 한줄이라도 줄이기 위해서 쓴다. 또한 ‘range(len(L))’을 안써서 좋다.

L = [2, 3, 4, 1, 2, 5, 6]
for idx in range(len(L)):
    val = L[idx]
    print(val)

# enumerate
for idx, val in enumerate(L):
    print(idx, val)