مرحبا يا هبر. في كثير من الأحيان عند العمل مع تسلسل ، السؤال الذي يطرح نفسه من إنشائها. يبدو أنه يستخدم لاستخدام
إدراج القائمة (فهم القائمة) ، وفي الكتب يصرخ حول الاستخدام الإلزامي لوظيفة
الخريطة المضمنة.
في هذه المقالة ، سننظر في هذه الأساليب للتعامل مع التتابعات ، ومقارنة الأداء ، وكذلك تحديد المواقف التي يكون فيها النهج أفضل.
قائمة الفهم
إدراج القائمة عبارة عن آلية لإنشاء قائمة مضمنة في بيثون. لديه مهمة واحدة فقط - لبناء قائمة. إدراج القائمة يبني قائمة من أي نوع قابل للتكرار ، مع تحويل (تصفية) القيم الواردة.
مثال على إدراج قائمة بسيطة لإنشاء قائمة مربعات الأرقام من 0 إلى 9:
squares = [x*x for x in range(10)]
النتيجة:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
الخريطة
الخريطة هي وظيفة مضمنة في اللغة. يقبل وظيفة كمعلمة الأولى ، وكائن قابل للتكرار باعتباره الثاني. إرجاع مولد (Python 3.x) أو قائمة (Python 2.x). سأختار بيثون 3.
مثال على استدعاء وظيفة الخريطة لإنشاء قائمة مربعات الأرقام من 0 إلى 9:
squares = list(map(lambda x: x*x, range(10)))
النتيجة:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
مقارنة الأداء
بناء بدون وظائف
كتجربة ، سننظر في مربعات الأرقام من الفاصل الزمني من 0 إلى 9999999:
python -m timeit -r 10 "[x*x for x in range(10000000)]" python -m timeit -r 10 "list(map(lambda x: x*x, range(10000000)))"
النتائج:
1 loop, best of 10: 833 msec per loop 1 loop, best of 10: 1.22 sec per loop
كما ترون ، تعمل طريقة
فهم القائمة على نحو أسرع بنسبة 32٪. لا يمكن الحصول على إجابات كاملة بعد تفكيكها ، لأن وظيفة الخريطة "يبدو أنها تخفي تفاصيل عملها". ولكن من المحتمل أن يكون هذا بسبب الدعوة المستمرة لوظيفة lambda ، والتي يتم فيها إجراء حسابات مربعة بالفعل. في حالة فهم القائمة ، نحتاج فقط إلى حساب المربع.
بناء مع الميزات
للمقارنة ، سننظر أيضًا في مربعات الأرقام ، لكن الحسابات ستكون الآن داخل الوظيفة:
python -m timeit -r 10 -s "def pow2(x): return x*x" "[pow2(x) for x in range(10000000)]" python -m timeit -r 10 -s "def pow2(x): return x*x" "list(map(pow2, range(10000000)))"
النتائج:
1 loop, best of 10: 1.41 sec per loop 1 loop, best of 10: 1.21 sec per loop
هذه المرة يتم عكس الوضع. كانت طريقة
الخريطة أسرع بنسبة 14٪. في هذا المثال ، كلتا الطريقتين في نفس الموقف. كلاهما يجب استدعاء دالة لحساب المربع. ومع ذلك ، فإن التحسينات الداخلية لوظيفة الخريطة تسمح لها بعرض نتائج أفضل.
ماذا تختار؟
أدناه هي القاعدة لاختيار الطريقة الصحيحة:

قد تكون هناك استثناءات لهذه القاعدة ، ولكن في معظم الحالات سوف تساعدك على اتخاذ القرار الصحيح!
هل الخريطة "أكثر أمانًا"؟
لماذا كثير نحث على استخدام
الخريطة . الحقيقة هي أنه في بعض الحالات تكون الخريطة أكثر أمانًا من فهم القائمة.
على سبيل المثال:
symbols = ['a', 'b', 'c'] values = [1, 2, 3] for x in symbols: print(x) squared = [x*x for x in values]
سيكون ناتج البرنامج كما يلي:
a 3 b 3 c 3
أعد كتابة الرمز نفسه باستخدام
الخريطة :
symbols = ['a', 'b', 'c'] values = [1, 2, 3] for x in symbols: print(x) squared = map(lambda x: x*x, values)
الاستنتاج:
a a b b c c
يمكن للملاحظ أن يلاحظ بالفعل من بناء جملة استخدام
الخريطة أن هذا هو بيثون 2. في الواقع ، في الثعبان الثاني كان هناك نوع مماثل من مشكلة متغيرات الكتابة. ومع ذلك ، في بيثون 3 ، تم حل هذه المشكلة ولم تعد ذات صلة.
الأمثلة الموضحة أعلاه ستظهر نفس النتائج. قد يبدو أيضًا أن هذا خطأ غبي ولن ترتكب مثل هذا الخطأ أبدًا ، ومع ذلك ، يمكن أن يحدث هذا عندما تقوم ببساطة بنقل كتلة من التعليمات البرمجية مع حلقة داخلية من كتلة أخرى. مثل هذا الخطأ يمكن أن يقضي الكثير من الوقت والأعصاب لإصلاحه.
استنتاج
أظهرت المقارنة أن كل طريقة جيدة في وضعها.
- إذا كنت لا تحتاج إلى جميع القيم المحسوبة في وقت واحد (أو ربما لا تكون مطلوبة على الإطلاق) ، فعليك اختيار الخريطة . لذلك ، حسب الحاجة ، سوف تطلب جزءًا من البيانات من المولد ، مع توفير قدر كبير من الذاكرة (Python 3. في Python 2 ، هذا غير منطقي ، لأن الخريطة تُرجع قائمة).
- إذا كنت بحاجة إلى حساب جميع القيم في وقت واحد ، ويمكن إجراء العمليات الحسابية دون استخدام الدوال ، فيجب عليك الاختيار في اتجاه قائمة الفهم . كما هو مبين من نتائج التجارب - لديها ميزة كبيرة في الأداء.
ملاحظة: إذا فاتني شيء ما ، فأنا سعيد بمناقشته معك في التعليقات.