λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
🐍 Python

μ΄νŽ™ν‹°λΈŒ 파이썬 3μž₯ - ν•¨μˆ˜

by dev.py 2025. 3. 17.

Better way 19 ν•¨μˆ˜κ°€ μ—¬λŸ¬ 값을 λ°˜ν™˜ν•˜λŠ” 경우 μ ˆλŒ€λ‘œ λ„€ κ°’ 이상을 μ–ΈνŒ¨ν‚Ήν•˜μ§€ 말라

ν•¨μˆ˜κ°€ μ—¬λŸ¬ 값을 λ°˜ν™˜ν•˜λŠ” 경우, μ–ΈνŒ¨ν‚Ή κ³Όμ •μ—μ„œ 였λ₯˜κ°€ μΌμ–΄λ‚˜κΈ° 쉽닀.

# μ•ˆμ’‹μ€ μ˜ˆμ‹œ - μ–ΈνŒ¨ν‚Ήν•˜λŠ” μΈμžμ—μ„œ μˆœμ„œκ°€ λ°”λ€Œμ—ˆμ„ λ•Œ, 였λ₯˜λ₯Ό μΈμ§€ν•˜κΈ° μ–΄λ ΅λ‹€
def get_stats(numbers):
	minimum = min(numbers)
    maximum = max(numbers)
    count = len(numbers)
    average = sum(numbers) / count
    return minimum, maximum, count, average

# μ •μƒμ μœΌλ‘œ 호좜
minimum, maximum, count, average = get_stats([1,2,3,4]) 

# average, count μˆœμ„œλ₯Ό 잘λͺ» 호좜 - 였λ₯˜λ₯Ό μΈμ§€ν•˜κΈ° 어렀움
minimum, maximum, average, count = get_stats([1,2,3,4])

 

ν•΄κ²° 방법 1. namedtuple μ‚¬μš©

# 쒋은 μ˜ˆμ‹œ 1 - namedtuple
from collections import namedtuple
# namedtuple μ •μ˜
Stats = namedtuple('Stats', ['minimum', 'maximum', 'count', 'average'])

def get_stats(numbers):
    minimum = min(numbers)
    maximum = max(numbers)
    count = len(numbers)
    average = sum(numbers) / count
    return Stats(minimum, maximum, count, average)
    
# 호좜 μ‹œ, μ΄λ¦„μœΌλ‘œ 값을 μ ‘κ·Όν•˜μ—¬ μˆœμ„œλ₯Ό μ‹ κ²½ μ“Έ ν•„μš” μ—†μŒ
stats = get_stats([1, 2, 3, 4])
print(stats.minimum)  # 1
print(stats.maximum)  # 4
print(stats.count)    # 4
print(stats.average)  # 2.5

 

ν•΄κ²° 방법 2. dataclass μ‚¬μš©

# 쒋은 μ˜ˆμ‹œ 2 - dataclass μ‚¬μš©
from dataclasses import dataclass

# dataclass μ •μ˜
@dataclass
class Stats:
    minimum: int
    maximum: int
    count: int
    average: float

def get_stats(numbers):
    minimum = min(numbers)
    maximum = max(numbers)
    count = len(numbers)
    average = sum(numbers) / count
    return Stats(minimum, maximum, count, average)

# 호좜 μ‹œ, 객체의 μ†μ„±μœΌλ‘œ μ ‘κ·Ό
stats = get_stats([1, 2, 3, 4])
print(stats.minimum)  # 1
print(stats.maximum)  # 4
print(stats.count)    # 4
print(stats.average)  # 2.5

 

namedtuple과 dataclass의 차이

νŠΉμ„± namedtuple dataclass
λ³€κ²½ κ°€λŠ₯ μ—¬λΆ€ λΆˆλ³€(immutable) 객체 기본적으둜 κ°€λ³€(mutable) 객체,
frozen=True둜 λΆˆλ³€ μ„€μ • κ°€λŠ₯
λ©”μ„œλ“œ μΆ”κ°€ λ©”μ„œλ“œ μΆ”κ°€ λΆˆκ°€ λ©”μ„œλ“œ μΆ”κ°€ κ°€λŠ₯
상속 지원 상속 λΆˆκ°€ 상속 κ°€λŠ₯
κΈ°λ³Έ μƒμ„±μž μžλ™ 생성됨 μžλ™ 생성됨
비ꡐ μ—°μ‚°μž μžλ™ 생성됨 (__eq__ λ“±) μžλ™ 생성됨 (__eq__ λ“±)
__repr__ μžλ™ 생성됨 μžλ™ 생성됨
기타 νŠΉμ§• νŠœν”Œκ³Ό ν˜Έν™˜λ˜λ©° λ©”λͺ¨λ¦¬ 효율적 객체 지ν–₯적이며 ν™•μž₯μ„± 있음

Better way 20 None을 λ°˜ν™˜ν•˜κΈ°λ³΄λ‹€λŠ” μ˜ˆμ™Έλ₯Ό λ°œμƒμ‹œμΌœλΌ

# μ•ˆ 쒋은 μ˜ˆμ‹œ - 였λ₯˜ μƒν™©μ—μ„œ Noneλ₯Ό λ°˜ν™˜
def safe_divide(a, b):
    if b == 0:
        return None  # 0으둜 λ‚˜λˆ„λŠ” 경우 None λ°˜ν™˜
    return a / b

result = safe_divide(10, 0)
if result is None:
    print("Error: Division by zero")
else:
    print("Result:", result)
  • μ˜ˆμ™Έ μƒν™©μ—μ„œ Noneλ₯Ό λ°˜ν™˜ν•˜λ©΄ ν˜ΈμΆœν•˜λŠ” μͺ½μ—μ„œ None을 κ²€μ¦ν•˜λŠ” 것이 λΆ€μžμ—°μŠ€λŸ½λ‹€.
  • λ˜ν•œ μ—¬λŸ¬ μ˜ˆμ™Έλ₯Ό None ν•˜λ‚˜λ‘œ ν‘œν˜„ν•˜μ—¬ λ°˜ν™˜ν•˜λ©΄ μ˜ˆμ™Έλ₯Ό νŠΉμ •ν•˜κΈ° μ–΄λ ΅λ‹€.
# 쒋은 μ˜ˆμ‹œ - 였λ₯˜ μƒν™©μ—μ„œ μ˜ˆμ™Έ λ°œμƒ
def safe_divide(a, b):
    if b == 0:
        raise ZeroDivisionError("Cannot divide by zero")
    return a / b

try:
    result = safe_divide(10, 0)
    print("Result:", result)
except ZeroDivisionError as e:
    print("Error:", e)

Better way 21 λ³€μˆ˜ μ˜μ—­κ³Ό ν΄λ‘œμ €μ˜ μƒν˜Έμž‘μš© 방식을 μ΄ν•΄ν•˜λΌ

파이썬 인터프리터가 λ³€μˆ˜λ₯Ό μ°ΎλŠ” μˆœμ„œ

  • ν˜„μž¬ ν•¨μˆ˜μ˜ μ˜μ—­
  • ν˜„μž¬ ν•¨μˆ˜λ₯Ό λ‘˜λŸ¬μ‹Ό μ˜μ—­
  • ν˜„μž¬ μ½”λ“œκ°€ λ“€μ–΄ μžˆλŠ” λͺ¨λ“ˆμ˜ μ˜μ—­ - μ „μ—­ μ˜μ—­(global)
  • λ‚΄μž₯ μ˜μ—­ (built-in-scope) - len, str λ“±μ˜ ν•¨μˆ˜κ°€ λ“€μ–΄ μžˆλŠ” μ˜μ—­
def sort_priority(values, group):
    def helper(x):
        if x in group:
            return (0,x)
        return (1,x)
    values.sort(key=helper)

helper ν•¨μˆ˜μ—μ„œ group이 μ„ μ–Έλ˜μ–΄ μžˆμ§€ μ•Šμ§€λ§Œ μ—λŸ¬κ°€ λ°œμƒν•˜μ§€ μ•ŠλŠ”λ‹€

μ™œλƒν•˜λ©΄ "ν˜„μž¬ ν•¨μˆ˜λ₯Ό λ‘˜λŸ¬μ‹Ό μ˜μ—­" μ—μ„œ group λ³€μˆ˜λ₯Ό 찾을 수 있기 λ•Œλ¬Έ -> 파이썬이 ν΄λ‘œμ €λ₯Ό μ§€μ›ν•˜κΈ° λ•Œλ¬Έ

 

def sort_priority2(numbers, group):
    found = False
    def helper(x):
        if x in group:
            found = True
            return (0, x)
        return (1,x)
    numbers.sort(key=helper)
    return found

μœ„μ˜ ν•¨μˆ˜λŠ” μ •μƒμ μœΌλ‘œ λ™μž‘ν•˜μ§€ μ•ŠλŠ”λ‹€. (개발자 μ˜λ„λŒ€λ‘œ λ™μž‘ x)

μ˜μ—­ 지정 버그(scoping bug)κ°€ λ°œμƒν•˜κΈ° λ•Œλ¬Έμ΄λ‹€. 

 

helper ν•¨μˆ˜μ˜ "found = True" ꡬ문은 sort_priority2μ—μ„œ μ„ μ–Έλ˜μ–΄ μžˆλŠ” found λ³€μˆ˜μ— True을 ν• λ‹Ήν•˜λŠ” 것이 μ•„λ‹Œ helper ν•¨μˆ˜ λ‚΄μ—μ„œ found λΌλŠ” λ³€μˆ˜λ₯Ό μƒˆλ‘œ λ§Œλ“€κ³  Trueλ₯Ό ν• λ‹Ήν•˜κΈ° λ•Œλ¬Έμ΄λ‹€.

 

def sort_priority3(numbers, group):
    found = False
    def helper(x):
        if x in group:
            nonlocal found = True
            return (0, x)
        return (1,x)
    numbers.sort(key=helper)
    return found

nonlocal ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ sort_priority3 의 found에 값이 μ •μƒμ μœΌλ‘œ ν• λ‹Ήν•  순 μžˆμ§€λ§Œ, nonlocal ν‚€μ›Œλ“œλŠ” μ‚¬μš©ν•˜μ§€ 말자 ν•¨μˆ˜μ˜ λ™μž‘μ„ μ΄ν•΄ν•˜λŠ” 데, μ–΄λ €μ›Œμ§„λ‹€.

 

ꡬ뢄 global nonlocal
μ‚¬μš© λͺ©μ  μ „μ—­ λ³€μˆ˜λ₯Ό ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œ μˆ˜μ •ν•  λ•Œ μ‚¬μš© 쀑첩 ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œ λ°”κΉ₯ ν•¨μˆ˜μ˜ λ³€μˆ˜λ₯Ό μˆ˜μ •ν•  λ•Œ μ‚¬μš©
적용 λŒ€μƒ μ „μ—­ λ³€μˆ˜ ν˜„μž¬ ν•¨μˆ˜μ˜ λ°”κΉ₯ ν•¨μˆ˜(non-global)의 지역 λ³€μˆ˜
μ„ μ–Έ μœ„μΉ˜ ν•¨μˆ˜ λ‚΄λΆ€ 쀑첩 ν•¨μˆ˜ λ‚΄λΆ€
λ³€μˆ˜ 생성 μ—¬λΆ€ κΈ°μ‘΄ μ „μ—­ λ³€μˆ˜λ₯Ό μ‚¬μš© (μ—†μœΌλ©΄ 였λ₯˜ λ°œμƒ) κΈ°μ‘΄ λ³€μˆ˜λ₯Ό μ‚¬μš© (μ—†μœΌλ©΄ 였λ₯˜ λ°œμƒ)

Better way 22 λ³€μˆ˜ μœ„μΉ˜ 인자λ₯Ό μ‚¬μš©ν•΄ μ‹œκ°μ μΈ μž‘μŒμ„ 쀄여라

예λ₯Ό λ“€λ©΄ 둜그λ₯Ό λ‚¨κΈ°λŠ” ν•¨μˆ˜λΌκ³  ν•˜μž

# μ•ˆ 쒋은 μ˜ˆμ‹œ
def log(message, values):
	if not values:
    	print(message)
    else:
        values_str = ', '.join(str(x) for x in values)
        print(f'{message}: {values_str}')

log('λ‚΄ μˆ«μžλŠ”', [1,2]) 
log('μ•ˆλ…•', []) # valuesκ°€ μ—†λŠ” κ²½μš°μ—λ„ 빈 리슀트λ₯Ό λ„£μ–΄μ€˜μ•Όν•¨

>>>
λ‚΄ μˆ«μžλŠ”: 1, 2
μ•ˆλ…•
# 쒋은 μ˜ˆμ‹œ - * ν‚€μ›Œλ“œ μ‚¬μš©
def log(message, *values): # μœ μΌν•˜κ²Œ 달라진 λΆ€λΆ„
	if not values:
    	print(message)
    else:
        values_str = ', '.join(str(x) for x in values)
        print(f'{message}: {values_str}')

log('λ‚΄ μˆ«μžλŠ”', 1, 2) 
log('μ•ˆλ…•') # valuesκ°€ μ—†λŠ” κ²½μš°μ—λŠ” μƒλž΅ κ°€λŠ₯

>>>
λ‚΄ μˆ«μžλŠ”: 1, 2
μ•ˆλ…•

 

Better Way 25: μœ„μΉ˜ μ „μš© 인자 λ˜λŠ” ν‚€μ›Œλ“œ μ „μš© 인자λ₯Ό μ‚¬μš©ν•΄ ν•¨μˆ˜ ν˜ΈμΆœμ„ λͺ…ν™•ν•˜κ²Œ λ§Œλ“€λΌ

ν•¨μˆ˜ 호좜이 λ³΅μž‘ν•˜κ³  νŠΉμ • 인자λ₯Ό ν‚€μ›Œλ“œ μ „μš© 인자둜 λ°”κΎΈμ–΄ ν•¨μˆ˜ ν˜ΈμΆœμ„ λͺ…ν™•ν•˜κ²Œ ν•  수 μžˆλ‹€.

# μ•ˆ 쒋은 μ˜ˆμ‹œ 
def move(x, y, speed):
    print(f"Moving to ({x}, {y}) at speed {speed}")

move(10, 20, 5)  # 속도가 μœ„μΉ˜μΈμ§€ ν—·κ°ˆλ¦΄ 수 있음


# 쒋은 μ˜ˆμ‹œ - * λ₯Ό 톡해 ν‚€μ›Œλ“œ μ „μš© 인자 섀정이 κ°€λŠ₯
def move(x, y, *, speed):
    print(f"Moving to ({x}, {y}) at speed {speed}")

move(10, 20, 5)
>>>
TypeError: move() takes 2 positional arguments but 3 were given


move(10, 20, speed=5) # speed ν‚€μ›Œλ“œ 인자 μ‚¬μš©
>>>
Moving to (10, 20) at speed 5

Better way 26 functools.wrap을 μ‚¬μš©ν•΄ ν•¨μˆ˜ λ°μ½”λ ˆμ΄ν„°λ₯Ό μ •μ˜ν•˜λΌ

νŒŒμ΄μ¬μ—μ„œλŠ” λ°μ½”λ ˆμ΄ν„°λ₯Ό μ •μ˜ν•  수 μžˆλŠ” 데, 이 λ•Œ functools.wrap을 μ‚¬μš©ν•˜μž

 

# μ•ˆ 쒋은 μ˜ˆμ‹œ - 메타 데이터가 사라짐 (디버거와 같이 μΈνŠΈλ‘œμŠ€νŽ™μ…˜ ν•˜λŠ” λ„κ΅¬μ—μ„œ λ¬Έμ œκ°€ λ°œμƒ)
def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("Before function call")
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def say_hello():
    """Returns a greeting."""
    print("Hello!")

print(say_hello.__name__)  # wrapper
print(say_hello.__doc__)   # None (λ¬Έμ„œ λ¬Έμžμ—΄μ΄ 사라짐)

 

# 쒋은 μ˜ˆμ‹œ
from functools import wraps

def my_decorator(func):
    @wraps(func)  # 원본 ν•¨μˆ˜μ˜ 메타데이터 μœ μ§€
    def wrapper(*args, **kwargs):
        print("Before function call")
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def say_hello():
    """Returns a greeting."""
    print("Hello!")

print(say_hello.__name__)  # say_hello
print(say_hello.__doc__)   # "Returns a greeting."

 

 

 

 

Effective Python 2nd μ΄νŽ™ν‹°λΈŒ 파이썬 : 파이썬 μ½”λ”©μ˜ 기술 : 넀이버 λ„μ„œ

넀이버 λ„μ„œ 상세정보λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€.

search.shopping.naver.com