كيفية إنشاء آلة حاسبة باستخدام بايثون

كيفية إنشاء آلة حاسبة باستخدام بايثون

إذا كنت تتعلم بايثون وتريد مشروعًا عمليًا يجمع بين الفهم، والتجريب، ومتعة رؤية النتيجة أمامك مباشرة، فمشروع إنشاء آلة حاسبة باستخدام بايثون من أفضل المشاريع التي يمكنك البدء بها. قد يبدو المشروع بسيطًا في البداية، لكن الحقيقة أنه يحمل داخله الكثير من المفاهيم المهمة: التعامل مع الإدخال من المستخدم، التحويل بين أنواع البيانات، استخدام الشروط، بناء الدوال، معالجة الأخطاء، ثم الانتقال لاحقًا إلى واجهة رسومية تجعل البرنامج أقرب إلى التطبيقات الحقيقية التي نستخدمها يوميًا.

والجميل في هذا المشروع أنه لا يعلّمك البرمجة فقط، بل يعلّمك أيضًا التفكير المنهجي. عندما تصنع آلة حاسبة، فأنت لا تكتب سطورًا عشوائية، بل تبني شيئًا له هدف واضح: استقبل رقمين أو أكثر، نفّذ عملية حسابية، ثم أظهر النتيجة بشكل صحيح ومفهوم. هذا النوع من المشاريع يرسّخ الأساسيات في ذهنك بطريقة أفضل بكثير من الحفظ النظري، لأنك تتعامل مع مشكلة حقيقية وتحلها خطوة خطوة.

في هذا المقال سنبني آلة حاسبة باستخدام بايثون من الصفر، وسنبدأ بنسخة بسيطة جدًا في سطر الأوامر، ثم نطوّرها تدريجيًا لتصبح أكثر احترافية، ونضيف إليها تحسينات مثل استخدام الدوال، ومعالجة الأخطاء، ودعم عمليات إضافية، ثم ننتهي بإنشاء واجهة رسومية باستخدام Tkinter. سأحاول أن أشرح كل جزء بروح بسيطة وواضحة، وكأننا نجلس معًا ونبني المشروع سطرًا سطرًا، لأن البرمجة في النهاية ليست سباقًا، بل رحلة فهم وتجريب.

لماذا آلة حاسبة مشروع ممتاز لتعلم بايثون؟

عندما يبدأ الشخص بتعلم بايثون، غالبًا يبحث عن مشروع لا يكون معقدًا جدًا ولا سطحيًا جدًا. آلة الحاسبة تقع في منطقة ممتازة بين الاثنين. فهي بسيطة بما يكفي لتبدأ بها بسرعة، وفي الوقت نفسه تسمح لك بأن تلمس الكثير من المفاهيم الأساسية. يمكنك مثلًا أن تبدأ بإصدار يقبل رقمين فقط ويحسب الجمع، ثم تضيف الطرح والضرب والقسمة، وبعد ذلك تدعم القسمة الصحيحة، والأسس، والجذر التربيعي، والنسبة المئوية، وربما العمليات المتسلسلة. ومع كل خطوة جديدة، ستشعر أنك لم تعد تكتب كودًا فقط، بل تبني أداة مفيدة فعلًا.

هناك سبب آخر يجعل هذا المشروع مهمًا: كل مطور تقريبًا يحتاج في مرحلة ما إلى كتابة برامج صغيرة تعتمد على الإدخال والحساب. سواء كنت تعمل في ويب، أو ذكاء اصطناعي، أو أتمتة، أو تطبيقات سطح المكتب، ستعود كثيرًا إلى هذه الأساسيات. لذلك، فإن الوقت الذي ستقضيه في بناء آلة حاسبة ليس وقتًا ضائعًا أبدًا، بل هو استثمار حقيقي في فهمك للغة بايثون وطريقة تفكيرها.

الفكرة العامة للمشروع

قبل أن نكتب أي كود، من الأفضل أن نرسم صورة ذهنية لما سنفعله. آلة الحاسبة البسيطة ستقوم بالخطوات التالية: تطلب من المستخدم إدخال رقم أول، ثم رقم ثانٍ، ثم يختار العملية الحسابية المطلوبة، وبعد ذلك تعرض النتيجة. هذه الفكرة البسيطة يمكن تنفيذها بعدة طرق. يمكننا كتابة برنامج يعمل في سطر الأوامر، ويمكننا أيضًا جعله برنامجًا بواجهة رسومية. ويمكننا لاحقًا أن نطوره ليصبح أكثر ذكاءً، مثل أن يقبل أكثر من رقم في نفس الوقت، أو أن يكرر العمليات حتى يخرج المستخدم، أو أن يتعامل مع الأخطاء بطريقة لطيفة بدل أن يتوقف فجأة.

في البداية سنبدأ بالطريقة الأسهل: آلة حاسبة نصية تعمل في الطرفية. هذا النوع من البرامج ممتاز جدًا للمبتدئين لأنه يزيل تعقيد الواجهة، ويجعلك تركز على المنطق نفسه. بعد أن تفهم الفكرة جيدًا، سننتقل إلى الواجهة الرسومية، وستلاحظ وقتها أن الأساس نفسه لم يتغير، وإنما تغيرت طريقة التفاعل فقط.

أول نسخة بسيطة جدًا

لنبدأ بأبسط شكل ممكن. هذه النسخة ستطلب من المستخدم رقمين وعملية حسابية، ثم تعطيه النتيجة.

num1 = float(input("أدخل الرقم الأول: "))
operator = input("أدخل العملية (+, -, *, /): ")
num2 = float(input("أدخل الرقم الثاني: "))

if operator == "+":
    result = num1 + num2
    print("النتيجة:", result)
elif operator == "-":
    result = num1 - num2
    print("النتيجة:", result)
elif operator == "*":
    result = num1 * num2
    print("النتيجة:", result)
elif operator == "/":
    if num2 != 0:
        result = num1 / num2
        print("النتيجة:", result)
    else:
        print("لا يمكن القسمة على صفر.")
else:
    print("العملية غير صحيحة.")

هذه النسخة صغيرة جدًا، لكنها تعلّمك أشياء مهمة للغاية. أولًا، نلاحظ أننا استخدمنا float() بدل int() حتى تسمح الآلة الحاسبة بالأرقام العشرية مثل 2.5 و 7.8. هذا القرار مهم لأن كثيرًا من العمليات الحسابية لا تكون أعدادًا صحيحة فقط. ثانيًا، استخدمنا الشروط if و elif و else لاختيار العملية المناسبة. ثالثًا، انتبهنا إلى حالة القسمة على صفر، وهي حالة لا يجوز تجاهلها لأن البرنامج سيتسبب في خطأ لو لم نعالجها.

ورغم أن هذا الكود يبدو بسيطًا، إلا أنه يمثل أساسًا جيدًا جدًا. كل ما سنفعله لاحقًا هو تحسين هذا الأساس وتوسيعه وتنظيمه.

تحسين الكود باستخدام الدوال

النسخة السابقة تعمل، لكنها ليست الأفضل من ناحية التنظيم. فبدل أن يكون كل شيء مكتوبًا في نفس المكان، من الأفضل أن نقسم البرنامج إلى دوال. الدوال تجعل الكود أوضح، وأسهل في الصيانة، وأسهل في التعديل لاحقًا. عندما تكبر المشاريع، يصبح التنظيم مهمًا جدًا، لأن الترتيب الجيد يوفر عليك كثيرًا من الوقت والتعب.

لنكتب نسخة أفضل:

def add(x, y):
    return x + y

def subtract(x, y):
    return x - y

def multiply(x, y):
    return x * y

def divide(x, y):
    if y == 0:
        return "لا يمكن القسمة على صفر"
    return x / y

print("اختر العملية:")
print("1. جمع")
print("2. طرح")
print("3. ضرب")
print("4. قسمة")

choice = input("أدخل رقم العملية (1/2/3/4): ")

num1 = float(input("أدخل الرقم الأول: "))
num2 = float(input("أدخل الرقم الثاني: "))

if choice == "1":
    print("النتيجة:", add(num1, num2))
elif choice == "2":
    print("النتيجة:", subtract(num1, num2))
elif choice == "3":
    print("النتيجة:", multiply(num1, num2))
elif choice == "4":
    print("النتيجة:", divide(num1, num2))
else:
    print("اختيار غير صحيح")

هنا أصبحت الفكرة أوضح. كل عملية حسابية لها دالتها الخاصة. وهذا يجعل الكود أكثر ترتيبًا وأسهل في التوسعة. مثلًا، إذا أردت لاحقًا إضافة عملية الأس، فلن تحتاج إلى إعادة كتابة البرنامج كله، بل ستضيف دالة جديدة وتربطها بالقائمة.

ومن الجميل في هذه الطريقة أنها تشبه طريقة التفكير الاحترافية في البرمجة. بدل أن تكتب كل شيء دفعة واحدة، تقوم بتقسيم المشكلة إلى أجزاء صغيرة، وكل جزء له مهمة محددة. هذا بالضبط ما يفعله المطورون في المشاريع الحقيقية.

جعل الآلة الحاسبة تعمل بشكل متكرر

في النسخ السابقة، ينفذ البرنامج عملية واحدة ثم ينتهي. وهذا جيد للتجربة الأولى، لكنه ليس مريحًا جدًا للمستخدم. من الطبيعي أن يرغب المستخدم في إجراء أكثر من عملية دون الحاجة إلى تشغيل البرنامج من جديد في كل مرة. لذلك سنجعل الآلة الحاسبة تعمل داخل حلقة تكرار، وتستمر حتى يختار المستخدم الخروج.

def add(x, y):
    return x + y

def subtract(x, y):
    return x - y

def multiply(x, y):
    return x * y

def divide(x, y):
    if y == 0:
        return "لا يمكن القسمة على صفر"
    return x / y

while True:
    print("\n=== آلة حاسبة بسيطة ===")
    print("1. جمع")
    print("2. طرح")
    print("3. ضرب")
    print("4. قسمة")
    print("5. خروج")

    choice = input("اختر عملية: ")

    if choice == "5":
        print("تم الخروج من البرنامج.")
        break

    if choice in ["1", "2", "3", "4"]:
        try:
            num1 = float(input("أدخل الرقم الأول: "))
            num2 = float(input("أدخل الرقم الثاني: "))
        except ValueError:
            print("الرجاء إدخال أرقام صحيحة فقط.")
            continue

        if choice == "1":
            print("النتيجة:", add(num1, num2))
        elif choice == "2":
            print("النتيجة:", subtract(num1, num2))
        elif choice == "3":
            print("النتيجة:", multiply(num1, num2))
        elif choice == "4":
            print("النتيجة:", divide(num1, num2))
    else:
        print("اختيار غير صحيح، حاول مرة أخرى.")

هذه النسخة أفضل بكثير، لأنها أقرب إلى تجربة حقيقية. كما أننا أضفنا هنا شيئًا مهمًا جدًا وهو try و except. لماذا؟ لأن المستخدم قد يكتب نصًا بدل رقم، مثل أن يكتب "abc" بالخطأ. في هذه الحالة سيحدث خطأ إذا حاولنا تحويل النص إلى float. بدل أن ينكسر البرنامج، نقوم بالتقاط الخطأ وإظهار رسالة لطيفة للمستخدم.

هذا النوع من التفكير مهم جدًا في البرمجة، لأن البرنامج الجيد ليس الذي يعمل في الظروف المثالية فقط، بل الذي يتعامل مع الأخطاء بطريقة محترمة وواضحة.

دعم عمليات إضافية

الآلة الحاسبة الحقيقية لا تقتصر على الجمع والطرح والضرب والقسمة. لذلك يمكننا توسيع البرنامج ليشمل عمليات أخرى مثل:

  • الأس x ** y

  • الجذر التربيعي

  • النسبة المئوية

  • القسمة الصحيحة //

  • باقي القسمة %

سنضيف الآن بعض هذه العمليات لنزيد قوة البرنامج.

import math

def add(x, y):
    return x + y

def subtract(x, y):
    return x - y

def multiply(x, y):
    return x * y

def divide(x, y):
    if y == 0:
        return "لا يمكن القسمة على صفر"
    return x / y

def power(x, y):
    return x ** y

def integer_division(x, y):
    if y == 0:
        return "لا يمكن القسمة على صفر"
    return x // y

def modulus(x, y):
    if y == 0:
        return "لا يمكن القسمة على صفر"
    return x % y

def square_root(x):
    if x < 0:
        return "لا يمكن حساب الجذر التربيعي لعدد سالب"
    return math.sqrt(x)

while True:
    print("\n=== آلة حاسبة متقدمة ===")
    print("1. جمع")
    print("2. طرح")
    print("3. ضرب")
    print("4. قسمة")
    print("5. أس")
    print("6. قسمة صحيحة")
    print("7. باقي القسمة")
    print("8. جذر تربيعي")
    print("9. خروج")

    choice = input("اختر عملية: ")

    if choice == "9":
        print("وداعًا!")
        break

    try:
        if choice == "8":
            num = float(input("أدخل الرقم: "))
            print("النتيجة:", square_root(num))
        elif choice in ["1", "2", "3", "4", "5", "6", "7"]:
            num1 = float(input("أدخل الرقم الأول: "))
            num2 = float(input("أدخل الرقم الثاني: "))

            if choice == "1":
                print("النتيجة:", add(num1, num2))
            elif choice == "2":
                print("النتيجة:", subtract(num1, num2))
            elif choice == "3":
                print("النتيجة:", multiply(num1, num2))
            elif choice == "4":
                print("النتيجة:", divide(num1, num2))
            elif choice == "5":
                print("النتيجة:", power(num1, num2))
            elif choice == "6":
                print("النتيجة:", integer_division(num1, num2))
            elif choice == "7":
                print("النتيجة:", modulus(num1, num2))
        else:
            print("اختيار غير صحيح")
    except ValueError:
        print("الرجاء إدخال قيمة رقمية صحيحة.")

الآن بدأ البرنامج يأخذ شكلًا أكثر نضجًا. لم نعد نتعامل مع العمليات الأساسية فقط، بل أصبحنا نغطي حالات أكثر. كما أن إضافة الجذر التربيعي قدمت لنا فرصة للتعامل مع مكتبة math، وهي مكتبة مفيدة جدًا في المشاريع الحسابية.

لاحظ أيضًا أننا منعنا الجذر التربيعي للعدد السالب، لأن الناتج في هذا السياق لن يكون عددًا حقيقيًا بسيطًا. هذه التفاصيل الصغيرة هي التي تصنع فرقًا بين برنامج عادي وبرنامج مهذب ومحترم مع المستخدم.

لماذا استخدمنا float بدل int؟

هذا سؤال مهم جدًا. كثير من المبتدئين يستخدمون int في البداية لأنهم يفكرون في الأعداد الصحيحة فقط. لكن الحقيقة أن الآلة الحاسبة يجب أن تكون مرنة. عندما يكتب المستخدم 3.5 أو 12.75، ينبغي أن يتعامل البرنامج مع هذه القيم دون مشكلة. لذلك استخدمنا float لأنه يسمح بالقيم العشرية.

لكن هناك ملاحظة مهمة هنا: float قد يتسبب أحيانًا في تمثيل غير دقيق للغاية لبعض الأعداد بسبب طبيعة التخزين الداخلي للأرقام العشرية في الحواسيب. قد ترى مثلًا نتيجة تبدو غريبة قليلًا مثل 0.30000000000000004 بدل 0.3. هذا ليس خطأ في البرنامج، بل هو سلوك معروف في الأعداد العشرية العائمة. وإذا كنت تريد دقة مالية أعلى، يمكنك استخدام مكتبة decimal بدل float.

مثال بسيط:

from decimal import Decimal

num1 = Decimal("0.1")
num2 = Decimal("0.2")
print(num1 + num2)

هذه الطريقة أفضل في الحسابات المالية أو الحالات التي تحتاج دقة عالية جدًا. أما في آلة حاسبة تعليمية، فـfloat غالبًا يكفي.

جعل البرنامج أكثر أناقة

البرامج الجيدة لا تكون فقط صحيحة، بل تكون أيضًا مرتبة وسهلة القراءة. يمكننا تحسين عرض النصوص، وتنظيم القائمة، وإضافة رسائل أوضح، بحيث يشعر المستخدم بأن البرنامج مكتوب بعناية وليس مجرد تجربة سريعة.

def show_menu():
    print("\n" + "=" * 30)
    print("      آلة حاسبة بايثون")
    print("=" * 30)
    print("1) جمع")
    print("2) طرح")
    print("3) ضرب")
    print("4) قسمة")
    print("5) أس")
    print("6) جذر تربيعي")
    print("7) خروج")
    print("=" * 30)

def get_number(prompt):
    while True:
        try:
            return float(input(prompt))
        except ValueError:
            print("الرجاء إدخال رقم صحيح.")

while True:
    show_menu()
    choice = input("اختر عملية: ")

    if choice == "7":
        print("تم إغلاق الآلة الحاسبة. إلى اللقاء!")
        break

    if choice == "6":
        num = get_number("أدخل الرقم: ")
        if num < 0:
            print("لا يمكن حساب الجذر التربيعي لعدد سالب.")
        else:
            print("النتيجة:", math.sqrt(num))
    elif choice in ["1", "2", "3", "4", "5"]:
        num1 = get_number("أدخل الرقم الأول: ")
        num2 = get_number("أدخل الرقم الثاني: ")

        if choice == "1":
            print("النتيجة:", num1 + num2)
        elif choice == "2":
            print("النتيجة:", num1 - num2)
        elif choice == "3":
            print("النتيجة:", num1 * num2)
        elif choice == "4":
            if num2 == 0:
                print("لا يمكن القسمة على صفر.")
            else:
                print("النتيجة:", num1 / num2)
        elif choice == "5":
            print("النتيجة:", num1 ** num2)
    else:
        print("خيار غير صالح، حاول مرة أخرى.")

في هذه النسخة قمنا بعمل شيء مفيد جدًا وهو إنشاء دالة get_number()، وهذه الدالة لا تسمح بمرور قيمة غير صحيحة. بدل أن نكرر الكود الخاص بالتقاط الخطأ في كل مرة، نقلناه إلى دالة واحدة. هذا الأسلوب ممتاز جدًا لأنك تقلل التكرار وتزيد من وضوح البرنامج.

وهنا تظهر إحدى أجمل قواعد البرمجة: لا تكرر نفسك. عندما تجد نفسك تكتب نفس السطور مرارًا، اسأل نفسك: هل يمكن وضعها داخل دالة؟ غالبًا نعم.

بناء الآلة الحاسبة بطريقة أكثر احترافية باستخدام كائنات

إذا أردت أن تأخذ المشروع خطوة إضافية، يمكنك بناؤه باستخدام البرمجة كائنية التوجه OOP. قد لا تحتاجها في نسخة بسيطة، لكن تعلمها هنا مفيد جدًا، لأنها تريك كيف يمكن تنظيم المشروع داخل كلاس واحد يجمع العمليات معًا.

import math

class Calculator:
    def add(self, x, y):
        return x + y

    def subtract(self, x, y):
        return x - y

    def multiply(self, x, y):
        return x * y

    def divide(self, x, y):
        if y == 0:
            return "لا يمكن القسمة على صفر"
        return x / y

    def power(self, x, y):
        return x ** y

    def square_root(self, x):
        if x < 0:
            return "لا يمكن حساب الجذر التربيعي لعدد سالب"
        return math.sqrt(x)

calc = Calculator()

print(calc.add(10, 5))
print(calc.divide(20, 4))
print(calc.square_root(16))

قد يبدو هذا الشكل أطول قليلًا، لكنه ممتاز عندما يكبر المشروع. بدل أن تكون العمليات مبعثرة، كلها أصبحت داخل كلاس واحد اسمه Calculator. هذا يعطيك بنية منظمة جدًا، ويجعل التوسع في المستقبل أسهل. على سبيل المثال، يمكنك لاحقًا إضافة سجل للعمليات، أو حفظ آخر نتيجة، أو توسيع الكلاس ليشمل خصائص أخرى.

إضافة سجل للعمليات

من الأشياء اللطيفة التي يمكن إضافتها إلى آلة الحاسبة هو الاحتفاظ بسجل العمليات السابقة. هذا يجعل البرنامج أكثر فائدة، ويساعد المستخدم على مراجعة ما فعله. يمكننا تخزين كل عملية في قائمة.

history = []

def save_history(expression, result):
    history.append(f"{expression} = {result}")

def show_history():
    if not history:
        print("لا يوجد سجل بعد.")
    else:
        print("\nسجل العمليات:")
        for item in history:
            print(item)

while True:
    print("\n1. جمع")
    print("2. عرض السجل")
    print("3. خروج")

    choice = input("اختر: ")

    if choice == "1":
        try:
            a = float(input("الرقم الأول: "))
            b = float(input("الرقم الثاني: "))
            result = a + b
            print("النتيجة:", result)
            save_history(f"{a} + {b}", result)
        except ValueError:
            print("إدخال غير صحيح.")
    elif choice == "2":
        show_history()
    elif choice == "3":
        break
    else:
        print("خيار غير صحيح.")

ميزة السجل أنه يضيف لمسة عملية جميلة. يشعر المستخدم أن البرنامج “يتذكر” ما قام به، وهذا يرفع من جودة التجربة.

تحويل الآلة الحاسبة إلى واجهة رسومية باستخدام Tkinter

الآن وصلنا إلى الجزء الذي يحبه كثير من الناس، وهو الواجهة الرسومية. حتى لو كانت آلة الحاسبة النصية كافية من ناحية المنطق، فإن الواجهة الرسومية تجعل المشروع يبدو أكثر واقعية وأقرب إلى التطبيقات التي نستخدمها على الكمبيوتر.

في بايثون توجد مكتبة ممتازة مدمجة اسمها Tkinter، وهي مناسبة جدًا لإنشاء واجهات رسومية بسيطة وسريعة. لننشئ آلة حاسبة بواجهة فيها أزرار وشاشة عرض.

import tkinter as tk
from tkinter import messagebox
import math

class CalculatorApp:
    def __init__(self, root):
        self.root = root
        self.root.title("آلة حاسبة بايثون")
        self.root.geometry("350x500")
        self.root.resizable(False, False)

        self.expression = ""
        self.input_text = tk.StringVar()

        input_frame = tk.Frame(self.root, bd=10, relief=tk.RIDGE)
        input_frame.pack(side=tk.TOP)

        input_field = tk.Entry(input_frame, font=("Arial", 20), textvariable=self.input_text, justify=tk.RIGHT, bd=10, width=17)
        input_field.grid(row=0, column=0)
        input_field.pack(ipady=10)

        buttons_frame = tk.Frame(self.root)
        buttons_frame.pack()

        buttons = [
            ("7", 1, 0), ("8", 1, 1), ("9", 1, 2), ("/", 1, 3),
            ("4", 2, 0), ("5", 2, 1), ("6", 2, 2), ("*", 2, 3),
            ("1", 3, 0), ("2", 3, 1), ("3", 3, 2), ("-", 3, 3),
            ("0", 4, 0), (".", 4, 1), ("=", 4, 2), ("+", 4, 3),
            ("C", 5, 0), ("(", 5, 1), (")", 5, 2), ("√", 5, 3),
        ]

        for (text, row, col) in buttons:
            button = tk.Button(
                buttons_frame,
                text=text,
                font=("Arial", 18),
                width=5,
                height=2,
                command=lambda t=text: self.click(t)
            )
            button.grid(row=row, column=col, padx=5, pady=5)

    def click(self, item):
        if item == "C":
            self.expression = ""
            self.input_text.set("")
        elif item == "=":
            try:
                result = eval(self.expression)
                self.input_text.set(result)
                self.expression = str(result)
            except Exception:
                messagebox.showerror("خطأ", "تعبير غير صالح")
                self.expression = ""
                self.input_text.set("")
        elif item == "√":
            try:
                value = float(self.expression)
                if value < 0:
                    raise ValueError("Negative")
                result = math.sqrt(value)
                self.input_text.set(result)
                self.expression = str(result)
            except Exception:
                messagebox.showerror("خطأ", "لا يمكن حساب الجذر")
                self.expression = ""
                self.input_text.set("")
        else:
            self.expression += str(item)
            self.input_text.set(self.expression)

root = tk.Tk()
app = CalculatorApp(root)
root.mainloop()

هذه النسخة ممتعة جدًا لأنها تنقلنا من البرمجة النصية إلى البرمجة التفاعلية. ستظهر نافذة حقيقية فيها أزرار، ويمكنك كتابة العمليات بشكل قريب من الطريقة المعتادة في الآلات الحاسبة. وعندما تضغط على = يتم حساب التعبير.

لكن هنا يجب أن ننتبه إلى أمر مهم جدًا: استخدمنا eval()، وهي دالة قوية لكنها تحتاج حذرًا. eval() تقوم بتنفيذ النص كأنه كود بايثون، ولذلك لا ينبغي استخدامها مع إدخال غير موثوق من المستخدم في التطبيقات الحقيقية. في مشروع تعليمي بسيط، قد تكون مقبولة للتجربة، لكن الأفضل في التطبيقات الجادة أن نستعمل طريقة أكثر أمانًا لتحليل التعبير الحسابي.

لماذا eval() تحتاج حذرًا؟

eval() سهلة جدًا وتوفر علينا وقتًا كثيرًا، لأنها تسمح للبرنامج بتنفيذ التعبير مباشرة. لكنها خطيرة إذا استُخدمت بشكل غير صحيح، لأن المستخدم قد يدخل نصًا لا نريده. لهذا، في البرامج الاحترافية، من الأفضل بناء محلل حسابي خاص أو استخدام مكتبات آمنة للتعامل مع التعبيرات الرياضية.

ومع ذلك، بما أننا نتحدث هنا عن مشروع تعليمي، فـeval() مفيدة جدًا لفهم الفكرة بسرعة. المهم أن تعرف أنها ليست الحل المثالي دائمًا، وأن استخدامها ينبغي أن يكون واعيًا ومحدودًا.

نسخة أكثر أمانًا للواجهة الرسومية

يمكننا أن نحسّن الواجهة السابقة قليلًا ونمنع بعض المشاكل، مثل السماح فقط بعناصر محددة داخل التعبير. لكن بما أن المقال تعليمي، سنكتفي هنا بالفكرة العامة ونضيف تحسينًا بسيطًا: التحكم في التعبير بحيث لا يحدث توقف مفاجئ. يمكن أيضًا التقاط استثناءات مختلفة بشكل أوضح.

def calculate_expression(expression):
    try:
        return eval(expression)
    except ZeroDivisionError:
        return "لا يمكن القسمة على صفر"
    except SyntaxError:
        return "صيغة غير صحيحة"
    except Exception:
        return "حدث خطأ غير متوقع"

ثم داخل الواجهة نستدعي هذه الدالة بدل eval() مباشرة. هذا لا يجعلها آمنة تمامًا، لكنه يجعلها أوضح في التعامل مع الأخطاء.

إضافة أزرار علمية

إذا أردت أن تجعل الآلة الحاسبة أقوى، يمكنك إضافة بعض الدوال العلمية مثل:

  • sin

  • cos

  • tan

  • log

  • exp

ويمكن تنفيذها عبر مكتبة math. مثال:

import math

def scientific_calculator():
    print("1. sin")
    print("2. cos")
    print("3. tan")
    print("4. log")

    choice = input("اختر دالة: ")
    num = float(input("أدخل الرقم: "))

    if choice == "1":
        print(math.sin(num))
    elif choice == "2":
        print(math.cos(num))
    elif choice == "3":
        print(math.tan(num))
    elif choice == "4":
        if num > 0:
            print(math.log(num))
        else:
            print("اللوغاريتم يتطلب عددًا أكبر من صفر")
    else:
        print("اختيار غير صحيح")

هذه الإضافات تقرب البرنامج من الآلات الحاسبة العلمية التي نعرفها. وبالمناسبة، إذا كنت تتعلم البرمجة، فدمج الرياضيات مع البرمجة مفيد جدًا، لأنه يجعلك تفهم كيف يمكن للأفكار المجردة أن تتحول إلى أدوات عملية.

جعل البرنامج يتعامل مع الأخطاء بشكل احترافي

من أكثر الأشياء التي تميز البرنامج الجيد هو تعامله مع الأخطاء. في البرمجة الواقعية، لا تتوقع أن يدخل المستخدم كل شيء بشكل صحيح. قد يكتب نصًا بدل رقم، أو ينسى إدخال قيمة، أو يحاول القسمة على صفر، أو يكتب تعبيرًا غير صالح. لذلك من المهم جدًا أن نضيف طبقة حماية داخل البرنامج.

def safe_float_input(prompt):
    while True:
        value = input(prompt)
        try:
            return float(value)
        except ValueError:
            print("الرجاء إدخال رقم صحيح.")

def safe_divide(x, y):
    if y == 0:
        return None
    return x / y

بهذه الطريقة، بدل أن ينهار البرنامج، سيستمر في العمل ويطلب من المستخدم إدخالًا صحيحًا. وهذا مهم جدًا لأن المستخدم لا يحب البرنامج الذي يتوقف فجأة. المستخدم يحب البرنامج الذي يرشده بلطف.

مثال كامل لآلة حاسبة نصية متقدمة

الآن، بعد أن فهمنا أجزاء كثيرة، من المفيد جدًا أن نرى مثالًا أكثر اكتمالًا يجمع ما تعلمناه. هذه النسخة تعتمد على الدوال، والحلقات، ومعالجة الأخطاء، وتدعم أكثر من عملية.

import math

def add(x, y):
    return x + y

def subtract(x, y):
    return x - y

def multiply(x, y):
    return x * y

def divide(x, y):
    if y == 0:
        return "لا يمكن القسمة على صفر"
    return x / y

def power(x, y):
    return x ** y

def sqrt(x):
    if x < 0:
        return "لا يمكن حساب الجذر التربيعي لعدد سالب"
    return math.sqrt(x)

def get_number(prompt):
    while True:
        try:
            return float(input(prompt))
        except ValueError:
            print("الرجاء إدخال رقم صحيح.")

while True:
    print("\n==============================")
    print("        آلة حاسبة Python")
    print("==============================")
    print("1) جمع")
    print("2) طرح")
    print("3) ضرب")
    print("4) قسمة")
    print("5) أس")
    print("6) جذر تربيعي")
    print("7) خروج")
    print("==============================")

    choice = input("اختر العملية: ")

    if choice == "7":
        print("شكرًا لاستخدامك البرنامج.")
        break

    if choice in ["1", "2", "3", "4", "5"]:
        num1 = get_number("أدخل الرقم الأول: ")
        num2 = get_number("أدخل الرقم الثاني: ")

        if choice == "1":
            result = add(num1, num2)
        elif choice == "2":
            result = subtract(num1, num2)
        elif choice == "3":
            result = multiply(num1, num2)
        elif choice == "4":
            result = divide(num1, num2)
        elif choice == "5":
            result = power(num1, num2)

        print("النتيجة:", result)

    elif choice == "6":
        num = get_number("أدخل الرقم: ")
        print("النتيجة:", sqrt(num))

    else:
        print("خيار غير صحيح، حاول مرة أخرى.")

هذه النسخة مناسبة جدًا كنقطة تعليمية قوية. يمكنك فهمها بسهولة، ومع ذلك فهي تحتوي على عدة عناصر مهمة: تنظيم جيد، تكرار أقل، دعم للعمليات الأساسية والمتقدمة، وتحكم في الأخطاء.

كيف تطور المشروع بنفسك؟

أجمل شيء في المشاريع الصغيرة هو أنها لا تنتهي عند الكود الأول. دائمًا يمكنك تطويرها. يمكنك مثلًا أن تضيف:

  • دعم العمليات المتسلسلة مثل: 2 + 3 * 4

  • حفظ السجل في ملف نصي

  • واجهة رسومية أجمل

  • دعم الألوان والأزرار الكبيرة

  • زر لحذف آخر رقم

  • زر لمسح الحقل بالكامل

  • دعم اختصارات لوحة المفاتيح

  • دعم العمليات العلمية الكاملة

  • تحويل المشروع إلى تطبيق مكتبي مستقل

كل إضافة من هذه الإضافات ستجعلك تتعلم شيئًا جديدًا. وهذا هو سر المشاريع الناجحة في التعلم: لا تنظر إليها على أنها نهاية، بل على أنها بداية لتعلم أوسع.

نصائح مهمة أثناء بناء الآلة الحاسبة

حين تبني مشروعًا مثل هذا، حاول ألا تكتفي بنسخ الكود فقط. الأفضل أن تقرأ كل سطر وتسأل نفسك: لماذا كتب بهذه الطريقة؟ ماذا يحدث لو تغير الإدخال؟ لماذا استخدمنا try هنا؟ لماذا فصلنا العمليات في دوال؟ هذا النوع من الأسئلة هو الذي ينقلك من مجرد “كاتب كود” إلى “مطور يفهم ما يكتب”.

وحاول أيضًا أن تجرب بنفسك. عدّل الأسماء، أضف عملية جديدة، غيّر شكل القائمة، وجرّب أن تجعل البرنامج يعمل بطريقة مختلفة. كل تجربة صغيرة ستبني عندك حسًا برمجيًا أقوى. لا تخف من الخطأ، لأن الخطأ في البرمجة ليس مشكلة، بل هو جزء طبيعي جدًا من عملية التعلم.

الخلاصة

إن إنشاء آلة حاسبة باستخدام بايثون مشروع ممتاز لكل من يريد دخول عالم البرمجة بطريقة عملية وممتعة. بدأنا بنسخة بسيطة جدًا تعمل في الطرفية، ثم حسّناها باستخدام الدوال، ثم أضفنا معالجة للأخطاء، ثم دعمنا عمليات إضافية مثل الأس والجذر التربيعي، وبعد ذلك انتقلنا إلى الواجهة الرسومية باستخدام Tkinter. وفي كل مرحلة كنا نبني على ما سبق، بدل أن نبدأ من الصفر في كل مرة.

هذا هو جمال بايثون بالفعل: لغة واضحة، مرنة، وقادرة على تحويل الأفكار الصغيرة إلى مشاريع حقيقية في وقت قصير. وإذا كنت ما زلت في بداية الطريق، فمشروع الآلة الحاسبة ليس مجرد تمرين بسيط، بل هو خطوة ممتازة ستجعلك تفهم أساسيات كثيرة وتكسب ثقة كبيرة في نفسك. وربما بعد أن تنتهي من هذا المشروع، ستشعر لأول مرة أن البرمجة ليست شيئًا معقدًا كما كنت تتخيل، بل شيء يمكن أن تستمتع به فعلًا.

كلمات أخيرة

لا تنظر إلى الآلة الحاسبة على أنها مشروع صغير لا يستحق الوقت. أحيانًا تكون المشاريع الصغيرة هي التي تفتح لك الباب نحو فهم كبير. ابدأ بنسخة بسيطة، ثم حسّنها، ثم أضف لمستك الخاصة. ومع كل تعديل ستشعر أن البرنامج صار أقرب إليك، وصرت أنت أقرب إلى فهم البرمجة نفسها.

ولأن البرمجة تتعلم بالتدريب لا بالمشاهدة فقط، فإن أفضل خطوة تالية بعد قراءة هذا المقال هي أن تفتح محرر الكود لديك وتكتب النسخة الأولى بيدك، ثم تعدلها مرة بعد مرة حتى تشعر أنها أصبحت من صنعك فعلًا. هنا يبدأ التعلم الحقيقي، وهنا تصبح الفكرة مهارة.

#كيفية إنشاء آلة حاسبة باستخدام بايثون #Python calculator tutorial #تعلم بايثون للمبتدئين #مشروع بايثون بسيط #إنشاء آلة حاسبة Python #برمجة آلة حاسبة #Python GUI calculator Tkinter