شرح assert في بايثون وAssertionError | أساسيات بايثون 33

شرح assert في بايثون وAssertionError للمبتدئين ضمن أساسيات بايثون 33

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

الفكرة المهمة للمبتدئ: assert ليست بديلًا عن if أو try/except للتحقق من إدخال المستخدم أو حماية البيانات. السبب أن تعليمات assert يمكن حذفها عند تشغيل بايثون بخيار التحسين -O.

في هذا الدرس من سلسلة أساسيات بايثون 33 سنشرح صيغة assert، وخطأ AssertionError، والرسالة الاختيارية، والفرق بينها وبين if وraise وtry/except، ومتى تستخدمها داخل الكود، ومتى يجب أن تستخدم تحققًا حقيقيًا يرفع استثناءً مناسبًا بدلًا منها.

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

الخلاصة السريعة: استخدم assert لاختبار افتراض داخلي أثناء التطوير. عند فشل الشرط تُرفع AssertionError، لكن لا تعتمد على assert للتحقق الذي يجب أن يعمل دائمًا؛ لأن تشغيل Python بخيار -O يزيل تعليمات assert. {alertInfo}

{getToc} $title={محتوى المقال}

ما معنى assert في بايثون؟

جملة assert تعني: افترض أن هذا التعبير صحيح. في التشغيل العادي، إذا كانت نتيجة التعبير True لا يحدث شيء ويستمر البرنامج، وإذا كانت False ترفع بايثون استثناء AssertionError.

الشكل الأساسي لاستخدام assert هو:

assert condition

حيث condition هو شرط يرجع True أو False.

تقنيًا، تعمل assert expression فقط عندما تكون القيمة المدمجة __debug__ مساوية لـTrue. وهذا هو الوضع الطبيعي عند تشغيل Python بدون خيار التحسين -O.

مثال بسيط:

age = 20

assert age >= 0

print("العمر صحيح")

في هذا المثال الشرط صحيح لأن age يساوي 20، ولذلك سيكمل البرنامج ويطبع:

العمر صحيح

كيف تعمل assert في بايثون عند تحقق الشرط أو فشله وظهور AssertionError

ماذا يحدث إذا فشل شرط assert؟

إذا كانت نتيجة الشرط بعد assert تساوي False، ترفع بايثون AssertionError. وإذا لم يلتقط الكود هذا الاستثناء، يتوقف التنفيذ ويظهر Traceback يوضح مكان فشل الشرط.

age = -5

assert age >= 0

print("العمر صحيح")

هنا الشرط age >= 0 غير صحيح، لأن العمر يساوي -5. لذلك سيظهر خطأ يشبه:

AssertionError

لن يصل البرنامج إلى سطر print() في هذا المثال؛ لأن AssertionError لم يتم التعامل معه. وإذا أردت فهم شكل الرسالة وأرقام الأسطر، راجع أساسيات بايثون 32: قراءة رسائل الخطأ وTraceback.

إضافة رسالة توضيحية مع assert

يمكنك إضافة رسالة اختيارية بعد الشرط. استخدمها عندما تساعد على شرح معنى الافتراض الذي فشل، لا لمجرد تكرار الشرط نفسه.

age = -5

assert age >= 0, "العمر لا يمكن أن يكون بالسالب"

print("العمر صحيح")

إذا فشل الشرط، سيظهر خطأ مع الرسالة:

AssertionError: العمر لا يمكن أن يكون بالسالب
نصيحة: رسالة assert ليست إلزامية. أضفها عندما توضح سبب الافتراض أو سياقه، بينما يعرض الـTraceback أصلًا السطر والتعبير الذي فشل. {alertSuccess}

مثال استخدام assert في بايثون مع رسالة توضيحية عند فشل الشرط

مثال تعليمي: assert داخل دالة

يمكن استخدام assert داخل دالة عندما تكون القيمة الإيجابية افتراضًا داخليًا يجب أن يضمنه الكود الذي يستدعي الدالة. المثال التالي تعليمي:

def square_positive(number):
    assert number > 0, "يجب أن يكون الرقم أكبر من صفر"
    return number * number

print(square_positive(5))

الناتج:

25

أما إذا استدعيت الدالة بقيمة غير مناسبة:

print(square_positive(-3))

سيظهر خطأ:

AssertionError: يجب أن يكون الرقم أكبر من صفر

إذا كانت هذه الدالة تستقبل بيانات من مستخدم أو API ويجب رفض القيمة السالبة دائمًا، فلا تعتمد على assert. استخدم مثلًا if number <= 0: raise ValueError(...) لأن هذا التحقق لا يختفي عند التشغيل بـ-O.

مثال عملي: اختبار نتيجة عملية حسابية

يمكن استخدام assert لاختبار أن دالة معينة تعطي النتيجة المتوقعة. مثلًا:

def add(a, b):
    return a + b

assert add(2, 3) == 5
assert add(10, 5) == 15

print("كل الاختبارات نجحت")

إذا كانت النتائج صحيحة، سيطبع البرنامج:

كل الاختبارات نجحت

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

هل assert بديل عن if؟

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

لا، assert ليست بديلًا مباشرًا عن if. صحيح أن الاثنين يستخدمان شروطًا، لكن الهدف مختلف.

المقارنة assert if
الهدف اختبار افتراض أثناء التطوير تنفيذ منطق برمجي حسب الشرط
ماذا يحدث عند فشل الشرط؟ يظهر AssertionError ينتقل البرنامج إلى else أو يتجاوز الكود
هل تصلح للتحقق من إدخال المستخدم؟ لا يفضل الاعتماد عليها نعم، هي الأنسب
الاستخدام الأفضل اختبار صحة افتراضات داخلية في الكود التحكم في مسار البرنامج

مثال باستخدام if للتحقق من إدخال المستخدم:

age = int(input("أدخل عمرك: "))

if age < 0:
    print("العمر غير صحيح")
else:
    print("العمر صحيح")

هنا if أفضل من assert، لأننا نتعامل مع إدخال مستخدم حقيقي، وليس مجرد اختبار داخلي أثناء التطوير.


الفرق بين assert و raise في بايثون

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

المقارنة assert raise
الهدف فحص افتراض داخلي أثناء التطوير والاختبار الإبلاغ عن خطأ أو قيمة غير صالحة أثناء التشغيل
نوع الاستثناء AssertionError فقط أي استثناء مناسب مثل ValueError أو TypeError
هل يعمل دائمًا؟ لا؛ يمكن حذف تعليماته عند تشغيل Python بخيار -O نعم؛ لا يختفي بسبب خيار -O
الاختيار المناسب شرط يجب ألا يفشل إذا كان منطق البرنامج صحيحًا مدخل أو قيمة أو حالة تشغيل غير صالحة يجب رفضها فعليًا

مثلًا، إذا كانت قيمة العمر قادمة من مستخدم ويجب رفض القيمة السالبة دائمًا، فاستخدم:

age = int(input("أدخل عمرك: "))

if age < 0:
    raise ValueError("العمر لا يمكن أن يكون بالسالب")

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

الفرق بين assert وif في بايثون ومتى تستخدم كل واحدة

متى أستخدم assert في بايثون؟

استخدم assert عندما تريد التأكد من افتراض داخلي أثناء كتابة الكود أو اختباره.

أمثلة مناسبة:

  • التأكد أن دالة معينة أعادت نتيجة متوقعة.
  • التأكد أن قيمة داخلية لا يجب أن تكون فارغة.
  • التأكد أن قائمة معينة تحتوي على عناصر قبل معالجتها.
  • اختبار دوال صغيرة أثناء التعلم.
  • اكتشاف الأخطاء المنطقية أثناء التطوير.

مثال:

items = ["apple", "banana"]

assert len(items) > 0, "القائمة لا يجب أن تكون فارغة"

print(items[0])

متى لا تستخدم assert؟

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

بدلًا من ذلك استخدم if أو try و except حسب الحالة.

مثال غير مناسب:

password = input("أدخل كلمة المرور: ")

assert password == "12345", "كلمة المرور خاطئة"

الأفضل:

password = input("أدخل كلمة المرور: ")

if password == "12345":
    print("تم تسجيل الدخول")
else:
    print("كلمة المرور خاطئة")
تنبيه مهم: لا تستخدم assert كوسيلة أمان أو تحقق أساسي من المستخدم. استخدمها غالبًا لاختبار افتراضات داخلية أثناء التطوير. {alertWarning}

ما هو AssertionError؟

AssertionError هو الخطأ الذي يظهر عندما يفشل شرط assert. بمعنى أن Python وصلت إلى سطر assert ووجدت أن الشرط غير صحيح.

مثال:

x = 10

assert x < 5, "x يجب أن يكون أقل من 5"

النتيجة:

AssertionError: x يجب أن يكون أقل من 5

هذا الخطأ يخبرك أن الافتراض الذي كتبته لم يكن صحيحًا.

هل يمكن تعطيل assert في بايثون؟

نعم. عند تشغيل Python بخيار التحسين -O تُزال تعليمات assert من الكود المولّد، وتصبح القيمة المدمجة __debug__ مساوية لـFalse. وينطبق حذف assertions أيضًا عند استخدام وضع التحسين الأعلى -OO، كما يمكن تفعيل التحسين عبر متغير البيئة PYTHONOPTIMIZE.

مثلًا، إذا كان ملفك باسم app.py فيمكن تشغيله هكذا:

python -O app.py

لهذا السبب لا تستخدم assert للتحقق من كلمة مرور أو صلاحية أو قيمة خارجية يجب فحصها دائمًا. استخدم if وارفع استثناء مناسبًا مثل ValueError عند الحاجة.

استخدام assert مع الدوال

يمكن أن تضع assert داخل دالة للتحقق من افتراض داخلي أثناء التطوير. لكن إذا كانت القيم معلمات عامة قد تأتي من مستخدم أو ملف أو API، فالتعامل الصحيح غالبًا هو تحقق صريح باستخدام if وraise.

def calculate_discount(price, discount):
    assert price > 0, "السعر يجب أن يكون أكبر من صفر"
    assert 0 <= discount <= 100, "نسبة الخصم يجب أن تكون بين 0 و 100"

    final_price = price - (price * discount / 100)
    return final_price

print(calculate_discount(100, 20))

الناتج:

80.0

هذا المثال مناسب لفهم آلية assert، لكنه ليس نموذجًا للتحقق من مدخلات خارجية. في كود إنتاجي يستقبل سعرًا وخصمًا من المستخدم، اجعل التحقق دائمًا باستخدام if وارفع ValueError عند القيم غير الصالحة.

assert مع القوائم

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

names = ["Ali", "Sara"]

assert len(names) > 0, "القائمة فارغة"

print(names[0])

إذا كانت القائمة فارغة:

names = []

assert len(names) > 0, "القائمة فارغة"

سيظهر:

AssertionError: القائمة فارغة

assert مع نوع البيانات

يمكنك أيضًا استخدام assert للتحقق من افتراض يتعلق بنوع قيمة داخلية. عادةً تكون isinstance() أوضح وأكثر مرونة من مقارنة type(value) == SomeType.

name = "Ali"

assert isinstance(name, str), "name يجب أن يكون نصًا"

print(name.upper())

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

خطأ شائع: لا تكتب assert كأنها دالة برسالة داخل الأقواس

assert جملة في Python وليست دالة. وضع الشرط وحده داخل أقواس للتجميع مثل assert (x > 0) لا يسبب مشكلة، لكن الخطأ الشائع هو كتابة الشرط والرسالة معًا داخل زوج واحد من الأقواس:

x = -1

assert (x > 0, "x يجب أن يكون موجبًا")

هذه الصيغة تنشئ tuple غير فارغة، والـtuple غير الفارغة تُعامل كقيمة صحيحة منطقيًا، لذلك قد لا يفشل assert كما تتوقع. اكتب الرسالة بعد فاصلة خارج هذا التجميع:

assert x > 0, "x يجب أن يكون موجبًا"
{alertWarning}القاعدة: الصيغة الصحيحة مع الرسالة هي assert condition, "message"، ولا تتعامل مع assert كأنها دالة تستقبل شرطًا ورسالة داخل الأقواس.

أخطاء شائعة عند استخدام assert

1. استخدام assert بدل if مع إدخال المستخدم

إذا كنت تتحقق من قيمة أدخلها المستخدم، استخدم if أو try except بدل الاعتماد على assert.

2. الاعتقاد أن رسالة assert إلزامية

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

assert age >= 0

الأفضل:

assert age >= 0, "العمر لا يمكن أن يكون بالسالب"

3. استخدام assert لأمور أمنية

لا تستخدم assert للتحقق من كلمات المرور أو الصلاحيات أو حماية أجزاء مهمة من التطبيق.

4. استخدام assert في تحقق يجب أن يعمل دائمًا

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


أخطاء استخدام assert في بايثون والتحقق من المستخدم والأمان

مقارنة سريعة: assert و if و try except

الأداة تستخدم متى؟ مثال استخدام
assert لاختبار افتراض داخلي أثناء التطوير التأكد أن نتيجة دالة تساوي المتوقع
if لاتخاذ قرار داخل البرنامج إذا كان العمر أقل من 18 اطبع رسالة
try except للتعامل مع أخطاء قد تحدث أثناء التشغيل محاولة تحويل نص إلى رقم والتعامل مع ValueError

إذا أردت مراجعة التعامل مع الأخطاء، يمكنك قراءة درس: شرح try و except في Python للمبتدئين.

إذا كان هدفك هو كتابة اختبارات تلقائية منظمة، فانتقل بعد هذا الدرس إلى صفحات unittest وpytest المرتبطة أعلاه بدل توسيع استخدام assert داخل منطق التطبيق.

روابط خارجية للتوسع

تمرين بسيط على assert

اكتب دالة تستقبل قائمة أرقام، ثم استخدم assert للتأكد أن القائمة ليست فارغة قبل حساب المتوسط.

ابدأ بهذا الكود:

def average(numbers):
    assert len(numbers) > 0, "لا يمكن حساب متوسط قائمة فارغة"
    return sum(numbers) / len(numbers)

print(average([10, 20, 30]))

الناتج:

20.0

ثم جرّب:

print(average([]))

ستلاحظ ظهور رسالة AssertionError مع الرسالة التي كتبتها.

الخلاصة

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

استخدم assert لاختبار افتراضات داخلية في الكود، مثل التأكد أن قيمة معينة منطقية أو أن نتيجة دالة تساوي المتوقع. لكن لا تستخدمها كبديل عن if في التحقق من إدخال المستخدم، ولا تعتمد عليها في الأمور الأمنية أو التحقق الأساسي في البرامج الحقيقية.

الخلاصة العملية: assert أداة ممتازة لاكتشاف الأخطاء أثناء التطوير، لكنها ليست بديلًا عن if أو try except في التعامل مع المستخدم والأخطاء الحقيقية. {alertSuccess}

أسئلة شائعة عن assert في بايثون

ما معنى assert في بايثون؟

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

متى أستخدم assert؟

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

هل assert بديل عن if؟

لا. if تستخدم لاتخاذ قرارات داخل البرنامج، أما assert فتستخدم غالبًا لاختبار افتراضات أثناء التطوير.

ما هو AssertionError؟

هو الخطأ الذي يظهر عندما يفشل شرط assert، أي عندما تكون نتيجة الشرط False.

هل أستخدم assert للتحقق من إدخال المستخدم؟

لا يفضل ذلك. الأفضل استخدام if أو try except للتحقق من إدخال المستخدم والتعامل مع الأخطاء بشكل واضح.

هل يمكن كتابة رسالة مع assert؟

نعم، يمكنك كتابة رسالة بعد الشرط باستخدام فاصلة، مثل: assert age >= 0, "العمر غير صحيح".

هل تعمل assert دائمًا؟

لا. عند تشغيل Python بخيار -O تُزال تعليمات assert. لذلك لا تستخدمها للتحقق الأمني أو مدخلات المستخدم أو أي شرط يجب تطبيقه دائمًا.

ما الفرق بين assert و raise؟

assert تفحص افتراضًا داخليًا وتنتج AssertionError ويمكن تعطيلها في وضع التحسين، بينما raise ترفع استثناءً تختاره مثل ValueError وتعمل دائمًا، لذلك هي الأنسب للتحقق الذي يجب تنفيذه أثناء التشغيل.

هل أكتب assert(condition, "message")؟

لا تكتب الشرط والرسالة كـtuple داخل الأقواس. الصيغة الصحيحة هي assert condition, "message". أما assert (condition) بشرط واحد فقط فمجرد تجميع للتعبير ولا يحمل مشكلة بحد ذاته.

إرسال تعليق

أحدث أقدم