List Comprehension vs Generator Expression
في هذا المقال سنتعلم معًا بعض المزايا الجميلة في بايثون التي ستساعدك حتمًا على توفير الاسطر البرمجية وبالتالي السرعة في المعالجة
بسم الله الرحمن الرحيم
في هذا المقال سنتعرف على :
-
ماهي List Comprehension
-
امثلة مباشرة على List Comprehension
-
ماهو Generator Expressions
-
Iterable and Iterator
-
كيف نتعامل مع Generator Expressions
المتطلبات على الأقل ان يكون لدى القارىء :
معرفة بانواع البيانات في بايثون والتكرارات
المستوى :
مبتدىء الى متوسط ولكن ان كنت في مستوى متقدم ربما لن يقدم لك تلك الفائدة المرجوة !
ماهي List Comprehension ؟
لناخد مثال بسيط اولًا فرضًا طلب مني القيام بكتابة كود برمجي يقوم بإضافة الاعداد من 0 الى 9 الى List فارغة.
num = []
for i in range(10):
num.append(i)
print(num)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]#output
ولكن باستخدام List Comprehension سنقوم بحل المثال كالتالي :
num = [i for i in range(10)]
print(num)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]#output
كما نلاحظ هنا تماما اختصرنا كود بثلاث اسطر بسطر واحد اذا يمكننا القول ببساطة ان List Comprehension هي احد طرق بايثون لجعل انشاء List انيق وبسطور اقل وسهل القراءة وسريع
والصيغة العامة لها كالتالي :
list_variable = [x for x in iterable]
حيث أن :
-
list_variable
هي المتغير الذي نريد حفظ List داخله
-
x
تعتبر عن القيمة التي سنقوم باضافتها ل List
-
for x in iterable
تعني شرط التكرارسنتحدث باالتفصيل الممل عن iterable لاحقًا
Multiple loops مع list comprehension
فرضا اردنا تكرار عناصر قائمة معينة 5 مرات بالطريقة العادية سنقوم بحلها هكذا :
our_list = [0,1,2,3]
num = []
for i in range(5):
for j in our_list:
num.append(j)
print(num)
[0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]#output
ولكن مع استخدام List Comprehension نقوم بالتالي :
num = [j for i in range(5) for j in our_list]
print(num)
[0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]#output
IF conditions مع list comprehension
فرضا اردنا اضافت شرط لمثالنا الاول بحيث انه سيقوم بعمل List للاعداد الزوجية الواقعة بين 0 و 9 بلطريقة العادية سنقوم بالتالي :
num = []
for i in range(10):
if i % 2 == 0 :
num.append(i)
print(num)
[0, 2, 4, 6, 8] #output
اما مع List Comprehension سنقوم بحل المثال بهذه الطريقة :
num = [ i for i in range(10) if i % 2 == 0 ]
print(num)
[0, 2, 4, 6, 8]#output
ملاحظة : Comprehension ليست مخصصة فقط لـ List بل يمكن استخدامها مع tuple , dictionaries وهناك ماسيواجهنا خصوصا عندما نتعامل مع tuple
مثال :
num = [ i for i in range(10) if i % 2 == 0 ]
print(num)
[0, 2, 4, 6, 8] #output
num = ( i for i in range(10) if i % 2 == 0 )
print(num)
<generator object <genexpr> at 0x00000244EE93C360> #output
نلاحظ هنا ان الاول يعتبر List Comprehension وعرفنا ذلك من خلال الاقواس [] بينما الثاني يملك الاقواس () والتي يقوم بايثون بمعالجتها على انها tuple اذا لماذا لم يتم طباعة المخرجات مثل مخرجات list؟ وماهي generator ؟وكيف سنقوم بحل هذه المشكلة ؟
هذا الامر يقودونا الى مايسمى بـ Generator Expression
ماهي Generator Expression؟
تعتبر Generator من الاكثر الاشياء الجميلة في بايثون رغم أنها سهلة ولكن هناك تعقيد بسيط في فهمها جيدا ولها عدة انواع ولكن بهذا الموضوع سنتطرق لنوع واحد وهو Generator Expressions
فيحديثنا السابق عن List Comprehensionsعلمنا ان Comprehensions ليست محصورة فقط على list حيث انه يمكن ان نقوم بعمل مشابهه ل tuple ولكن صادفتنا هناك مشكلة اذ مانتج كانمختلف تماما عن المتوقع !
ان الناتج الذي نتج انذاك يسمى Generator Expressions
ولكن قبل المضي قدما يجب لتسهيل فهمنا Generator Expressions
التعرف على :
Iterable and Iterator
1- Iterable
هو object ببايثون يقوم بارجاع Iterator وتحتوي على ولها احد الخواص iter او getitem
اذا كان ماقلته غير مفهوم بالنسبة لك لاداعي للذعر ابدا انت تعرفه مسبقا! ولكن هيا بنا لنضع النقاط على الحروف 😉
يعتبر list احد صور Iterable نعم هناك صور اخرى له ايضا ستعرفها بنفسك 😉 لنبسط الفكرة قليلا ياترى مالذي يفرق list عن int ؟
list = [1,2,3]
print(list[0])
1 #output
num = 123
print(num[0])
#output
Traceback (most recent call last):
File "<pyshell#68>", line 1, in <module>
num[0]
TypeError: 'int' object is not subscriptable
اذا مايفرق list عن int انه قابل للفهرسة او يمكن ان يحتوي على index كما نعلم اذا يمكننا صياغة الان Iterable انها اي object قابل ان يكون له index
مثلا : list , string , dictionary , tuple , .. etc
ويمكننا المعرفة عن طريق استخدام احد الدوال
hasattr()
حيث انا قلنا سابقا شرط ان يكون object الذي نملكه يجب ان يكون له احد الخواص iter او getitem
>>> hasattr(list, '__iter__')
True
>>> hasattr(int, '__iter__')
False
2- Iterator
اذا ماهو Iterator ؟ ممكن ان نقول Iterator هي القيم التي لها index داخل Iterable
3- Iteration
لنفترض اردنا طباعة كل قيم اللستة التي عملنها مسبقا سنقوم بالتالي :
for i in list :
print(i)
#output
1
2
3
اذا يمكننا تعريف Iteration ببساطة على انها العملية التي تاخد القيم من شيء معين
يمكننا ان نربط هذه المعاني بصفحات الكتاب بحيث نعتبر Iterable صفحات الكتاب و Iteration فاصل الكتاب و Iterator احدى الصفحات التي وضعنا بها فاصل الكتاب
في مثالنا السابق عندما اردنا طباعة قيم اللستة ان ماحصل تقريبا خلف الانظار هو كالتالي :
1- تم استدعاء دالة تسمى iter() لتحويل ال object الى iterator object
2- تم استدعاء الدالة next() لتقوم باخد القيمة الاخرى داخل iterator object
3- StopIteration exception وهو ماحصل عندما انتهت القيمة عندي وتوقف for loop
>>> list = [1,2,3]
>>> iterator = iter(list)
>>> print(iterator)
<list_iterator object at 0x000001CA788C8710>
>>> next(iterator)
1
>>> next(iterator)
2
>>> next(iterator)
3
>>> next(iterator)
Traceback (most recent call last):
File "<pyshell#82>", line 1, in <module>
next(iterator)
StopIteration
كما لاحظنا هنا عندما استدعينا دالة iter() قامت بتحويل list object الى iterator object
وثم عندما استدعينا next() قامت بطرح القيمة مرا تل والاخرى الى ان انتهت من القيم قامت بطباعة خطا StopIteration اي انه لايجود قيم يمكن طباعته
ملاحظة : لطباعة جميع القيم بسطر واحد يمكن استخدام * بالمثال السابق (print(*iterator ولكن يجب التاكد اننا اعدنا جعل المتغير iterator object حيث بالخطوة الاولى سنقوم بالتفريغ الكلي وهذا ماسنناقشه لاحقا
اعتقد انه حان الوقت للتعرف على Generator Expressions
نلاحظ عندما قمنا بطابعة iterator object ظهر لي
<list_iterator object at 0x000001CA788C8710>
وهو مشابهه تقريبا لما حصل معي عند استخدام tuple كما تلاحظون
num = [ i for i in range(10) if i % 2 == 0 ]
print(num)
[0, 2, 4, 6, 8] #output
num = ( i for i in range(10) if i % 2 == 0 )
print(num)
<generator object <genexpr> at 0x00000244EE93C360> #output
اذا الان اتضحت الرؤية ان الحالة الاولى كانت List Comprehension والحالة الثانية كانت Generator Expressions وهي كسابقتها iterator object
اذا كيف سنقوم بحل المشكلة وطباعة القيم ؟
هناك حلان :
1. سنقوم بماقمنا به بالمثال السابق بعد عمل iterator object وهي استخدام دالة next()
>>> num = ( i for i in range(10) if i % 2 == 0 )
>>> next(num)
0
>>> next(num)
2
>>> next(num)
4
>>> next(num)
6
>>> next(num)
8
>>> next(num)
Traceback (most recent call last):
File "<pyshell#97>", line 1, in <module>
next(num)
StopIteration
2- او اننا سنقوم باستخدام for loop
>>> num = ( i for i in range(10) if i % 2 == 0 )
>>> for i in num :
print(i)
0
2
4
6
8
حسنا الان ماذا لو قمنا بعمل for loop اخرى ل num ؟
بو o.O اختفى كل شيء !
نعم لهذا بالمثال السابق قلت انه من الجدير ان نقوم بتعريف المتغير مره اخرى وهذا مايميز Generator Expressions اي ان القيمة التي سوف نقوم بطباعتها سيتم محوها من الذاكرة على الفور مما يجعل الامر كود اقل ومساحة اقل وعمل لا اروع 😇
الملخص
-
- كما ذكرنا سابقا List Comprehension تعتبر طريقة سهلة وانيقة لانشاء list
-
- وايضا تعتبر طريقة اسرع من الطرق العادية كاستخدام for loop مثلا
-
- يجب الانتباه جيدا عند استخدام List Comprehension بحيث لايتعدى الكود سطر واحد حتى يحتفظ الكود على سهولة قرائته
-
- يجب كتابة كل List Comprehension ب for loop ولكن لايمكن تحويل كل for loop الى List Comprehension
-
- لاتعتبر List Comprehension الطريقة الوحيدة هناك طرق اخرى لتحسين طريقة كتابة list اما باستخدام Lambda functions او built in functions وغيرهم
-
-Generator Expressions تشبهه List Comprehension ولكن الاختلاف في الناتج
-
-Generator Expressions اذا تم استخدامها مره واحدة لايمكن استخدامها مرا اخرى
وكما قلت في بادىء الامر توجد انواع ومواضع مختلفه يستخدم لها Generator مثلا function generator او class-based iterator وجميعها دا فائدة قصوى في بعض الحالات يمكنكم البحث عنهم والتعمق فيهم او ربما ساقوم بطرح مقال اخر يخص هذا الجانب من Generator بشكل اعمق
بالتوفيق جميعَا
ياصديقي الأمر كله يدور حول الشغف ،ما إن يبهت الشغف يبهت معه كل شيء !
miss-x
لايوجد لديك حساب في عالم البرمجة؟
تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !