Python 을 사용할 때면 대부분 list, dict, set 정도의 기본 컨테이너만 사용을 했었다. 하지만 이외에도 꽤나 유용하게 사용할 수 있는 컨테이너들이 있는데
Python에서 기본으로 제공해주는 collections
모듈을 이용하면 된다.
collections 모듈에는 다양한 컨테이너들이 있는데 그 중 유용하게 사용해볼 수 있는 컨테이너 몇 가지가 있다.
python 의 기본 dict를 사용할 때 다음과 같은 코드를 사용한 적이 있다.
...
b: dict
a: dict ( list를 value 로 갖는 dict )
for key, value in b.items():
a[key].append(value)
이렇게 될 때 만약 a 에 key 값이 존재 하지 않게 되면 분기처리를 하여서
a 에 해당 key 값으로 list값을 주거나 아래와 같이 setdefault 함수를 사용해줘야한다.
...
d = {}
for k, v in s:
d.setdefault(k, []).append(v)
하지만 분기처리를 하면 코드의 가독성이 떨어지고, setdefault는 미리 key 값을 정의할 수 있는 경우에만 사용이 가능하다.
이 때 defaultdict를 사용하면 아주 유용하다.
import collections
int_dict = collections.defaultdict(int)
list_dict = collections.defaultdict(list)
dict_dict = collections.defaultdict(dict)
tuple_dict = collections.defaultdict(tuple)
set_dict = collections.defaultdict(set)
float_dict = collections.defaultdict(float)
print(int_dict["a"], list_dict["a"], dict_dict["a"], tuple_dict["a"], set_dict["a"],float_dict["a"])
print(f"{int_dict}\n{list_dict}\n{dict_dict}\n{tuple_dict}\n{set_dict}\n{float_dict}\n")
0 [] {} () set() 0.0
defaultdict(<class 'int'>, {'a': 0})
defaultdict(<class 'list'>, {'a': []})
defaultdict(<class 'dict'>, {'a': {}})
defaultdict(<class 'tuple'>, {'a': ()})
defaultdict(<class 'set'>, {'a': set()})
defaultdict(<class 'float'>, {'a': 0.0})
위와 같이 defaultdict 를 처음 선언하게 될 때 type 값을 넣어주게 되면 참조되는 key 값이 비어있으면 기본으로 각 type별 설정되어있는 default 값을 넣어서 생성해주게 된다.
당연히 아무 값을 할당해주지 않았을 때만 default 값을 가지게 되고 특정 값을 할당하면 그대로 dict 처럼 사용할 수 있다.
이외에도 custom 한 default 값을 사용하고 싶다면 아래와 같이 함수를 만들어서 사용할 수 있다.
def custom_factory():
return ["b"]
custom_dict = collections.defaultdict(custom_factory)
print(custom_dict["a"], custom_dict["b"])
['b'] ['b']
상황에 맞게 defaultdict를 활용하면 더 간결하고 효율적으로 코드를 작성할 수 있을 것이다.
namedtuple은 튜플의 각 위치에 의미를 부여하고 더 읽기 쉽고 자체 문서화된 코드를 허용한다. 일반 튜플을 사용하는 모든 곳에서 사용할 수 있으며 위치 색인 대신 이름으로 필드에 액세스할 수 있는 기능을 추가할 수 있다.
named_tuple = collections.namedtuple("Point", ["x", "y", "z"])
p = named_tuple(1,2,3)
print(p[0], p[1], p[2])
print(p.x, p.y, p.z)
for value in p:
print(value)
temp_list = [1,2,3]
n_t = named_tuple._make(temp_list)
print(n_t)
['b'] ['b']
1 2 3
1 2 3
1
2
3
Point(x=1, y=2, z=3)
기존 tuple 을 사용하기 위해서는 위치 인덱스를 사용했어야 했다. 실제 사용할만한 예시 상황을 보면 다음과 같다.
EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')
import csv
for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "rb"))):
print(emp.name, emp.title)
import sqlite3
conn = sqlite3.connect('/companydata')
cursor = conn.cursor()
cursor.execute('SELECT name, age, title, department, paygrade FROM employees')
for emp in map(EmployeeRecord._make, cursor.fetchall()):
print(emp.name, emp.title)
다음과 같이 tuple 방식의 결과물을 받을 때 유용하게 사용할 수 있다. 이외에도 Sqlalchemy 를 통한 return 값을 받을 때도 namedtuple을 쓰면 보다 직관적이고 효율적인 코드 작성이 가능하다.