לדלג לתוכן

9.2 פונקציות ומחלקות פתרון

ניקוי קוד - פונקציות

הבעיות שנמצאו:
- 10 פרמטרים לפונקציה - חורג בהרבה מהכלל של עד 3 פרמטרים.
- הפונקציה עושה שלושה דברים: מחשבת, מדפיסה, שולחת אימייל, ושומרת ל-DB.
- תופעת לוואי: שליחת אימייל ושמירה ל-DB בתוך פונקציה שנקראת handle_order.
- ערכים קסומים: import smtplib בתוך פונקציה.

פתרון:

from dataclasses import dataclass


@dataclass
class Customer:
    name: str
    email: str


@dataclass
class Product:
    id: str
    name: str
    price_per_unit: float


@dataclass
class ShippingAddress:
    address: str
    city: str
    country: str


def handle_order(customer: Customer, product: Product, quantity: int,
                 discount_percent: float, shipping: ShippingAddress) -> None:
    total = calculate_total(product.price_per_unit, quantity, discount_percent)
    print_order_summary(customer, product, quantity, discount_percent, total)
    send_confirmation(customer.email)
    save_order(customer.email, product.id, quantity)


def calculate_total(price: float, quantity: int, discount_percent: float) -> float:
    total = price * quantity
    return total - (total * discount_percent / 100)


def print_order_summary(customer: Customer, product: Product,
                        quantity: int, discount_percent: float, total: float) -> None:
    print(f"Order for {customer.name}")
    print(f"Email: {customer.email}")
    print(f"Product: {product.name} x{quantity}")
    if discount_percent > 0:
        print(f"Discount: {discount_percent}%")
    print(f"Total: {total}")


def send_confirmation(email: str) -> None:
    print(f"Confirmation sent to {email}")


def save_order(email: str, product_id: str, quantity: int) -> None:
    print("Order saved to database")

ניקוי קוד - רמות אבסטרקציה

def generate_report(data: list) -> None:
    valid = filter_valid_entries(data)
    avg = calculate_average(valid)
    print_report(valid, avg)


def filter_valid_entries(data: list) -> list:
    return [item for item in data if isinstance(item, dict)
            and "score" in item and item["score"] >= 0]


def calculate_average(entries: list) -> float:
    if not entries:
        return 0
    return sum(item["score"] for item in entries) / len(entries)


def print_report(entries: list, avg: float) -> None:
    print("=" * 40)
    print("REPORT")
    print("=" * 40)
    print(f"Total entries: {len(entries)}")
    print(f"Average score: {avg:.2f}")
    print_top_entries(entries)


def print_top_entries(entries: list) -> None:
    top = sorted(entries, key=lambda x: x["score"], reverse=True)[:3]
    for i, entry in enumerate(top, 1):
        print(f"{i}. {entry.get('name', 'Unknown')} - {entry['score']}")

בונוס - ערכים קסומים

MAX_HEAVY_WEIGHT_KG = 30
HEAVY_RATE_PER_KG = 4.5
LIGHT_RATE_PER_KG = 2.8
LONG_DISTANCE_KM = 500
LONG_DISTANCE_SURCHARGE = 1.35
MIN_SHIPPING_COST = 15


def calculate_shipping(weight: float, distance: float) -> float:
    if weight > MAX_HEAVY_WEIGHT_KG:
        base = weight * HEAVY_RATE_PER_KG
    else:
        base = weight * LIGHT_RATE_PER_KG

    if distance > LONG_DISTANCE_KM:
        base *= LONG_DISTANCE_SURCHARGE

    if base < MIN_SHIPPING_COST:
        base = MIN_SHIPPING_COST

    return round(base, 2)