KR_ControlFlow - somaz94/python-study GitHub Wiki

Python ์ œ์–ด ํ๋ฆ„(Control Flow) ๊ฐœ๋… ์ •๋ฆฌ


1๏ธโƒฃ break ๋ฌธ

๋ฐ˜๋ณต๋ฌธ์„ ์ฆ‰์‹œ ์ข…๋ฃŒํ•˜๋Š” ์ œ์–ด๋ฌธ์ž…๋‹ˆ๋‹ค.

# ์˜ˆ์ œ 1: ์ˆซ์ž 5๋ฅผ ๋งŒ๋‚˜๋ฉด ๋ฐ˜๋ณต ์ข…๋ฃŒ
for i in range(10):
    if i == 5:
        break
    print(i)  # 0,1,2,3,4 ์ถœ๋ ฅ

# ์˜ˆ์ œ 2: while๋ฌธ์—์„œ์˜ break
while True:
    response = input("๊ณ„์†ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? (y/n): ")
    if response == 'n':
        break

โœ… ํŠน์ง•:

  • ๋ฐ˜๋ณต๋ฌธ์„ ์ฆ‰์‹œ ์ข…๋ฃŒ
  • ์ค‘์ฒฉ ๋ฐ˜๋ณต๋ฌธ์—์„œ๋Š” ๊ฐ€์žฅ ์•ˆ์ชฝ์˜ ๋ฐ˜๋ณต๋ฌธ๋งŒ ์ข…๋ฃŒ
  • while True์™€ ์ž์ฃผ ํ•จ๊ป˜ ์‚ฌ์šฉ


2๏ธโƒฃ continue ๋ฌธ

ํ˜„์žฌ ๋ฐ˜๋ณต์„ ๊ฑด๋„ˆ๋›ฐ๊ณ  ๋‹ค์Œ ๋ฐ˜๋ณต์œผ๋กœ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

# ์˜ˆ์ œ 1: ์ง์ˆ˜๋งŒ ์ถœ๋ ฅ
for i in range(5):
    if i % 2 != 0:
        continue
    print(i)  # 0,2,4 ์ถœ๋ ฅ

# ์˜ˆ์ œ 2: ํŠน์ • ์กฐ๊ฑด ๊ฑด๋„ˆ๋›ฐ๊ธฐ
for name in ['John', '', 'Jane', '', 'Mike']:
    if name == '':
        continue
    print(name)  # ๋นˆ ๋ฌธ์ž์—ด ์ œ์™ธํ•˜๊ณ  ์ถœ๋ ฅ

โœ… ํŠน์ง•:

  • ํ˜„์žฌ ๋ฐ˜๋ณต๋งŒ ๊ฑด๋„ˆ๋œ€
  • ๋ฐ˜๋ณต๋ฌธ์˜ ์‹œ์ž‘์œผ๋กœ ์ฆ‰์‹œ ์ด๋™
  • ์กฐ๊ฑด์— ๋งž์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋ฅผ ์ฒ˜๋ฆฌํ•  ๋•Œ ์œ ์šฉ


3๏ธโƒฃ pass ๋ฌธ

์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ์•Š๊ณ  ๋„˜์–ด๊ฐ‘๋‹ˆ๋‹ค.

# ์˜ˆ์ œ 1: ํด๋ž˜์Šค ๋ผˆ๋Œ€ ๋งŒ๋“ค๊ธฐ
class MyEmptyClass:
    pass

# ์˜ˆ์ œ 2: ์กฐ๊ฑด๋ฌธ์—์„œ ์‚ฌ์šฉ
if True:
    pass  # ๋‚˜์ค‘์— ๊ตฌํ˜„ํ•  ์˜ˆ์ •
else:
    print("else")

โœ… ํŠน์ง•:

  • ๋ฌธ๋ฒ•์ ์œผ๋กœ ๋ฌธ์žฅ์ด ํ•„์š”ํ•  ๋•Œ ์‚ฌ์šฉ
  • ์ž„์‹œ ์ฝ”๋“œ ์ž‘์„ฑ ์‹œ ์œ ์šฉ
  • ์•„๋ฌด ๋™์ž‘๋„ ํ•˜์ง€ ์•Š์Œ


4๏ธโƒฃ else ์ ˆ๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉ

๋ฐ˜๋ณต๋ฌธ์ด ์ •์ƒ์ ์œผ๋กœ ์™„๋ฃŒ๋  ๋•Œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

# for-else ์˜ˆ์ œ
for i in range(5):
    if i == 10:
        break
else:
    print("๋ฐ˜๋ณต๋ฌธ์ด ์ •์ƒ์ ์œผ๋กœ ์™„๋ฃŒ๋จ")

# while-else ์˜ˆ์ œ
count = 0
while count < 3:
    print(count)
    count += 1
else:
    print("while๋ฌธ์ด ์ •์ƒ์ ์œผ๋กœ ์™„๋ฃŒ๋จ")

โœ… ํŠน์ง•:

  • break ์—†์ด ๋ฐ˜๋ณต๋ฌธ์ด ์™„๋ฃŒ๋  ๋•Œ ์‹คํ–‰
  • ๋ฐ˜๋ณต๋ฌธ์˜ ์ •์ƒ ์ข…๋ฃŒ ์—ฌ๋ถ€ ํ™•์ธ ๊ฐ€๋Šฅ
  • for๋ฌธ๊ณผ while๋ฌธ ๋ชจ๋‘ ์‚ฌ์šฉ ๊ฐ€๋Šฅ


5๏ธโƒฃ ์ค‘์ฒฉ๋œ ์ œ์–ด๋ฌธ

์ œ์–ด๋ฌธ ์•ˆ์— ๋‹ค๋ฅธ ์ œ์–ด๋ฌธ์„ ํฌํ•จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

# ์ค‘์ฒฉ ๋ฐ˜๋ณต๋ฌธ์—์„œ break ์‚ฌ์šฉ
for i in range(3):
    for j in range(3):
        if i == j:
            break
        print(i, j)

# ์ค‘์ฒฉ ์กฐ๊ฑด๋ฌธ์—์„œ continue ์‚ฌ์šฉ
for i in range(5):
    if i < 2:
        continue
    if i > 3:
        break
    print(i)  # 2,3 ์ถœ๋ ฅ

โœ… ํŠน์ง•:

  • ์—ฌ๋Ÿฌ ์ œ์–ด๋ฌธ์„ ์ค‘์ฒฉํ•ด์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
  • ๋ณต์žกํ•œ ๋กœ์ง ๊ตฌํ˜„์— ํ™œ์šฉ
  • ๊ฐ€๋…์„ฑ์„ ์œ„ํ•ด ์ ์ ˆํ•œ ๋“ค์—ฌ์“ฐ๊ธฐ ํ•„์š”


6๏ธโƒฃ try-except-else-finally ๊ตฌ๋ฌธ

์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ์ œ์–ด ํ๋ฆ„ ๊ตฌ์กฐ์ด๋‹ค.

# ๊ธฐ๋ณธ try-except
try:
    result = 10 / 0
except ZeroDivisionError:
    print("0์œผ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค")

# try-except-else-finally
try:
    number = int(input("์ˆซ์ž๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”: "))
    result = 100 / number
except ValueError:
    print("์˜ฌ๋ฐ”๋ฅธ ์ˆซ์ž๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”")
except ZeroDivisionError:
    print("0์œผ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค")
else:
    print(f"๊ฒฐ๊ณผ: {result}")  # ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์œผ๋ฉด ์‹คํ–‰
finally:
    print("ํ•ญ์ƒ ์‹คํ–‰๋˜๋Š” ์ฝ”๋“œ")  # ์˜ˆ์™ธ ๋ฐœ์ƒ ์—ฌ๋ถ€์™€ ๊ด€๊ณ„์—†์ด ์‹คํ–‰

โœ… ๊ตฌ์„ฑ ์š”์†Œ:

  • try: ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์ฝ”๋“œ
  • except: ํŠน์ • ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์‹คํ–‰ํ•  ์ฝ”๋“œ
  • else: ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์•˜์„ ๋•Œ ์‹คํ–‰ํ•  ์ฝ”๋“œ
  • finally: ์˜ˆ์™ธ ๋ฐœ์ƒ ์—ฌ๋ถ€์™€ ๊ด€๊ณ„์—†์ด ํ•ญ์ƒ ์‹คํ–‰ํ•  ์ฝ”๋“œ


7๏ธโƒฃ ์ปจํ…์ŠคํŠธ ๊ด€๋ฆฌ์ž(with ๋ฌธ)

๋ฆฌ์†Œ์Šค์˜ ํš๋“๊ณผ ํ•ด์ œ๋ฅผ ์ž๋™์œผ๋กœ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

# ํŒŒ์ผ ์ฒ˜๋ฆฌ์— with ์‚ฌ์šฉ
with open('example.txt', 'w') as file:
    file.write('Hello, World!')
# ํŒŒ์ผ์ด ์ž๋™์œผ๋กœ ๋‹ซํž˜

# ์—ฌ๋Ÿฌ ์ปจํ…์ŠคํŠธ ๊ด€๋ฆฌ์ž ๋™์‹œ ์‚ฌ์šฉ
with open('input.txt', 'r') as input_file, open('output.txt', 'w') as output_file:
    content = input_file.read()
    output_file.write(content.upper())

# ์‚ฌ์šฉ์ž ์ •์˜ ์ปจํ…์ŠคํŠธ ๊ด€๋ฆฌ์ž
from contextlib import contextmanager

@contextmanager
def timer():
    import time
    start = time.time()
    yield  # ์ด ์ง€์ ์—์„œ with ๋ธ”๋ก ๋‚ด๋ถ€ ์ฝ”๋“œ ์‹คํ–‰
    end = time.time()
    print(f"์‹คํ–‰ ์‹œ๊ฐ„: {end - start}์ดˆ")

# ์‚ฌ์šฉ
with timer():
    # ์‹œ๊ฐ„์„ ์ธก์ •ํ•  ์ฝ”๋“œ
    sum(range(1000000))

โœ… ์žฅ์ :

  • ๋ฆฌ์†Œ์Šค ๋ˆ„์ˆ˜ ๋ฐฉ์ง€
  • ์ž๋™ ์ •๋ฆฌ(cleanup) ๋ณด์žฅ
  • ์ฝ”๋“œ ๊ฐ„๊ฒฐ์„ฑ ํ–ฅ์ƒ
  • ์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ์—๋„ ๋ฆฌ์†Œ์Šค ํ•ด์ œ


8๏ธโƒฃ match-case ๋ฌธ(Python 3.10+)

๊ตฌ์กฐ์  ํŒจํ„ด ๋งค์นญ์„ ์ œ๊ณตํ•˜๋Š” Switch-case์™€ ์œ ์‚ฌํ•œ ๊ตฌ๋ฌธ์ด๋‹ค.

# ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•
def process_response(status):
    match status:
        case 200:
            return "OK"
        case 404:
            return "Not Found"
        case 500:
            return "Server Error"
        case _:  # ๊ธฐ๋ณธ๊ฐ’
            return "Unknown"

# ํŒจํ„ด ๋งค์นญ ํ™œ์šฉ
def process_command(command):
    match command.split():
        case ["quit"]:
            return "ํ”„๋กœ๊ทธ๋žจ์„ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค."
        case ["help"]:
            return "๋„์›€๋ง์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค."
        case ["open", filename]:
            return f"{filename} ํŒŒ์ผ์„ ์—ฝ๋‹ˆ๋‹ค."
        case ["save", filename]:
            return f"{filename} ํŒŒ์ผ์„ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค."
        case ["open", *filenames]:
            return f"์—ฌ๋Ÿฌ ํŒŒ์ผ์„ ์—ฝ๋‹ˆ๋‹ค: {filenames}"
        case _:
            return "์•Œ ์ˆ˜ ์—†๋Š” ๋ช…๋ น์–ด์ž…๋‹ˆ๋‹ค."

# ๊ฐ์ฒด ํŒจํ„ด ๋งค์นญ
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

def classify_point(point):
    match point:
        case Point(x=0, y=0):
            return "์›์ "
        case Point(x=0, y=y):
            return f"y์ถ• ์œ„์˜ ์  (y={y})"
        case Point(x=x, y=0):
            return f"x์ถ• ์œ„์˜ ์  (x={x})"
        case Point(x=x, y=y) if x == y:
            return f"๋Œ€๊ฐ์„  ์œ„์˜ ์  (x=y={x})"
        case Point():
            return f"์ผ๋ฐ˜ ์ขŒํ‘œ ({point.x}, {point.y})"

โœ… ํŠน์ง•:

  • ๋ณต์žกํ•œ ์กฐ๊ฑด๋ฌธ ๋Œ€์ฒด ๊ฐ€๋Šฅ
  • ๋‹ค์–‘ํ•œ ํŒจํ„ด ๋งค์นญ ์ง€์›
  • ๊ตฌ์กฐ ๋ถ„ํ•ด(destructuring) ๊ธฐ๋Šฅ
  • ๊ฐ€๋“œ ์กฐ๊ฑด(if ์กฐ๊ฑด) ์‚ฌ์šฉ ๊ฐ€๋Šฅ
  • ์ฝ”๋“œ ๊ฐ€๋…์„ฑ ํ–ฅ์ƒ


9๏ธโƒฃ ์ œ์–ด ํ๋ฆ„ ์ตœ์ ํ™” ๊ธฐ๋ฒ•

์ œ์–ด ํ๋ฆ„์„ ์ตœ์ ํ™”ํ•˜์—ฌ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ค๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

1. ์กฐ๊ธฐ ๋ฐ˜ํ™˜ ํŒจํ„ด

# ์ค‘์ฒฉ ์กฐ๊ฑด๋ฌธ
def process_data(data):
    if data:
        if isinstance(data, list):
            if len(data) > 0:
                # ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ
                return "์ฒ˜๋ฆฌ ์™„๋ฃŒ"
            else:
                return "๋นˆ ๋ฆฌ์ŠคํŠธ"
        else:
            return "๋ฆฌ์ŠคํŠธ๊ฐ€ ์•„๋‹˜"
    else:
        return "๋ฐ์ดํ„ฐ ์—†์Œ"

# ์กฐ๊ธฐ ๋ฐ˜ํ™˜ ํŒจํ„ด
def process_data_optimized(data):
    if not data:
        return "๋ฐ์ดํ„ฐ ์—†์Œ"
    
    if not isinstance(data, list):
        return "๋ฆฌ์ŠคํŠธ๊ฐ€ ์•„๋‹˜"
    
    if len(data) == 0:
        return "๋นˆ ๋ฆฌ์ŠคํŠธ"
    
    # ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ
    return "์ฒ˜๋ฆฌ ์™„๋ฃŒ"

2. ๊ฒ€์ƒ‰ ์ตœ์ ํ™”

# ์„ ํ˜• ๊ฒ€์ƒ‰ - break ํ™œ์šฉ
def find_element(data, target):
    result = -1
    for i, value in enumerate(data):
        if value == target:
            result = i
            break
    return result

# ์ด์ง„ ๊ฒ€์ƒ‰ - ์ •๋ ฌ๋œ ๋ฐ์ดํ„ฐ์—์„œ ํšจ์œจ์ 
def binary_search(data, target):
    low, high = 0, len(data) - 1
    
    while low <= high:
        mid = (low + high) // 2
        if data[mid] == target:
            return mid
        elif data[mid] < target:
            low = mid + 1
        else:
            high = mid - 1
    
    return -1

3. ๋ฃจํ”„ ์ตœ์ ํ™”

import time

# ๋ฃจํ”„ ๋‚ด ์—ฐ์‚ฐ ์ตœ์†Œํ™”
def sum_squares_unoptimized(n):
    start = time.time()
    result = 0
    for i in range(n):
        result += i**2
    print(f"Unoptimized: {time.time() - start:.6f}์ดˆ")
    return result

def sum_squares_optimized(n):
    start = time.time()
    # ๋ฃจํ”„ ๋ฐ–์œผ๋กœ ๋น„์šฉ์ด ํฐ ์—ฐ์‚ฐ ์ด๋™
    result = sum(i**2 for i in range(n))
    print(f"Optimized: {time.time() - start:.6f}์ดˆ")
    return result

# ์˜ˆ์‹œ: ์ฒ˜๋ฆฌํ•  ๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ์„ ๋•Œ ํšจ๊ณผ์ 
sum_squares_unoptimized(1000000)
sum_squares_optimized(1000000)

โœ… ์ตœ์ ํ™” ์›์น™:

  • ๋ถˆํ•„์š”ํ•œ ์—ฐ์‚ฐ ์ œ๊ฑฐ
  • ์กฐ๊ฑด ๊ฒ€์‚ฌ ์ˆœ์„œ ์ตœ์ ํ™”
  • ์กฐ๊ธฐ ๋ฐ˜ํ™˜ ํ™œ์šฉ
  • ์ ์ ˆํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์„ ํƒ
  • ๋ฃจํ”„ ๋‚ด๋ถ€ ์—ฐ์‚ฐ ์ตœ์†Œํ™”


๐Ÿ”Ÿ ๊ณ ๊ธ‰ ์ œ์–ด ํ๋ฆ„ ํŒจํ„ด

์‹ค๋ฌด์—์„œ ์œ ์šฉํ•œ ๊ณ ๊ธ‰ ์ œ์–ด ํ๋ฆ„ ํŒจํ„ด์ด๋‹ค.


1. ๊ฐ€๋“œ ํŒจํ„ด(Guard Pattern)

def process_user(user_data):
    # ๊ฐ€๋“œ ์ ˆ - ์œ ํšจํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ๋น ๋ฅด๊ฒŒ ๋ฐ˜ํ™˜
    if user_data is None:
        return "์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค"
    
    if not isinstance(user_data, dict):
        return "์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๋Š” ๋”•์…”๋„ˆ๋ฆฌ ํ˜•ํƒœ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค"
    
    if 'name' not in user_data:
        return "์‚ฌ์šฉ์ž ์ด๋ฆ„์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค"
    
    if 'age' not in user_data:
        return "์‚ฌ์šฉ์ž ๋‚˜์ด๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค"
    
    # ๋ชจ๋“  ๊ฒ€์ฆ์„ ํ†ต๊ณผํ•œ ํ›„ ์‹ค์ œ ์ฒ˜๋ฆฌ ๋กœ์ง
    name = user_data['name']
    age = user_data['age']
    
    return f"{name}({age}์„ธ) ์‚ฌ์šฉ์ž ์ฒ˜๋ฆฌ ์™„๋ฃŒ"

2. ์ƒํƒœ ํŒจํ„ด(State Pattern)

class OrderState:
    def process(self, order):
        raise NotImplementedError
    
    def cancel(self, order):
        raise NotImplementedError

class NewOrder(OrderState):
    def process(self, order):
        print("์ฃผ๋ฌธ ์ฒ˜๋ฆฌ ์‹œ์ž‘")
        order.state = ProcessingOrder()
        return True
    
    def cancel(self, order):
        print("์ƒˆ ์ฃผ๋ฌธ ์ทจ์†Œ")
        order.state = CancelledOrder()
        return True

class ProcessingOrder(OrderState):
    def process(self, order):
        print("์ด๋ฏธ ์ฒ˜๋ฆฌ ์ค‘์ž…๋‹ˆ๋‹ค")
        return False
    
    def cancel(self, order):
        print("์ฒ˜๋ฆฌ ์ค‘ ์ฃผ๋ฌธ ์ทจ์†Œ")
        order.state = CancelledOrder()
        return True

class ShippedOrder(OrderState):
    def process(self, order):
        print("์ด๋ฏธ ๋ฐœ์†ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค")
        return False
    
    def cancel(self, order):
        print("๋ฐœ์†ก๋œ ์ฃผ๋ฌธ์€ ์ทจ์†Œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค")
        return False

class CancelledOrder(OrderState):
    def process(self, order):
        print("์ทจ์†Œ๋œ ์ฃผ๋ฌธ์€ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค")
        return False
    
    def cancel(self, order):
        print("์ด๋ฏธ ์ทจ์†Œ๋œ ์ฃผ๋ฌธ์ž…๋‹ˆ๋‹ค")
        return False

class Order:
    def __init__(self):
        self.state = NewOrder()
    
    def process(self):
        return self.state.process(self)
    
    def cancel(self):
        return self.state.cancel(self)

3. ์ฒด์ธ ํŒจํ„ด(Chain Pattern)

def validate_username(username):
    if len(username) < 4:
        return False, "์‚ฌ์šฉ์ž ์ด๋ฆ„์€ 4์ž ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค"
    return True, None

def validate_email(email):
    if '@' not in email:
        return False, "์œ ํšจํ•œ ์ด๋ฉ”์ผ ํ˜•์‹์ด ์•„๋‹™๋‹ˆ๋‹ค"
    return True, None

def validate_password(password):
    if len(password) < 8:
        return False, "๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” 8์ž ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค"
    return True, None

def register_user(username, email, password):
    # ๊ฒ€์ฆ ์ฒด์ธ
    validations = [
        (validate_username, username),
        (validate_email, email),
        (validate_password, password)
    ]
    
    for validator, value in validations:
        valid, error = validator(value)
        if not valid:
            return {"success": False, "error": error}
    
    # ๋ชจ๋“  ๊ฒ€์ฆ์„ ํ†ต๊ณผํ•˜๋ฉด ์‚ฌ์šฉ์ž ๋“ฑ๋ก
    return {"success": True, "message": "์‚ฌ์šฉ์ž๊ฐ€ ๋“ฑ๋ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค"}

4. ์ „๋žต ํŒจํ„ด(Strategy Pattern)

from abc import ABC, abstractmethod

# ์ „๋žต ์ธํ„ฐํŽ˜์ด์Šค
class SortStrategy(ABC):
    @abstractmethod
    def sort(self, data):
        pass

# ๊ตฌ์ฒด์ ์ธ ์ „๋žต๋“ค
class QuickSort(SortStrategy):
    def sort(self, data):
        print("ํ€ต ์ •๋ ฌ ์ˆ˜ํ–‰")
        return sorted(data)  # ์‹ค์ œ๋กœ๋Š” ํ€ต ์ •๋ ฌ ๊ตฌํ˜„

class MergeSort(SortStrategy):
    def sort(self, data):
        print("๋ณ‘ํ•ฉ ์ •๋ ฌ ์ˆ˜ํ–‰")
        return sorted(data)  # ์‹ค์ œ๋กœ๋Š” ๋ณ‘ํ•ฉ ์ •๋ ฌ ๊ตฌํ˜„

class BubbleSort(SortStrategy):
    def sort(self, data):
        print("๋ฒ„๋ธ” ์ •๋ ฌ ์ˆ˜ํ–‰")
        return sorted(data)  # ์‹ค์ œ๋กœ๋Š” ๋ฒ„๋ธ” ์ •๋ ฌ ๊ตฌํ˜„

# ์ปจํ…์ŠคํŠธ
class Sorter:
    def __init__(self, strategy=None):
        self.strategy = strategy or QuickSort()
    
    def set_strategy(self, strategy):
        self.strategy = strategy
    
    def sort(self, data):
        return self.strategy.sort(data)

# ์‚ฌ์šฉ ์˜ˆ์‹œ
sorter = Sorter()
data = [3, 1, 4, 1, 5, 9, 2, 6]

# ๊ธฐ๋ณธ ์ „๋žต(ํ€ต ์ •๋ ฌ) ์‚ฌ์šฉ
result = sorter.sort(data)

# ์ „๋žต ๋ณ€๊ฒฝ
sorter.set_strategy(MergeSort())
result = sorter.sort(data)

# ์กฐ๊ฑด์— ๋”ฐ๋ฅธ ์ „๋žต ์„ ํƒ
if len(data) < 10:
    sorter.set_strategy(BubbleSort())
else:
    sorter.set_strategy(QuickSort())

result = sorter.sort(data)

โœ… ๊ณ ๊ธ‰ ํŒจํ„ด ์žฅ์ :

  • ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ ์ฆ๊ฐ€
  • ์œ ์ง€๋ณด์ˆ˜์„ฑ ํ–ฅ์ƒ
  • ํ™•์žฅ์„ฑ ๊ฐœ์„ 
  • ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ
  • ์ฝ”๋“œ ๊ตฌ์กฐํ™” ๋ฐ ๋ชจ๋“ˆํ™”


1๏ธโƒฃ1๏ธโƒฃ ๋น„๋™๊ธฐ ์ œ์–ด ํ๋ฆ„

๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ์˜ ์ œ์–ด ํ๋ฆ„ ๊ด€๋ฆฌ ๋ฐฉ๋ฒ•์ด๋‹ค.

import asyncio

# ๊ธฐ๋ณธ ๋น„๋™๊ธฐ ํ•จ์ˆ˜
async def fetch_data(id):
    print(f"๋ฐ์ดํ„ฐ {id} ๊ฐ€์ ธ์˜ค๋Š” ์ค‘...")
    await asyncio.sleep(1)  # ๋น„๋™๊ธฐ ๋Œ€๊ธฐ (I/O ์ž‘์—… ์‹œ๋ฎฌ๋ ˆ์ด์…˜)
    return f"๋ฐ์ดํ„ฐ {id}"

# ๋™์‹œ ์‹คํ–‰
async def fetch_all_data():
    # ์—ฌ๋Ÿฌ ์ž‘์—… ๋™์‹œ ์‹คํ–‰
    tasks = [fetch_data(i) for i in range(1, 6)]
    results = await asyncio.gather(*tasks)
    return results

# ์ˆœ์ฐจ ์‹คํ–‰
async def fetch_in_sequence():
    results = []
    for i in range(1, 6):
        result = await fetch_data(i)
        results.append(result)
    return results

# ํƒ€์ž„์•„์›ƒ ์ฒ˜๋ฆฌ
async def fetch_with_timeout(id, timeout=1.5):
    try:
        return await asyncio.wait_for(fetch_data(id), timeout)
    except asyncio.TimeoutError:
        return f"๋ฐ์ดํ„ฐ {id} ๊ฐ€์ ธ์˜ค๊ธฐ ์‹œ๊ฐ„ ์ดˆ๊ณผ"

# ๋น„๋™๊ธฐ ์ปจํ…์ŠคํŠธ ๊ด€๋ฆฌ์ž
async def process_data():
    async with asyncio.TaskGroup() as tg:
        task1 = tg.create_task(fetch_data(1))
        task2 = tg.create_task(fetch_data(2))
        task3 = tg.create_task(fetch_data(3))
    
    # ๋ชจ๋“  ์ž‘์—…์ด ์™„๋ฃŒ๋œ ํ›„ ๊ฒฐ๊ณผ ์‚ฌ์šฉ
    return [task1.result(), task2.result(), task3.result()]

# ๋น„๋™๊ธฐ ์ดํ„ฐ๋ ˆ์ด์…˜
async def async_range(start, stop):
    for i in range(start, stop):
        await asyncio.sleep(0.5)
        yield i

async def use_async_iterator():
    async for i in async_range(1, 5):
        print(f"๋น„๋™๊ธฐ ์ดํ„ฐ๋ ˆ์ด์…˜: {i}")

# ๋ฉ”์ธ ํ•จ์ˆ˜
async def main():
    # ๋™์‹œ ์‹คํ–‰
    results = await fetch_all_data()
    print(f"๋™์‹œ ์‹คํ–‰ ๊ฒฐ๊ณผ: {results}")
    
    # ์ˆœ์ฐจ ์‹คํ–‰
    results = await fetch_in_sequence()
    print(f"์ˆœ์ฐจ ์‹คํ–‰ ๊ฒฐ๊ณผ: {results}")
    
    # ํƒ€์ž„์•„์›ƒ ์ฒ˜๋ฆฌ
    result = await fetch_with_timeout(5, 0.5)
    print(f"ํƒ€์ž„์•„์›ƒ ์ฒ˜๋ฆฌ: {result}")
    
    # ๋น„๋™๊ธฐ ์ปจํ…์ŠคํŠธ ๊ด€๋ฆฌ์ž
    results = await process_data()
    print(f"TaskGroup ๊ฒฐ๊ณผ: {results}")
    
    # ๋น„๋™๊ธฐ ์ดํ„ฐ๋ ˆ์ด์…˜
    await use_async_iterator()

# ์‹คํ–‰
if __name__ == "__main__":
    asyncio.run(main())

โœ… ๋น„๋™๊ธฐ ์ œ์–ด ํ๋ฆ„ ํŠน์ง•:

  • ๋™์‹œ์„ฑ ์ฒ˜๋ฆฌ
  • ๋น„์ฐจ๋‹จ(non-blocking) I/O
  • ํƒ€์ž„์•„์›ƒ ๊ด€๋ฆฌ
  • ์ž‘์—… ๊ทธ๋ฃนํ™”
  • ๋น„๋™๊ธฐ ์ดํ„ฐ๋ ˆ์ด์…˜
  • ๋น„๋™๊ธฐ ์ปจํ…์ŠคํŠธ ๊ด€๋ฆฌ


1๏ธโƒฃ2๏ธโƒฃ ์ œ์–ด ํ๋ฆ„ ์ตœ์ ํ™” ์‚ฌ๋ก€ ์—ฐ๊ตฌ

์‹ค์ œ ์‚ฌ๋ก€๋ฅผ ํ†ตํ•œ ์ œ์–ด ํ๋ฆ„ ์ตœ์ ํ™” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณธ๋‹ค.


๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ํŒŒ์ดํ”„๋ผ์ธ

# ๊ฐ ๋‹จ๊ณ„๋ณ„ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜
def validate_data(data):
    if not data:
        return None
    return data

def transform_data(data):
    if data is None:
        return None
    
    try:
        transformed = [x * 2 for x in data]
        return transformed
    except Exception:
        return None

def filter_data(data):
    if data is None:
        return None
    
    return [x for x in data if x > 10]

def save_data(data):
    if data is None:
        return "์ฒ˜๋ฆฌ ์‹คํŒจ"
    
    # ์ €์žฅ ๋กœ์ง
    return f"์ €์žฅ ์™„๋ฃŒ: {data}"

# ์ตœ์ ํ™” ์ „ - ์ค‘์ฒฉ ์กฐ๊ฑด๋ฌธ
def process_pipeline_original(data):
    validated = validate_data(data)
    if validated is not None:
        transformed = transform_data(validated)
        if transformed is not None:
            filtered = filter_data(transformed)
            if filtered is not None:
                return save_data(filtered)
            else:
                return "ํ•„ํ„ฐ๋ง ์‹คํŒจ"
        else:
            return "๋ณ€ํ™˜ ์‹คํŒจ"
    else:
        return "์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์‹คํŒจ"

# ์ตœ์ ํ™” ํ›„ - ์กฐ๊ธฐ ๋ฐ˜ํ™˜ ๋ฐ ํŒŒ์ดํ”„๋ผ์ธ ํŒจํ„ด
def process_pipeline_optimized(data):
    validated = validate_data(data)
    if validated is None:
        return "์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์‹คํŒจ"
    
    transformed = transform_data(validated)
    if transformed is None:
        return "๋ณ€ํ™˜ ์‹คํŒจ"
    
    filtered = filter_data(transformed)
    if filtered is None:
        return "ํ•„ํ„ฐ๋ง ์‹คํŒจ"
    
    return save_data(filtered)

# ํ•จ์ˆ˜ํ˜• ์ ‘๊ทผ๋ฒ•
def pipeline(*funcs):
    def process(data):
        result = data
        for func in funcs:
            result = func(result)
            if result is None:
                return None
        return result
    return process

# ์‚ฌ์šฉ ์˜ˆ์‹œ
process_data = pipeline(validate_data, transform_data, filter_data)
result = process_data([1, 5, 10, 15])
if result is not None:
    print(save_data(result))
else:
    print("ํŒŒ์ดํ”„๋ผ์ธ ์ฒ˜๋ฆฌ ์‹คํŒจ")

๊ณ ์„ฑ๋Šฅ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ

import time
from collections import defaultdict

class EventProcessor:
    def __init__(self):
        self.handlers = defaultdict(list)
        self.default_handler = lambda event: print(f"์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์€ ์ด๋ฒคํŠธ: {event}")
    
    def register(self, event_type, handler):
        self.handlers[event_type].append(handler)
    
    def process(self, event):
        event_type = event.get('type')
        
        # ๋น ๋ฅธ ๊ฒฝ๋กœ(fast path): ์•Œ๋ ค์ง„ ์ด๋ฒคํŠธ ํƒ€์ž…์ธ ๊ฒฝ์šฐ
        if event_type in self.handlers:
            for handler in self.handlers[event_type]:
                handler(event)
            return True
        
        # ๋А๋ฆฐ ๊ฒฝ๋กœ(slow path): ์•Œ๋ ค์ง„ ์ด๋ฒคํŠธ ํƒ€์ž…์ด ์•„๋‹Œ ๊ฒฝ์šฐ
        self.default_handler(event)
        return False

# ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ
def handle_click(event):
    print(f"ํด๋ฆญ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ: {event.get('position')}")

def handle_hover(event):
    print(f"ํ˜ธ๋ฒ„ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ: {event.get('position')}")

def handle_key(event):
    print(f"ํ‚ค ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ: {event.get('key')}")

# ์‚ฌ์šฉ ์˜ˆ์‹œ
processor = EventProcessor()
processor.register('click', handle_click)
processor.register('hover', handle_hover)
processor.register('keypress', handle_key)

# ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ
events = [
    {'type': 'click', 'position': (10, 20)},
    {'type': 'hover', 'position': (30, 40)},
    {'type': 'keypress', 'key': 'Enter'},
    {'type': 'unknown', 'data': 'some data'}
]

for event in events:
    processor.process(event)

โœ… ์‚ฌ๋ก€ ์—ฐ๊ตฌ ํ•ต์‹ฌ ํฌ์ธํŠธ:

  • ์ฝ”๋“œ ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ ํ–ฅ์ƒ
  • ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๋ถ„๋ฆฌ
  • ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๊ฐœ์„ 
  • ํ™•์žฅ์„ฑ ๋†’์€ ๊ตฌ์กฐ ์„ค๊ณ„
  • ์‹คํ–‰ ๊ฒฝ๋กœ ์ตœ์ ํ™”
  • ์ œ์–ด ํ๋ฆ„ ๋ช…ํ™•ํ™”


โš ๏ธ **GitHub.com Fallback** โš ๏ธ