مرحبا بالجميع. اليوم نريد أن نشارك ترجمة مفيدة واحدة ، أعدت قبل إطلاق الدورة التدريبية "مطور الويب في بيثون" . تعد كتابة التعليمات البرمجية الموفرة للوقت والفعالة في Python مهمة بشكل خاص عند إنشاء تطبيق ويب أو نموذج للتعلم الآلي أو الاختبار.

عندما بدأت في تعلم المولدات في بيثون ، لم يكن لدي أي فكرة عن مدى أهميتها. ومع ذلك ، فقد ساعدوني باستمرار في كتابة وظائف طوال رحلتي عبر التعلم الآلي.
تسمح لك وظائف المولد بالإعلان عن وظيفة ستتصرف مثل التكرار. أنها تسمح للمبرمجين بإنشاء متكررين سريع وبسيط ونظيف. التكرار هو كائن يمكن تكراره (محلقًا). يتم استخدامه لاستخلاص حاوية البيانات وجعلها تتصرف ككائن قابل للتكرار. على سبيل المثال ، يمكن أن يكون مثال الكائن القابل للتكرار هو السلاسل والقوائم والقواميس.
يبدو المولد وكأنه دالة ، لكنه يستخدم الكلمة المفتاحية بدلاً من الإرجاع. دعونا نلقي نظرة على مثال لجعله أكثر وضوحا.
def generate_numbers(): n = 0 while n < 3: yield n n += 1
هذه هي وظيفة مولد. عندما تسميها ، فإنها ترجع كائن المولد.
>>> numbers = generate_numbers() >>> type(numbers) <class 'generator'>
من المهم الانتباه إلى كيف يتم تغليف الحالة في جسم وظيفة المولد. يمكنك تكرار واحد في وقت واحد باستخدام وظيفة next () المدمجة:
>>> next_number = generate_numbers() >>> next(next_number) 0 >>> next(next_number) 1 >>> next(next_number) 2
ماذا يحدث إذا اتصلت بعد ذلك () بعد انتهاء التنفيذ؟
StopIteration هو نوع استثناء مضمّن يحدث تلقائيًا بمجرد توقف المولد عن إرجاع نتيجة. هذه إشارة توقف للحلقة.
بيان العائد
وتتمثل مهمتها الرئيسية في التحكم في تدفق وظيفة المولد بحيث يبدو وكأنه عبارة إرجاع. عند استدعاء دالة المولد أو استخدام تعبير المولد ، فإنها تُرجع مكررًا خاصًا يسمى المولد. لاستخدام مولد ، قم بتعيينه إلى بعض المتغيرات. عند استدعاء طرق خاصة في المولد ، مثل next () ، سيتم تنفيذ رمز الوظيفة حتى يتم إنتاجه.
عندما يحصل في بيان العائد ، يقوم البرنامج بإيقاف الوظيفة مؤقتًا وإرجاع القيمة إلى الكائن الذي بدأ التنفيذ. (بينما توقف الإرجاع عن تنفيذ الوظيفة بالكامل.) عندما يتم تعليق الوظيفة ، يتم الحفاظ على حالتها.
الآن وقد أصبحنا على دراية بالمولدات في Python ، فلنقارن الطريقة المعتادة مع النهج الذي يستخدم المولدات من حيث الذاكرة والوقت الذي يقضيه في تنفيذ التعليمات البرمجية.
بيان المشكلة
لنفترض أننا بحاجة إلى مراجعة قائمة كبيرة من الأرقام (على سبيل المثال ، 1،000،000،000) وحفظ المربعات الخاصة بجميع الأرقام التي يجب تخزينها بشكل منفصل في قائمة أخرى.
النهج المعتاد
import memory_profiler import time def check_even(numbers): even = [] for num in numbers: if num % 2 == 0: even.append(num*num) return even if __name__ == '__main__': m1 = memory_profiler.memory_usage() t1 = time.clock() cubes = check_even(range(100000000)) t2 = time.clock() m2 = memory_profiler.memory_usage() time_diff = t2 - t1 mem_diff = m2[0] - m1[0] print(f"It took {time_diff} Secs and {mem_diff} Mb to execute this method")
بعد تشغيل الكود أعلاه ، نحصل على ما يلي:
It took 21.876470000000005 Secs and 1929.703125 Mb to execute this method
باستخدام المولدات
import memory_profiler import time def check_even(numbers): for num in numbers: if num % 2 == 0: yield num * num if __name__ == '__main__': m1 = memory_profiler.memory_usage() t1 = time.clock() cubes = check_even(range(100000000)) t2 = time.clock() m2 = memory_profiler.memory_usage() time_diff = t2 - t1 mem_diff = m2[0] - m1[0] print(f"It took {time_diff} Secs and {mem_diff} Mb to execute this method")
بعد تشغيل الكود أعلاه ، نحصل على ما يلي:
It took 2.9999999995311555e-05 Secs and 0.02656277 Mb to execute this method
كما نرى ، يتم تقليل وقت التشغيل والذاكرة المستخدمة بشكل كبير. تعمل المولدات على مبدأ يعرف باسم "الحوسبة البطيئة". هذا يعني أنه يمكنهم حفظ المعالج والذاكرة وموارد الحوسبة الأخرى.
استنتاج
آمل في هذا المقال أن أتمكن من إظهار كيف يمكن استخدام المولدات في Python لتوفير موارد مثل الذاكرة والوقت. تظهر هذه الميزة نظرًا لحقيقة أن المولدات لا تخزن جميع النتائج في الذاكرة ، ولكن تحسبها على الطاير ، ويتم استخدام الذاكرة فقط إذا طلبنا نتيجة الحسابات. تسمح لك المولدات أيضًا باستخلاص كمية كبيرة من كود البليت ، وهو أمر ضروري لكتابة التكرارات ، لذلك فهي تساعد أيضًا في تقليل مقدار الكود.