Search
๐Ÿ“˜

Effective Python 2/E - Brett Slatkin

1. Pythonic

๊ฐ€. Helper Function > Complex Expressions

๋ณต์žกํ•œ ์‹ ๋ณด๋‹ค๋Š” ๋„์šฐ๋ฏธ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ€๋…์„ฑ์„ ๋†’์ผ ๊ฒƒ
Donโ€™t Do This
request = {"name": ["MJ"], "phone": ["010-111"]} name = request.get("name", [""])[0] or 0
Python
๋ณต์‚ฌ
Do this
def get_first_value(values, key, default=0): found = values.get(key, ['']) if found[0]: return int(found[0]) return default request = {"name": ["MJ"], "phone": ["010-111"]} name = get_first_value(request, "name")
Python
๋ณต์‚ฌ
Why
โ€ข
๋ช…ํ™•ํ•จ์— ๋”ฐ๋ฅธ ๊ฐ€๋…์„ฑ ์šฐ์œ„๊ฐ€ ๊ฐ„๊ฒฐํ•จ์— ๋”ฐ๋ฅธ ๋ฏธ์„ธํ•œ ์„ฑ๋Šฅ ์šฐ์œ„ ๋ณด๋‹ค ๋‚ซ๋‹ค
โ†’ ๊ฐ€๋…์„ฑ ์šฐ์œ„๋Š” ์œ ์ง€๋ณด์ˆ˜์˜ ํŽธ๋ฆฌํ•จ์œผ๋กœ ์ด์–ด์ง€๊ณ  ์ด๊ฒƒ์€ ํœด๋จผ์—๋Ÿฌ ๊ฐ์†Œ์™€ ์œ ์ง€๋ณด์ˆ˜ ์šฉ์ด๋กœ ์ด์–ด์ง
โ†’ ๋ฏธ์„ธํ•œ ์„ฑ๋Šฅ ์šฐ์œ„๋Š” ์‚ฌ๋žŒ์ด ์ฒด๊ฐํ•  ์ˆ˜ ์—†์Œ

๋‚˜. unpacking > indexing

๋ฐ˜๋ณต๋ฌธ์—์„œ index ๋Œ€์‹  unpacking์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ€๋…์„ฑ์„ ๋†’์ผ ๊ฒƒ
Donโ€™t Do This
name_age_tuples = [('MJ', 30), ('DB', 29)] for i in range(len(name_age_tuples)): name_age_tuple = name_age_tuples[i] name = name_age_tuple[0] age = name_age_tuple[1] print(f'{i + 1}: {name}, {age}')
Python
๋ณต์‚ฌ
Do this
โ€ข
ํŠนํžˆ ๋ฐ˜๋ณต๋ฌธ์—์„œ unpacking ์‚ฌ์šฉ ์‹œ ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ์ด ํฌ๊ฒŒ ํ–ฅ์ƒ๋œ๋‹ค
name_age_tuples = [('MJ', 30), ('DB', 29)] for i, (name, age) in enumerate(name_age_tuples, 1): print(f'{i}: {name}, {age}')
Python
๋ณต์‚ฌ
Why
โ€ข
์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด โ€˜์‹œ๊ฐ์  ์žก์Œ'์ด ์ค„๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ์˜ ์˜๋„๊ฐ€ ๋ช…ํ™•ํ•˜๊ฒŒ ๋“œ๋Ÿฌ๋‚œ๋‹ค

๋‹ค. zip for iterators in parallel

๊ธธ์ด๊ฐ€ ๊ฐ™์€ ๋ณต์ˆ˜๊ฐœ์˜ ์ดํ„ฐ๋ ˆ์ดํ„ฐ ์‚ฌ์šฉ ์‹œ zip์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ€๋…์„ฑ์„ ๋†’์ผ ๊ฒƒ
Donโ€™t Do This
longest_name = None max_count = 0 for i in rage(len(names)): count = counts[i] if count > max_count: longest_name = names[i] max_count = count
Python
๋ณต์‚ฌ
Do this
โ€ข
๊ธธ์ด๊ฐ€ ๋‹ค๋ฅผ ๊ฒฝ์šฐ, ์งง์€ ๊ธธ์ด์˜ ์ดํ„ฐ๋ ˆ์ดํ„ฐ์— ๋งž์ถฐ ๋ฐ˜๋ณต๋จ
โ†’ ๊ธด ๊ธธ์ด์˜ ์ดํ„ฐ๋ ˆ์ดํ„ฐ์— ๋งž์ถฐ ๋ฐ˜๋ณตํ•  ๋•Œ๋Š” zip ๋Œ€์‹  itertools.zip_longest ํ•จ์ˆ˜ ์‚ฌ์šฉ
โ†’ ์ด ๋•Œ, ์งง์€ ๊ธธ์ด์˜ ์ดํ„ฐ๋ ˆ์ดํ„ฐ์˜ outbound ์š”์†Œ๋Š” None ์ฒ˜๋ฆฌ๋จ
for count, name zip(counts, names): if count > max_count: longest_name = name max_count = count
Python
๋ณต์‚ฌ
Why
โ€ข
์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด โ€˜์‹œ๊ฐ์  ์žก์Œ'์ด ์ค„๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ์˜ ์˜๋„๊ฐ€ ๋ช…ํ™•ํ•˜๊ฒŒ ๋“œ๋Ÿฌ๋‚œ๋‹ค

๋ผ. assignment expression

์™ˆ๋Ÿฌ์Šค ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ๊ณผ ๋ณ€์ˆ˜ ํ• ๋‹น ์‹์˜ ๋ฐ˜๋ณต์„ ์ค„์ผ ๊ฒƒ
Donโ€™t Do This
Python
๋ณต์‚ฌ
Do this
Python
๋ณต์‚ฌ
Why
โ€ข

2. List & Dict

๊ฐ€. unpacking > slicing

source interator ๋ฐ˜๋ณต ์‚ฌ์šฉ ์‹œ unpakcing ํ™œ์šฉํ•˜์—ฌ ์ฝ”๋“œ๋ฐ˜๋ณต๊ณผ ํœด๋จผ์—๋Ÿฌ ๊ฐ€๋Šฅ์„ฑ์„ ์ค„์ผ ๊ฒƒ
Donโ€™t Do This
all_csv_rows = list(generate_csv(source)) header = all_csv_rows[0] rows = all_csv_rows[1:] print(f'header: {header}, len of rows: {len(rows)}')
Python
๋ณต์‚ฌ
Do this
โ€ข
๋‹จ, unpacking์— ๋”ฐ๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ถฉ๋ถ„ํžˆ ๊ฐ๋‹นํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ๋งŒ ์‚ฌ์šฉํ•œ๋‹ค
โ†’ ๋ฉ”๋ชจ๋ฆฌ ๋ถ€์กฑ์— ๋”ฐ๋ฅธ ํ”„๋กœ๊ทธ๋žจ ๊ฐ•์ œ ์ข…๋ฃŒ๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ์Œ
โ€ข
๋งŒ์•ฝ rows์— ๋งŽ์€ ๋ฐ์ดํ„ฐ๊ฐ€ ๋“ค์–ด์žˆ์„ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค๋ฉด ์˜ˆ์™ธ๋‚˜ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ํ†ตํ•ด ๊ฐ€๋Šฅ์„ฑ์„ ์‚ฌ์ „ ์ฐจ๋‹จํ•ด์•ผ ํ•œ๋‹ค
โ†’ ์˜ˆ๋ฅผ ๋“ค์–ด csvํŒŒ์ผ ์—ฌ๋ถ€ ๋ฐ ํŒŒ์ผ ์ด๋ฆ„ ๋“ฑ์„ ์ฒดํฌํ•˜์—ฌ ์˜๋„ํ•œ csv ํŒŒ์ผ๋งŒ ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ์œ ํšจ์„ฑ ๋กœ์ง์„ ์ถ”๊ฐ€ํ•œ๋‹ค
it = generate_csv(source) header, *rows = it print(f'header: {header}, len of rows: {len(rows)}')
Python
๋ณต์‚ฌ
Why
โ€ข
unpacking ์‚ฌ์šฉ ์‹œ index์— ๊ธฐ๋ฐ˜ํ•œ slicing ์‚ฌ์šฉ ๋ณด๋‹ค ํœด๋จผ์—๋Ÿฌ๋ฅผ ์ค„์ด๋Š”๋ฐ ์šฉ์ดํ•˜๋‹ค
โ€ข
unpacking ์‚ฌ์šฉ์— ๋”ฐ๋ผ ๋ฐ˜๋ณต์„ ์ค„์ด๊ณ  ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ์œผ๋กœ์จ ์ฝ”๋“œ์˜ ์˜๋„๊ฐ€ ๋ช…ํ™•ํ•˜๊ฒŒ ๋“œ๋Ÿฌ๋‚œ๋‹ค

๋‚˜. get > in, KeyError

Donโ€™t Do This
Python
๋ณต์‚ฌ
Do this
Python
๋ณต์‚ฌ
Why
โ€ข

๋‹ค. defaultdict > setdefault

Donโ€™t Do This
Python
๋ณต์‚ฌ
Do this
Python
๋ณต์‚ฌ
Why
โ€ข

๋ผ. __missing__ for setting default

Donโ€™t Do This
Python
๋ณต์‚ฌ
Do this
Python
๋ณต์‚ฌ
Why
โ€ข

3. Function

๊ฐ€. Exception > None

์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ None์„ ๋ฐ˜ํ™˜ํ•˜์ง€ ๋ง๊ณ  Exception์„ ๋ฐœ์ƒ์‹œ์ผœ ํœด๋จผ์—๋Ÿฌ๋ฅผ ์ค„์ผ ๊ฒƒ
Donโ€™t Do This
โ€ข
unpacking์— ๋”ฐ๋ฅธ None ๋ฐ˜ํ™˜๋„ ์ž์ œ
def divide(a, b): try: return a / b except ZeroDivisionError: return None
Python
๋ณต์‚ฌ
def divide(a, b): try: return True, a / b except ZeroDivisionError: return False, None
Python
๋ณต์‚ฌ
Do this
โ€ข
Exception ์ฒ˜๋ฆฌ ๋ถ€๋ถ„์ด ์žˆ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด docstring ์ž‘์„ฑํ•˜์—ฌ ๊ด€๋ จ ์„ค๋ช…์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅ
โ€ข
๋ช…์‹œ์„ฑ ํ–ฅ์ƒ์„ ์œ„ํ•ด ํƒ€์ž… ์ง€์ • ๊ถŒ์žฅ
def divide(a: float, b: float) -> float: """a๋ฅผ b๋กœ ๋‚˜๋ˆ” Raises: ValueError: b๊ฐ€ 0์ผ ๋•Œ ๋‚˜๋ˆ—์…ˆ์„ ํ•  ์ˆ˜ ์—†๋‹ค """ try: return a / b except ZeroDivisionError: return ValueError('์ž˜๋ชป๋œ ์ž…๋ ฅ') try: result = divide(x, y) except ValueError: print('์ž˜๋ชป๋œ ์ž…๋ ฅ') else: print(f'๊ฒฐ๊ณผ: {result}')
Python
๋ณต์‚ฌ
Why
โ€ข
ํ•จ์ˆ˜์—์„œ None ๋ฐ˜ํ™˜ ์‹œ โ€˜0 ๋˜๋Š” Falseโ€™ ๋ฐ˜ํ™˜์— ๋”ฐ๋ฅธ ๊ฐ’ ์ฒ˜๋ฆฌ์™€ ํ˜ผ๋™๋  ์ˆ˜ ์žˆ๋‹ค
โ†’ ์กฐ๊ฑด๋ฌธ์—์„œ None๊ณผ 0์™€ False๋Š” ๋ชจ๋‘ False๋กœ ํ‰๊ฐ€๋œ๋‹ค
โ€ข
โ€˜None ๋ฐ˜ํ™˜โ€™์€ โ€˜์˜ˆ์™ธ ๋ฐœ์ƒโ€™๊ณผ ๋…ผ๋ฆฌ์  ์—ฐ๊ด€์„ฑ์ด ๋–จ์–ด์ง„๋‹ค
โ†’ None์€ โ€˜๊ฐ’์ด ์ง€์ •๋˜์ง€ ์•Š์Œ'์„ ๋œปํ•˜๋ฏ€๋กœ ๋…ผ๋ฆฌ์ ์œผ๋กœ โ€˜์˜ˆ์™ธ ๋ฐœ์ƒ'๊ณผ ์ง์ ‘์ ์ธ ์—ฐ๊ด€์ด ์—†๋‹ค

Reference

โ€ข
Brett Slatkin, Effective Python 2nd Edition, https://effectivepython.com/
โ€ข
(๋ฒˆ์—ญ๋ช…) ํŒŒ์ด์ฌ ์ฝ”๋”ฉ์˜ ๊ธฐ์ˆ , https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=254321728