إدخال بيانات المستخدم في بايثون
في الدروس السابقة, كنا نكتب الكود ثم نقوم بتجربته فيتنفذ كما هو, بمعنى أننا كنا أصلاً نعرف ما سيظهر عند تشغيل الكود لأننا كنا نقوم بتحديد قيم المتغيرات قبل تشغيل البرنامج.
في هذا الدرس ستتعلم كيف تنشئ برنامح يتفاعل مع المستخدم, حيث أنك عندما تقوم بتشغيله سيطلب من المستخدم إدخال بيانات, و بعد إدخالها سيقوم البرنامج بمعالجتها و فعل شيء معين بها.
الدالة input() في بايثون
لجعل المستخدم قادر على إدخال بيانات في البرنامج أثناء اشتغاله نستخدم دالة جاهزة إسمها input().
في كل مرة تقوم فيها باستدعاء هذه الدالة يقوم مفسّر لغة بايثون بانتظارك لإدخال ما تريد من لوحة المفاتيح ( Keyboard ).
بعد الإنتهاء من الإدخال و النقر على الزر Enter سيتم إرجاع الشيء الذي قمت بإدخاله كنص في المكان الذي تم منه إستدعاء الدالة input().
معلومة تقنية
عند استدعاء الدالة input() فإنك حتى لو قمت بإدخال رقم فإنها سترجعه كنص.
لذلك في حال كنت تريد من المستخدم أن يدخل رقم, سيكون عليك تحويل ما ترجعه الدالة لرقم.
أمثلة على إدخال البيانات من المستخدم في بايثون
في المثال التالي قمنا بإنشاء برنامج يطلب من المستخدم إدخال إسمه, ثم يعرضه له.
المثال الأول
# name هنا قمنا بإظهار رسالة تطلب من المستخدم أن يدخل إسمه. الإسم الذي سيدخله سيتم تخزينه في المتغير
name = input("What's your name? ")
# name هنا قمنا بعرض جملة ترحيب مبنية على إسم المستخدم الذي قمنا بتخزينه قبل قليل في المتغير
print("Nice to meet you", name)
•سنحصل على النتيجة التالية عند تشغيل الملف Test مع الإشارة إلى أننا قمنا بتعليم البيانات التي إنتظرنا البرنامج لإدخالها من لوحة المفاتيح باللون الأصفر.
Nice to meet you mhamad
في المثال التالي قمنا بإنشاء برنامج يطلب من المستخدم إدخال عددين صحيحين, ثم يعرضه له ناتج جمعهما.
لاحظ أننا وضعنا الدالة input() بداخل الدالة int() حتى يتم تحويل الرقم الذي سيدخله المستخدم إلى عدد صحيح قبل تخزينه في المتغير.
لو لم نفعل ذلك لتم إعتبار الأرقام التي أدخلها المستخدم عبارة عن نصوص و بالتالي كان ذلك سيسبب خطأ منطقي إظهار ناتج الجمع.
المثال الثاني
# a بعدها سيتم تخزين العدد في المتغير .int إلى النوع str هنا قمنا بإظهار رسالة تطلب من المستخدم أن يدخل عدد. العدد الذي سيدخله سيتم تحويله من النوع
a = int(input("Enter a: "))
# b بعدها سيتم تخزين العدد في المتغير .int إلى النوع str هنا قمنا بإظهار رسالة تطلب من المستخدم أن يدخل عدد. العدد الذي سيدخله سيتم تحويله من النوع
b = int(input("Enter b: "))
# هنا قمنا بعرض ناتج جمع العددين اللذين تم إدخالهما
print('a + b =', a + b)
•سنحصل على النتيجة التالية عند تشغيل الملف Test مع الإشارة إلى أننا قمنا بتعليم البيانات التي إنتظرنا البرنامج لإدخالها من لوحة المفاتيح باللون الأصفر.
Enter b: 7
a + b = 12
في المثال التالي قمنا بإنشاء برنامج يطلب من المستخدم إدخال عدد يمثل عدد عناصر مصفوفة, ثم يطلب منه إدخال قيمة لكل عنصر في المصفوفة.
في الأخير يعرض له البرنامج كل قيمة قام بإدخالها فيها على سطر واحد.
المثال الثالث
# n بعدها سيتم تخزين العدد في المتغير .int إلى النوع str العدد الذي سيدخله سيتم تحويله من النوع .aList هنا قمنا بإظهار رسالة تطلب من المستخدم أن يدخل عدد عناصر الكائن
n = int(input("Enter the length of the list: "))
# عدد عناصره يساوي العدد الذي أدخله المستخدم, و القيمة الأولية لكل عنصر فيه هي 0 aList إسمه list هنا قمنا بإنشاء
aList = [0] * n
# واحداً i و طبعاً, في بداية كل دورة في هذه الحلقة ستزيد قيمة المتغير .aList تبدأ من 0 إلى عنصر في الكائن for هنا قمنا بإنشاء حلقة
for i in range(len(aList)):
# بعدها سيتم وضعها في العنصر .int إلى النوع str في كل دورة سيطلب من المستخدم إدخال قيمة لعنصر جديد. بعدها سيتم تحويل نوع القيمة التي يدخلها من النوع
aList[i] = int(input('Enter aList[' + str(i) + ']: '))
print('aList contain the following values:')
# val و تخزنه في الكائن aList هنا قمنا بإنشاء حلقة تجلب في كل دورة قيمة عنصر من عناصر الكائن
for val in aList:
# تضيف مسافة فارغة بعد عرض القيمة بدلاً من النزول على سطر جديد print() مع جعل الدالة val هنا قمنا بطباعة القيمة المخزنة في المتغير
print(val, end=' ')
•سنحصل على النتيجة التالية عند تشغيل الملف Test مع الإشارة إلى أننا قمنا بتعليم البيانات التي إنتظرنا البرنامج لإدخالها من لوحة المفاتيح باللون الأصفر.
Enter aList[0]: 10
Enter aList[1]: 20
Enter aList[2]: 30
Enter aList[3]: 40
Enter aList[4]: 50
The list contain the following values:
10 20 30 40 50
مفهوم الـ Iterator في بايثون
الـ Iterator عبارة عن كائن يحتوي على عدد محدد من القيم التي يتم تخزينها بالترتيب وراء بعضها البعض حيث أنك عندما تريد الوصول إلى القيم التي فيه فإنك تستطيع الوصول إلى قيمه الواحدة تلو الأخرى بنفس الترتيب الذي تم تخزينهم فيه.
فعلياً, كلما وصلت إلى قيمة فيه تصبح قادر على الوصول إلى القيمة التالية الموضوعة بعدها مباشرةً.
معلومة تقنية
الـ Iterator في بايثون عبارة عن كائن يطبق بروتوكول يقال له Iterator Protocol.
هذا البروتوكول يتم تطبيقه من خلال إستدعاء الدالتين المجهزتين لذلك: __iter__() و __next__().
و بالتالي تستطيع إنشاء Iterator بنفسك إذا فعلت Override لهاتين الدالتين بشكل صحيح في حال أردت ذلك.
الفرق بين الـ Iterator و الـ Iterable في بايثون
عند إنشاء كائن list, tuple, set, أو dict فإنك بذلك تنشئ كائن نوعه Iterable حيث أنك تستطيع الوصول لقيمة أي عنصر فيهم بشكل مباشر من خلال ذكر رقم الـ Index أو الـ Key الخاص بالعنصر.
كائن الـ Iterator لا يمكن الوصول لقيم محددة فيه, لأنه كما سبق و قلنا يمكنك الوصول لقيمه بنفس الترتيب الذي تم تخزينهم فيه.
في كل مرة تريد فيها الحصول على القيمة التالية فيه سيكون عليك إستدعاء دالة إسمها next().
هذه الدالة مصممة لإعطاءك القيمة التالية في الـ Iterator في كل مرة تستدعيها فيها.
في حال وصلت إلى نهاية الـ Iterator - أي إلى آخر قيمة فيه - و قمت باستدعاءها, سترجع لك الخطأ StopIteration.
الفرق المهم بين الـ Iterable و الـ Iterator هو أن هذا الأخير لا يمكن الوصول بشكل مباشر لقيمة محددة فيه.
التعامل مع الـ Iterator في بايثون
في البداية, للحصول على نسخة من كائن نوعه Iterable ككائن نوعه Iterator, نستخدم دالة جاهزة في بايثون إسمها iter().
في المثال التالي قمنا بإنشاء list وضعنا فيه 3 قيم.
بعدها قمنا بإنشاء iterator منه, و من ثم عرضنا القيم الموجودة فيه الواحدة تلو الأخرى.
مثال
# my_list يحتوي على 3 قيم, إسمه list هنا قمنا بإنشاء
my_list = ("Banana", "Orange", "Apple")
# my_list وضعنا فيه قيم الكائن iterator هنا قمنا بإنشاء
my_iterator = iter(my_list)
# ثلاث مرات و عرض ما ترجعه في كل مرة next() هنا قمنا باستدعاء الدالة
# my_iterator لاحظ أنها في كل مرة ترجع القيمة التالية في الكائن
print(next(my_iterator))
print(next(my_iterator))
print(next(my_iterator))
•سنحصل على النتيجة التالية عند تشغيل الملف Test.
Orange
Apple
المرور على قيم الـ Iterator بواسطة الحلقة for في بايثون
في المثال التالي قمنا بإنشاء list وضعنا فيه 3 قيم.
بعدها قمنا باستخدام الحلقة for لعرض القيم الموجودة فيه الواحدة تلو الأخرى.
المثال الأول
# my_list يحتوي على 3 قيم, إسمه list هنا قمنا بإنشاء
my_list = ("Banana", "Orange", "Apple")
# بعدها سيتم عرض قيمته ,val و من ثم وضعها في المتغير my_list هنا في كل دورة سيتم جلب القيمة التالية من الكائن
for val in my_list:
print(val)
•سنحصل على النتيجة التالية عند تشغيل الملف Test.
Orange
Apple
معلومة تقنية
الذي عليك معرفته هنا هو أن مفسر لغة بايثون يقوم بتحويل الحلقة for إلى كائن iterator و على هذا الأساس فإن الحلقة ترجع لك القيمة التالية في كل دورة.
إذاً الحلقة for التي تستخدمها للمرور على قيم أي Iterable كالتالي.
for element in iterable:
# iterable هنا نكتب ما نريد أن نفعله مع قيم الـ
فعلياً مفسر لغة بايثون يقوم داخلياً بالتعامل مع الحلقة for كالتالي.
# iterable من الـ iterator يقوم بإنشاء
iter_obj = iter(iterable)
# لا تتوقف while بعدها ينشئ حلقة
while True:
# iterator و في كل دورة في هذه الحلقة يحاول جلب القيمة التالية الموجودة في كائن الـ
try:
element = next(iter_obj)
# سيتم إيقاف الحلقة عن العمل - StopIteration أي عندما يحدث خطأ نوعه - iterator بمجرد أن لا يعود هناك أي قيمة جديدة في كائن الـ
except StopIteration:
break
ملاحظة
لست مضطر لفهم طريقة عمل الحلقة for بشكل دقيق جداُ في هذه المرحلة, لكن يفضل أن تعرف ذلك لتفهم كيف تعمل لغة بايثون و تزيد خبرتك في التعامل معها.
كما أنك ستفهم الكود الذي كتبناه الآن بكل سهولة في دروس لاحقة حين تتعلم كيف تعالج الأخطاء البرمجية باستخدام الكلمتين try و except.
في المثال التالي قمنا بالمرور على جميع أحرف النص و عرضهم واحداً تلو الآخر باستخدام الحلقة for.
المثال الثاني
# هنا قمنا بتعريف متغير يحتوي على نص, أي يحتوي على سلسلة من الأحرف string = 'Python' # بعدها سيتم عرضه .string في كل دورة في الحلقة سيتم جلب حرف من هذا النص و تخزينه في المتغير for c in string: print(c)
•سنحصل على النتيجة التالية عند تشغيل الملف Test.
y
t
h
o
n
ملاحظة
بما أن الحلقة for ترجع الحرف التالي الموجود في النص في كل دورة, فهذا يعني أن النوع str أيضاً يعتبر Iterable.
أمثلة حول إنشاء Iterator في بايثون
في المثال التالي قمنا ببناء كلاس يعطينا Iterator لا نهاية له. أي قمنا ببناء Infinite Iterator.
المثال الأول
# __next__() و __iter__() للدالتين Override لأنه يفعل Iterator يمثل IterCounter هنا قمنا بإنشاء كلاس إسمه class IterCounter: # هي 0 IterCounter هنا قلنا أن القيمة الأولى التي سيتم إعطاؤها لأي كائن يتم إنشاؤه من الكلاس def __iter__(self): self.num = 0 return self # مضافاً إليها 1 num ستكون قيمة المتغير next() في كل مرة نستدعي فيها الدالة IterCounter هنا قلنا أن القيمة التالية التي سيرجعها الكائن الذي ننشئه من الكلاس def __next__(self): self.num += 1 return self.num # iter_counter و من ثم قمنا بتخزينه في الكائن ,iter() بواسطة الدالة iterator مع تحويله مباشرةً لـ IterCounter هنا قمنا بإنشاء كائن من الكلاس iter_counter = iter(IterCounter()) # next() في كل مرة نمرره للدالة iter_counter هنا قمنا بعرض القيمة التالية التي سيرجعها الكائن print(next(iter_counter)) print(next(iter_counter)) print(next(iter_counter)) print(next(iter_counter)) print(next(iter_counter))
•سنحصل على النتيجة التالية عند تشغيل الملف Test.
2
3
4
5
في المثال التالي قمنا ببناء كلاس يعطينا Iterator يعطينا القيم المضاعفة للعدد 2 مع جعل المستخدم قادر على تحديد عدد القيم الأقصى الذي سيتم إرجاعه.
المثال الثاني
class PowTwo: # يمكن تمرير رقم لها مباشرةً عند إنشاء كائن من هذا الكلاس end الخاصية def __init__(self, end=1): self.end = end # تساوي 0 next() الذي سنستخدمه لحساب كم مرة تم إستدعاء الدالة n هنا جعلنا القيمة الأولية للمتغير def __iter__(self): self.n = 1 return self # سيتم إرجاع القيمة end أصغر من قيمة الخاصية n إذا كانت قيمة المتغير ,next() هنا قلنا أنه كلما تم إستدعاء الدالة # الذي يعني أنه لم يعد هناك أي قيمة في الكائن StopIteration المضاعفة التالية, و إذا لم تكن أصغر منها سيتم إرجاع الخطأ def __next__(self): if self.n <= self.end: result = 2 ** self.n self.n += 1 return result else: raise StopIteration # next() و من ثم طباعة المضاعفات الخمسة للرقم 2 كلما تم إستدعاء الدالة end و تمرير القيمة 5 مكان الخاصية PowTwo هنا قمنا بإنشاء كائن من الكلاس for val in PowTwo(5): print(val)
•سنحصل على النتيجة التالية عند تشغيل الملف Test.
4
8
16
32