تمرین و پروژه‌های پایتون

ساخت برنامه تبدیل واحد با پایتون؛ پروژه کامل طول، وزن، دما، حجم و سرعت

ساخت برنامه تبدیل واحد با پایتون

🗓 آخرین به‌روزرسانی:

ساخت برنامه تبدیل واحد با پایتون یکی از پروژه‌های مناسب برای تمرین محاسبات، توابع، دیکشنری، مدیریت ورودی و طراحی یک منوی متنی است. در این آموزش یک مبدل ساده چندخطی نمی‌سازیم؛ بلکه برنامه‌ای کامل خواهیم داشت که بتواند واحدهای طول، وزن، حجم، سرعت و دما را به یکدیگر تبدیل کند، ورودی نامعتبر را مدیریت کند و به‌سادگی برای واحدهای جدید توسعه پیدا کند.

اگر سه پروژه قبلی این مجموعه یعنی بازی حدس عدد با پایتون، بازی سنگ کاغذ قیچی با پایتون و تولیدکننده رمز عبور با پایتون را انجام داده باشید، این پروژه قدم بعدی مناسبی است. این بار تمرکز اصلی روی طراحی ساختار داده برای تبدیل‌ها و جدا کردن منطق محاسبه از رابط کاربری است.

در این پروژه چه چیزی می‌سازیم؟

برنامه نهایی در ترمینال اجرا می‌شود. کاربر ابتدا نوع تبدیل را انتخاب می‌کند، سپس واحد مبدأ، واحد مقصد و مقدار را وارد می‌کند. نتیجه محاسبه و نمایش داده می‌شود و کاربر می‌تواند تبدیل دیگری انجام دهد.

  • تبدیل واحدهای طول
  • تبدیل واحدهای وزن
  • تبدیل واحدهای حجم
  • تبدیل واحدهای سرعت
  • تبدیل دما بین سلسیوس، فارنهایت و کلوین
  • اعتبارسنجی ورودی عددی
  • تشخیص واحد نامعتبر
  • منوی تعاملی و امکان اجرای چند تبدیل
  • ساختار قابل توسعه برای افزودن واحدهای جدید

پیش‌نیازهای پروژه

این پروژه فقط از امکانات داخلی پایتون استفاده می‌کند و نیازی به نصب پکیج خارجی ندارد. بهتر است با تابع input در پایتون، توابع و پارامترها و مدیریت خطا با try و except آشنا باشید.

یک فایل جدید با نام زیر ایجاد کنید:

unit_converter.py

سپس آن را اجرا کنید:

python unit_converter.py

ایده اصلی تبدیل واحدها

برای بسیاری از واحدها می‌توان یک «واحد پایه» تعریف کرد. برای مثال در گروه طول، متر را واحد پایه در نظر می‌گیریم. اگر بخواهیم ۲.۵ متر را به سانتی‌متر تبدیل کنیم، ابتدا مقدار را به متر پایه می‌بریم و سپس از متر به سانتی‌متر تبدیل می‌کنیم.

برای نمونه:

2.5 متر = 2.5 × 1 متر پایه
2.5 ÷ 0.01 = 250 سانتی‌متر

این روش باعث می‌شود به‌جای نوشتن فرمول جداگانه برای هر جفت واحد، فقط ضریب هر واحد نسبت به واحد پایه را ذخیره کنیم.

تعریف ضرایب تبدیل در دیکشنری

برای گروه‌های طول، وزن، حجم و سرعت از یک دیکشنری چندسطحی استفاده می‌کنیم:

UNIT_GROUPS = {
    "length": {
        "m": 1.0,
        "km": 1000.0,
        "cm": 0.01,
        "mm": 0.001,
        "in": 0.0254,
        "ft": 0.3048,
        "yd": 0.9144,
        "mi": 1609.344,
    },
    "weight": {
        "kg": 1.0,
        "g": 0.001,
        "mg": 0.000001,
        "lb": 0.45359237,
        "oz": 0.028349523125,
    },
    "volume": {
        "l": 1.0,
        "ml": 0.001,
        "m3": 1000.0,
        "cup": 0.2365882365,
        "gal": 3.785411784,
    },
    "speed": {
        "m/s": 1.0,
        "km/h": 1 / 3.6,
        "mph": 0.44704,
        "knot": 0.514444,
    },
}

در گروه طول، متر واحد پایه است. در وزن، کیلوگرم؛ در حجم، لیتر و در سرعت، متر بر ثانیه را به‌عنوان پایه در نظر گرفته‌ایم.

ساخت تابع تبدیل واحدهای خطی

گروه‌هایی مثل طول و وزن رابطه خطی دارند؛ یعنی کافی است مقدار را در ضریب واحد مبدأ ضرب و سپس بر ضریب واحد مقصد تقسیم کنیم.

def convert_linear(
    value,
    from_unit,
    to_unit,
    group,
):
    factors = UNIT_GROUPS[group]

    if (
        from_unit not in factors
        or to_unit not in factors
    ):
        raise ValueError(
            "واحد واردشده معتبر نیست."
        )

    base_value = (
        value * factors[from_unit]
    )

    return (
        base_value / factors[to_unit]
    )

برای مثال:

result = convert_linear(
    2.5,
    "m",
    "cm",
    "length",
)

print(result)

خروجی:

250.0

چرا دما را نمی‌توان با همین روش تبدیل کرد؟

تبدیل دما فقط ضرب و تقسیم نیست. صفر سلسیوس معادل ۳۲ فارنهایت است و صفر کلوین نیز نقطه دیگری دارد. بنابراین برای دما باید فرمول جداگانه بنویسیم.

تبدیل دما در پایتون

راه تمیز این است که ابتدا هر ورودی را به سلسیوس تبدیل کنیم و بعد از سلسیوس به واحد مقصد برویم.

def convert_temperature(
    value,
    from_unit,
    to_unit,
):
    if from_unit == to_unit:
        return value

    if from_unit == "c":
        celsius = value
    elif from_unit == "f":
        celsius = (
            value - 32
        ) * 5 / 9
    elif from_unit == "k":
        celsius = value - 273.15
    else:
        raise ValueError(
            "واحد دما معتبر نیست."
        )

    if to_unit == "c":
        return celsius

    if to_unit == "f":
        return (
            celsius * 9 / 5 + 32
        )

    if to_unit == "k":
        return celsius + 273.15

    raise ValueError(
        "واحد دما معتبر نیست."
    )

چند نمونه:

print(
    convert_temperature(
        0, "c", "f"
    )
)

print(
    convert_temperature(
        212, "f", "c"
    )
)

خروجی:

32.0
100.0

نمایش واحدهای قابل استفاده

برای اینکه کاربر مجبور نباشد واحدها را حدس بزند، قبل از دریافت ورودی فهرست واحدهای همان گروه را نمایش می‌دهیم:

def show_units(group):
    if group == "temperature":
        units = ("c", "f", "k")
    else:
        units = tuple(
            UNIT_GROUPS[group].keys()
        )

    print(
        "واحدهای قابل استفاده:"
    )
    print(
        ", ".join(units)
    )

دریافت مقدار عددی از کاربر

ورودی input() رشته است و ممکن است کاربر مقدار نامعتبر وارد کند. تابع زیر فقط زمانی پایان پیدا می‌کند که یک عدد معتبر دریافت شود:

def get_number(message):
    while True:
        value = input(message).strip()

        try:
            return float(value)
        except ValueError:
            print(
                "لطفاً یک عدد معتبر وارد کنید."
            )

استفاده از float باعث می‌شود اعداد اعشاری مثل ۲.۵ هم پذیرفته شوند.

ساخت منوی اصلی برنامه

برای ساده نگه داشتن رابط کاربری، پنج نوع تبدیل تعریف می‌کنیم:

CATEGORIES = {
    "1": ("طول", "length"),
    "2": ("وزن", "weight"),
    "3": ("حجم", "volume"),
    "4": ("سرعت", "speed"),
    "5": ("دما", "temperature"),
}

تابع انتخاب دسته:

def choose_category():
    while True:
        print("\nنوع تبدیل را انتخاب کنید:")

        for key, item in CATEGORIES.items():
            print(
                f"{key}) {item[0]}"
            )

        print("0) خروج")

        choice = input(
            "انتخاب شما: "
        ).strip()

        if choice == "0":
            return None

        if choice in CATEGORIES:
            return CATEGORIES[choice]

        print("گزینه نامعتبر است.")

تابع اجرای یک تبدیل

def run_conversion():
    category = choose_category()

    if category is None:
        return False

    category_name, group = category

    print(
        f"\nتبدیل واحدهای {category_name}"
    )

    show_units(group)

    from_unit = input(
        "واحد مبدأ: "
    ).strip().lower()

    to_unit = input(
        "واحد مقصد: "
    ).strip().lower()

    value = get_number(
        "مقدار: "
    )

    try:
        if group == "temperature":
            result = convert_temperature(
                value,
                from_unit,
                to_unit,
            )
        else:
            result = convert_linear(
                value,
                from_unit,
                to_unit,
                group,
            )
    except ValueError as error:
        print(f"خطا: {error}")
        return True

    print(
        f"\n{value:g} {from_unit} "
        f"= {result:.6g} {to_unit}"
    )

    return True

کد کامل برنامه تبدیل واحد با پایتون

UNIT_GROUPS = {
    "length": {
        "m": 1.0,
        "km": 1000.0,
        "cm": 0.01,
        "mm": 0.001,
        "in": 0.0254,
        "ft": 0.3048,
        "yd": 0.9144,
        "mi": 1609.344,
    },
    "weight": {
        "kg": 1.0,
        "g": 0.001,
        "mg": 0.000001,
        "lb": 0.45359237,
        "oz": 0.028349523125,
    },
    "volume": {
        "l": 1.0,
        "ml": 0.001,
        "m3": 1000.0,
        "cup": 0.2365882365,
        "gal": 3.785411784,
    },
    "speed": {
        "m/s": 1.0,
        "km/h": 1 / 3.6,
        "mph": 0.44704,
        "knot": 0.514444,
    },
}

CATEGORIES = {
    "1": ("طول", "length"),
    "2": ("وزن", "weight"),
    "3": ("حجم", "volume"),
    "4": ("سرعت", "speed"),
    "5": ("دما", "temperature"),
}


def convert_linear(
    value,
    from_unit,
    to_unit,
    group,
):
    factors = UNIT_GROUPS[group]

    if (
        from_unit not in factors
        or to_unit not in factors
    ):
        raise ValueError(
            "واحد واردشده معتبر نیست."
        )

    base_value = (
        value * factors[from_unit]
    )

    return (
        base_value / factors[to_unit]
    )


def convert_temperature(
    value,
    from_unit,
    to_unit,
):
    if from_unit == to_unit:
        return value

    if from_unit == "c":
        celsius = value
    elif from_unit == "f":
        celsius = (
            value - 32
        ) * 5 / 9
    elif from_unit == "k":
        celsius = value - 273.15
    else:
        raise ValueError(
            "واحد دما معتبر نیست."
        )

    if to_unit == "c":
        return celsius

    if to_unit == "f":
        return (
            celsius * 9 / 5 + 32
        )

    if to_unit == "k":
        return celsius + 273.15

    raise ValueError(
        "واحد دما معتبر نیست."
    )


def show_units(group):
    if group == "temperature":
        units = ("c", "f", "k")
    else:
        units = tuple(
            UNIT_GROUPS[group].keys()
        )

    print("واحدهای قابل استفاده:")
    print(", ".join(units))


def get_number(message):
    while True:
        value = input(message).strip()

        try:
            return float(value)
        except ValueError:
            print(
                "لطفاً یک عدد معتبر وارد کنید."
            )


def choose_category():
    while True:
        print("\nنوع تبدیل را انتخاب کنید:")

        for key, item in CATEGORIES.items():
            print(f"{key}) {item[0]}")

        print("0) خروج")

        choice = input(
            "انتخاب شما: "
        ).strip()

        if choice == "0":
            return None

        if choice in CATEGORIES:
            return CATEGORIES[choice]

        print("گزینه نامعتبر است.")


def run_conversion():
    category = choose_category()

    if category is None:
        return False

    category_name, group = category

    print(
        f"\nتبدیل واحدهای {category_name}"
    )

    show_units(group)

    from_unit = input(
        "واحد مبدأ: "
    ).strip().lower()

    to_unit = input(
        "واحد مقصد: "
    ).strip().lower()

    value = get_number("مقدار: ")

    try:
        if group == "temperature":
            result = convert_temperature(
                value,
                from_unit,
                to_unit,
            )
        else:
            result = convert_linear(
                value,
                from_unit,
                to_unit,
                group,
            )
    except ValueError as error:
        print(f"خطا: {error}")
        return True

    print(
        f"\n{value:g} {from_unit} "
        f"= {result:.6g} {to_unit}"
    )

    return True


def main():
    print(
        "=== برنامه تبدیل واحد با پایتون ==="
    )

    while run_conversion():
        pass

    print("برنامه پایان یافت.")


if __name__ == "__main__":
    main()

نمونه اجرای برنامه

=== برنامه تبدیل واحد با پایتون ===

نوع تبدیل را انتخاب کنید:
1) طول
2) وزن
3) حجم
4) سرعت
5) دما
0) خروج
انتخاب شما: 1

تبدیل واحدهای طول
واحدهای قابل استفاده:
m, km, cm, mm, in, ft, yd, mi
واحد مبدأ: m
واحد مقصد: cm
مقدار: 2.5

2.5 m = 250 cm

چند تست برای اطمینان از صحت تبدیل‌ها

قبل از توسعه پروژه بهتر است چند مقدار شناخته‌شده را تست کنید:

print(
    convert_linear(
        1, "mi", "km", "length"
    )
)

print(
    convert_linear(
        1, "kg", "g", "weight"
    )
)

print(
    convert_linear(
        36,
        "km/h",
        "m/s",
        "speed",
    )
)

print(
    convert_temperature(
        0, "c", "f"
    )
)

نتایج تقریبی باید به‌ترتیب برابر با ۱.۶۰۹۳۴۴، ۱۰۰۰، ۱۰ و ۳۲ باشند. منطق همین تبدیل‌ها قبل از انتشار این پروژه تست شده است.

اشتباه‌های رایج در پروژه تبدیل واحد

نوشتن فرمول برای هر جفت واحد

اگر برای متر به سانتی‌متر، متر به کیلومتر، کیلومتر به سانتی‌متر و همه حالت‌های دیگر شرط جدا بنویسید، تعداد شرط‌ها خیلی سریع زیاد می‌شود. استفاده از واحد پایه، کد را بسیار ساده‌تر می‌کند.

استفاده از یک فرمول عمومی برای دما

دما با طول و وزن تفاوت دارد. فرمول‌های سلسیوس، فارنهایت و کلوین Offset دارند و نمی‌توان فقط از یک ضریب ثابت استفاده کرد.

استفاده از int برای همه ورودی‌ها

تبدیل واحد معمولاً با اعداد اعشاری سروکار دارد؛ بنابراین float انتخاب مناسب‌تری برای مقدار ورودی است.

نادیده گرفتن واحد نامعتبر

اگر کاربر به‌جای cm مقدار دیگری وارد کند، برنامه باید پیام خطا بدهد، نه اینکه با KeyError متوقف شود. به همین دلیل قبل از دسترسی به دیکشنری، عضویت واحد بررسی می‌شود.

چطور پروژه را توسعه دهیم؟

  1. افزودن مساحت: متر مربع، سانتی‌متر مربع، فوت مربع و هکتار را اضافه کنید.
  2. افزودن زمان: ثانیه، دقیقه، ساعت و روز را پشتیبانی کنید.
  3. افزودن انرژی: ژول، کیلوژول و کالری را اضافه کنید.
  4. نام فارسی واحدها: کاربر بتواند «متر» یا «کیلومتر» را هم وارد کند.
  5. تاریخچه تبدیل‌ها: آخرین تبدیل‌ها را در یک List نگه دارید.
  6. ذخیره تاریخچه: نتایج را در فایل متنی یا JSON ذخیره کنید.
  7. نسخه GUI: همین منطق را با Tkinter به برنامه پنجره‌ای تبدیل کنید.
  8. نسخه وب: منطق تبدیل را در یک API یا برنامه وب کوچک استفاده کنید.

تمرین پیشنهادی

یک گروه جدید با نام time به UNIT_GROUPS اضافه کنید و واحدهای ثانیه، دقیقه، ساعت و روز را پشتیبانی کنید. سپس آن را بدون تغییر در تابع convert_linear() به منوی برنامه اضافه کنید. اگر طراحی برنامه درست باشد، برای اضافه کردن این گروه نیازی به بازنویسی منطق اصلی تبدیل نخواهید داشت.

این پروژه چه مفاهیمی را تمرین می‌دهد؟

  • دیکشنری‌های تو در تو
  • توابع و پارامترها
  • محاسبات اعشاری
  • شرط‌ها
  • حلقه while
  • دریافت ورودی با input
  • تبدیل رشته به float
  • مدیریت ValueError
  • ساخت منوی تعاملی
  • طراحی کد قابل توسعه
  • تفکیک منطق برنامه از رابط کاربری

جمع‌بندی

در این آموزش یک برنامه تبدیل واحد کامل با پایتون ساختیم که پنج گروه اصلی طول، وزن، حجم، سرعت و دما را پوشش می‌دهد. برای واحدهای خطی از یک مدل مبتنی بر ضریب و واحد پایه استفاده کردیم و دما را به‌دلیل تفاوت فرمول‌ها جداگانه مدیریت کردیم. همچنین ورودی کاربر، خطاهای احتمالی و اجرای چندباره برنامه را پوشش دادیم.

این پروژه نمونه خوبی از این است که چگونه یک مسئله ساده را با ساختار داده مناسب به برنامه‌ای قابل توسعه تبدیل کنیم. قبل از رفتن به پروژه بعدی، پیشنهاد می‌شود حداقل گروه «زمان» را به برنامه اضافه کنید تا مطمئن شوید معماری تبدیل‌ها را به‌درستی درک کرده‌اید.

📌 همچنین بخوانید: تمرین پایتون با جواب، ساخت بازی با پایتون و Pygame و ساخت ربات با پایتون

می‌خواهی پیشرفتت ذخیره شود؟با ورود یا ثبت‌نام رایگان، درس‌های تمام‌شده را علامت بزن و درصد پیشرفتت را در حساب کاربری ببین.ورود / ثبت‌نام برای ذخیره پیشرفت
درس بعدی · پروژه‌های پایتون (5 از 19)ساخت برنامه محاسبه سن با پایتون؛ محاسبه دقیق سال، ماه و روز با datetime ←
آموزش‌های تازه، کد آماده و رفع خطاهر هفته در کانال Dev Source؛ رایگان.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *