ابحث في المدونة

الخميس، 14 مايو 2020

الطريقة الصحيحة لاستخدام مدخلات المستخدم داخل العمليات الحسابية في بايثون

بسم الله الرحمن الرحيم.
الإخوة الكرام السلام عليكم ورحمة الله وبركاته.
أهلًا وسهلًا ومرحبًا بكم في مشاركتنا البسيطة هذه التي سنتعرف فيها على طريقة سهلة وميسرة للتحقق من مدخلات البرنامج إن كانت على هيئة أرقام أم حروف.
من المعروف أنه في بايثون يتم استخدام دالة input للتحصل على بيانات معينة من المستخدم.
تستقبل بايثون هذه البيانات بصيغة السلاسل النصية strings حتى وإن أدخل المستخدم أرقامًا.
وبطبيعة الحال, لا يمكن استخدام هذا المدخل في إجراء العمليات الحسابية.
هناك حل معروف لدى أوساط المتعلمين ألا وهو استخدام دالة int لتحويل المدخل إلى integer
ولا أقول أن هذه الطريقة ليست صحيحة بل على العكس تمامًا.
لكني أقول أن هذه الطريقة يشوبها شيء من الخطأ وتنطوي على بعض الثغرات.
من ذلك أنه لو قام المستخدم تعسفًا بإدخال حرف في حين أنك طلبت منه إدخال رقم, فستفشل عملية التحويل ويتوقف برنامجك عن العمل على الفور.
بالإضافة إلى ذلك, لو أدخل المستخدم أرقامًا ذات فواصل عشرية فسيحدث نفس الأمر تمامًا.
والأكيد أنك لا تريد لبرنامجك أن يحظى بسمعة سيئة وأن يُعلم عنه أنه كثير التوقف لأسباب قد يراها المستخدم غير منطقية.

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

سنقوم أولًا بتعريف الدالة ونجعلها تستقبل قيمة نصية كمعامل لها, وسنسميها isnumber

def isnumber(x):
نحن الآن سنحتاج إلى تجربة تحويل النص الذي تم تعويضه عن x إلى رقم وبالصيغتين integer و float , وسنستثني الخطأ الذي يحصل عادة لو فشلت عملية التحويل.
المفهوم المستخدم لاستثناء الأخطاء في بايثون هو try and except
إذًا فسنقول
    try:
        if isinstance(float(x),float) == True or isinstance(int(x),int):
            return True

نتوقف قليلًا لشرح الكود الذي كتبناه
في بايثون هناك دالة مدمجة اسمها isinstance تستقبل معاملين.
تعمل هذه الدالة على التحقق مما إذا كانت القيمة المعوضة في المعامل الأول تمثل النوع المكتوب في المعامل الثاني
مثال:
لو كتبنا isinstance("this is a text",str) فإن هذه الدالة سترجع True إذا كان المعامل الأول نوعه str 
ما فعلنا نحن داخل جملة try وفي الجملة الشرطية أننا سألنا البرنامج ما إذا كان float(x) نوعها float أو أن int(x) تمثل النوع integer 
فإذا تحقق إحدى الأمرين قمنا بجعل الدالة ترجع True

فعليًا , لو استخدمنا الدالة بهذه الطريقة دون إدراجها تحت سيطرة الجملة try وكان النص المعوض عن x ليس رقمًا فسيعطينا مفسر بايثون ValueError لأنه لم يستطع تحويل قيمة x إلى أي من صيغ الأرقام الموجودة سواء int أو float .
إذًا فوظيفة try هنا هي محاولة تنفيذ الدالة.
بقي الآن أن نضع استثناء الخطأ الذي قد يحصل في هذه المحاولة باستخدام جواب try وهو except
لكن قبل ذلك ينبغي التعرف على اسم الخطأ المحتمل بغرض استثناؤه
الحقيقة, نوع الخطأ هو ValueError , وقد تعرفنا عليه بالطريقة التالية:
قمت باستخدام الدالة int وعوضت بداخلها عن نص عشوائي مع علمي بأنه ليس رقم
لقد كتبت هذا الكود في المفسر:
int("this is a text")
ظهرت لي النتيجة التالية:

Traceback (most recent call last):
  File "<console>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'this is a text'

انتقلت مباشرة إلى الكلمة الأولى من السطر الأخير, وعلمت أن اسم الخطأ هو فعلًا ValueError

إذًا سأكمل بناء الدالة وأكتب التالي:

    except ValueError:
        return False

جميل جدًا, لقد استثنيت الخطأ المحتمل , وحددت أن العملية التي ستقوم الدالة بتنفيذها عند وقوعه هو إرجاع False كقيمة للدالة.

والآن أصبح كود الدالة كاملًا بهذه الطريقة:

def isnumber(x):
 try:
  if isinstance(float(x),float) == True or isinstance(int(x),int) == True:
   return True
 except ValueError:
  return False

لنجرب الآن دالتنا

>>> isnumber("text1")
False
>>> isnumber("4275")
True
>>> isnumber("21")
True
>>> isnumber("3.14")
True

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

مثال:


number = input("اكتب أي رقم للتحقق منه")
if isnumber(number) == True:
 print("مدخل صحيح")
else:
 print("غير مسموح بكتابة الحروف. لا بد من كتابة الأرقام فقط")

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

أرجو أن أكون قد وفقت في إيصال المعلومة بالطريقة المرجوة, مع تمنياتي لكم بالتوفيق.
والسلام عليكم ورحمة الله وبركاته.

هناك تعليق واحد:

  1. السلام عليكم ورحمة الله وبركاته.
    ماذا لو كتبناها هكذا
    try:

    اسم المتغير = float(اسم المتغير)
    except:
    وفي جوابها نظهر له رسالة خطأ عشان يعرف المستخدِم أن الخطأ منه هو
    أليس هذا الكود أصغر ويؤدي الغرض بكفاءة أَم لا؟

    ردحذف

قل شيئًا