새소식

반응형
Python/Clean Code Series(클린코드)

Python 딕셔너리에 대해서 알면 좋은 8가지 (FOR CLEAN CODE)

  • -
반응형

파이썬에서 딕셔너리를 다루는 더 나은 방법에 대해 이야기해보려고 합니다. 

 

1) dict(key=value) 사용하기

우리가 흔히 알고 있는 딕셔너리 생성 방법은 중괄호 {}를 사용하는 것입니다. 하지만 dict(key=value)로 생성하는 방법은 더 깔끔하고 직관적입니다.
 
# 일반적으로 dictionary를 생성할때
d = {'apple':4,'orange':5,'pear':6,'pineapple':7}
# 더 나은 방법으로 똑같이 dictionary를 생성하는법
d = dict(apple=4, orange=5, pear=6, pineapple=7)

 

dict(key=value) 장점:

  • {}를 사용할 때, 문자열 키에 따옴표를 입력할 필요가 없습니다.
  • 예를 들어, 'apple', 'orange' 등과 같이 말이죠.
  • 더 많은 키를 다뤄야 할수록 따옴표를 입력해야 하는 것이 귀찮아집니다.
  • dict()를 사용할 때는 따옴표를 무시할 수 있습니다.

물론, dict() 방식은 문자열이 아닌 키에는 작동하지 않기 때문에, 두 방법 모두 각자의 용도가 있습니다.

 

 

2) ** 사용해서 딕셔너리 합치기

# 여기에 2 dicts가 있습니다.
a = {1:1, 2:2}
b = {3:3, 4:4}
# ** 를 사용함으로써 쉽게 a, b dicts를 합칠 수 있습니다.
x = {**a, **b}
print(x) # {1:1, 2:2, 3:3, 4:4}
  • 딕셔너리 앞의 **는 키-값 쌍을 부모 딕셔너리로 언패킹합니다.
# 일반적인 key-value도 같이 추가할 수 있습니다.
a = {1:1, 2:2}
b = {3:3, 4:4}
x = {**a, **b, 5:5}
print(x) # {1:1, 2:2, 3:3, 4:4, 5:5}

 

반응형
 

3) **를 사용하여 딕셔너리를 키워드 인자로 전달하기

def test(a, b, c): 
    print(a, b, c)
test(a=1, c=2, b=3) # 1 3 2
 

우리는 a, b, c를 키로 가지는 딕셔너리를 이 함수에 동적으로 전달할 수 있습니다.

mydict = dict(a=1, b=2, c=3)
print(mydict) # {'a':1, 'b':2, 'c':3}

# test(a=1, b=2, c=3) 로 사용하는것과 동일합니다.
test(**mydict) # 1 2 3

^ 딕셔너리 앞의 **는 다시 한 번 그 키-값 쌍들을 test 함수로 언패킹합니다.

참고: 이는 함수에 키워드 인자를 동적으로 전달하고 싶을 때 유용합니다.

 

 

4) 딕셔너리 컴프리헨션

{1:1, 2:4, 3:9, 4:16}와 같은 딕셔너리를 만들고 싶다고 가정해 봅시다.

# 일반적으로 dict를 만들때
d = {}
for iin range(1,5): 
    d[i] = i**2
print(d) # {1: 1, 2: 4, 3: 9, 4: 16}

# dict comprehension를 써서 만들때
d = {i:i**2 for i in range(1, 5)}
print(d) # {1:1, 2:4, 3:9, 4:16}

 

두 방법 모두 맞는 방법입니다. 하지만 딕셔너리 컴프리헨션이 훨씬 더 우아하고, 파이썬스러우며, 읽기 쉽다는 점을 주목하세요.

 
# 2중 for문
d = {}
for i in range(2): 
    for j in range(2,4): 
        d[(i, j)] =0
        
print(d)  # {(0, 2): 0, (0, 3): 0, (1, 2): 0, (1, 3): 0}


# dict comprehension에서 2중 for문 사용법
d = {(i, j):0 for i in range(2)for j in range(2, 4)}
print(d)  # {(0, 2): 0, (0, 3): 0, (1, 2): 0, (1, 3): 0}
 
 
 

5) dict.get(key, default_value)

 

존재하지 않는 키에 접근할 때, 우리는 KeyError를 얻습니다.

d = {1:1, 2:2, 3:3}
print(d[1]) # 1
print(d[4]) # KeyError
 
 

.get() 메서드를 사용하여 KeyError를 피할 수 있습니다. 이 메서드는 키가 존재하지 않을 경우 None을 반환합니다.

 
# .get() 사용할때
d = {1:1, 2:2, 3:3}
print(d.get(1)) # 1
print(d.get(4)) # None
 
KeyError를 발생시키는 대신 None을 얻는다는 점을 주목하세요.
 
# .get() 커스텀 기본값
d = {1:1, 2:2, 3:3}
print(d.get(1, 100)) # 1
print(d.get(4, 100)) # 100
print(d.get(9, 100)) # 100
 
 커스텀 기본값도 정의할 수 있습니다.
 
 
 

 

6) 튜플 리스트를 사용하여 dict() 생성하기

ls = [('apple', 4), ('orange', 5), ('pear', 6)]
# 이것을 dict()에 전달하여 딕셔너리를 생성할 수 있습니다
d = dict(ls)
print(d) # {'apple': 4, 'orange': 5, 'pear': 6}
 
딕셔너리 컴프리헨션을 작성하지 않고도 튜플에서 빠르게 딕셔너리를 생성할 수 있습니다.
 
 

7) .items() and .values()

d = dict(apple=4, orange=5, pear=6)
print(d) # {'apple':4, 'orange':5, 'pear':6}
 
 

딕셔너리 자체를 순회할 때, 우리는 단순히 모든 딕셔너리 키를 생성합니다:

for k in d: 
    print(k)
# apple
# orange
# pear
 
 

**.values()**를 사용하면 모든 딕셔너리 값을 생성합니다:

 
for v in d.values(): 
    print(v)
# 4
# 5
# 6
 
 

**.items()**를 사용하면, 키와 값을 튜플로 모두 생성합니다:

for k, v in d.items(): 
    print(k, v)
# apple 4
# orange 5
# pear 6
 
개인적으로 **.items()**가 딕셔너리의 모든 키-값 쌍을 빠르게 순회하는 데 가장 유용한 메서드라고 생각합니다.
 
 
 

8) 딕셔너리 키가 될 수 있는 것과 될 수 없는 것

 
참고:
  • 불변 데이터 타입은 딕셔너리 키가 될 수 있습니다. 예: int str tuple bool
  • 가변 데이터 타입은 될 수 없습니다. 예: list dict
# 불변 데이터 타입을 딕셔너리 키로 사용하려는 시도
mylist = [1,2,3]

d = {mylist:5}
# TypeError: unhashable type: 'list'
 

어떤 객체가 딕셔너리 키로 사용될 수 있는지 확인하려면 내장 hash() 함수를 사용할 수 있습니다.

# hash() 메서드를 불변 타입에 사용할때
a:int = 4
b:str = 'hi'
print(hash(a)) # 4
print(hash(b)) # -4763374371541057969

# hash() 메서드를 가변 타입에 사용할때
l:list = [1,2,3]
d:dict = {1:1}
print(hash(l)) # TypeError: unhashable type: 'list'
print(hash(d)) # TypeError: unhashable type: 'dict'
 
따라서 딕셔너리 키가 될 수 있는 커스텀 객체를 만들고 싶다면, __hash__ 메서드를 사용하여 커스텀 객체를 어떻게 해시할지 정의할 수 있습니다.
 
class Dog: 
    def __init__(self, name, age): 
        self.name = name 
        self.age = age 

    def __hash__(self): 
        return hash(str(self.name) + str(self.age))

dog1 = Dog('rocky', 4)
dog2 = Dog('fifi', 5)

d = {dog1:1, dog2:2}
print(d)
# {<__main__.Dog object at 0x10476a9f0>: 1, <__main__.Dog object at 0x10476aa20>: 2}
반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.