اذهب إلى المحتوى

تُعَد لغة بايثون من أكثر لغات البرمجة قوةً وانتشارًا، فهي تدخل في معظم البنى الرقمية العصرية. ونظرًا لتنوع المسارات الوظيفية التي قد يوفرها احتراف البرمجة بلغة بايثون، سيركز المطوّر غالبًا على إتقان أساسيات مسار أو مسارين ثم يبحث عن فرصة عمل كمتدرب. ويَعُدّ أغلب المطوروين هذه الخطوة على أنها الخطوة الأصعب في المسيرة المهنية، ويعاني الكثيرون في اجتيازها.

لهذا السبب، نوجه مقالنا إلى مطوري بايثون الذين يستعدون للدخول إلى سوق العمل. ونناقش فيه أهم النقاط التي قد يُسألون عنها في مقابلات العمل، سواءً لناحية استيعابهم مفاهيم اللغة الأساسية أو لتحديد إمكانياتهم التقنية وقدرتهم على إيجاد الحلول.

سنتحدث فيما يلي عن بعض الأسئلة التي تُطرح على مطوري بايثون في مقابلات العمل، وقد قدمناها وفق أقسام تغطي أساسيات اللغة، ثم مكتبات بايثون، وأطر العمل التي تعتمد على بايثون.

أسئلة عامة

فيما يلي أبرز الأسئلة التي قد تطرح على المتقدمين لوظيفة مطوري بايثون في مقابلات التوظيف.

لماذا اخترت العمل مع بايثون؟ ما مميزاتها

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

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

ما المقصود بأن لغة بايثون ديناميكية النمط dynamically typed

بايثون لغة ديناميكية في تحديد نوع المتغير، فهي تحدد تلقائيًا نوع المتغير بمجرد إسناد قيمة له. فإن أسندنا له قيمةً صحيحة، فسيكون المتحول صحيحًا، ونصيًا إن أسندنا إليه نصًا، بالتالي لا حاجة للتصريح عن نوع المتغير.

كيف نحدد نوع متغير ما إن احتجنا إلى ذلك

لا يمكن تحديد نوع المتغير عند التصريح عنه؛ إذ يرمي عندها المفسّر Interpreter خطأً. ولحل الأمر نستخدم التابع ()type لتحديد نوع المتغير والتعليمة is لمقارنة نوعه مع الأنواع التي تدعمها لغة بايثون وتكون نتيجة العملية نتيجة منطقيةً بوليانية (صحيح أو خاطئ)، وعندها يُنفذ الشرط المتعلق بالنوع أو لا يُنفّذ.

قارن بين list و tuple في بايثون، ووضّح ذلك من خلال مثال

يقدم كلا النوعين أسلوبًا لترتيب البيانات وفق تسلسل محدد لتخزينها، مثل عرض قائمة بالمقاسات المتاحة لسلعة ما؛ أما وجه الاختلاف بينهما، فهو قابلية التعديل Immutability؛ فالقوائم من النوع list ديناميكية، ويمكن تعديل عناصرها وإضافة أو حذف عناصر بعد إنشائها وفي أي وقت؛ في حين لا يمكن تعديل أي شيء بالقوائم من النوع tuple بعد إنشائها.

مع ذلك لكل نوع استخدامه المناسب، حيث نستخدم القائمة list مثلًا لتخزين الاسم المستعار لمستخدم وعمره ومكان إقامته وبريده الإلكتروني، فقد يرغب المستخدم بتغيير أي منها؛ في حين نستخدم القائمة tuple لتخزين أيام الأسبوع مثلًا فهي لن تتغير.

كيف نمرر إلى دالة أربعة وسطاء موضعيين Positional دون أن تصرح عن أربع معاملات

نصرح في هذه الحالة عن الدالة بالطريقة التقليدية ثم نسمي معاملًا واحدًا فقط يبدأ بالرمز * كالتالي:

def func(*args):

بهذا الشكل يمكن أن نمرر للدالة أي عدد من الوسطاء، وsنصل إلى أي وسيط من خلال دليل المعامل args مثل args[2] لاستخدام قيمة الوسيط الثالث.

متى يحافظ وسيط ممر إلى دالة على قيمته بعد أن تحدّثها الدالة

تمرر بايثون الوسطاء إلى الدوال على شكل مرجع إلى كائن، لهذا نحن أمام سلوكين في هذه الحالة:

  • الوسيط القابل للتعديل Mutable مثل القوائم list سيحتفظ المتغير عندها بالتعديلات التي أجرتها الدالة
  • الوسيط غير القابل للتعديل مثل المتغيرات الصحيحة int والنصوص str لن تتغير عندها قيمة المتغير خارج الدالة

ما هي المزخرفات Decorators في بايثون؟

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

ما الفرق بين الصنف Class والكائن Object والنسخة instance في بايثون؟

تُعَد هذه المفاهيم أساسيةً في البرمجة كائنية التوجه OOP، فالصنف في بايثون هو مخطط أو هيكل للكائن، تُعرَّف فيه المتغيرات والدوال التي تصف خصائص الكائن وطريقة عمله أو الوظائف التي يقوم بها؛ أما الكائن، فهو كيان فعلي حقيقي تأخذ حيزًا من الذاكرة بٌنيت على أساس مخطط الصنف. والنسخة هي مصطلح يُستخدم لوصف الكائن بعد إنشائه، خاصةً عند وجود أكثر من كائن ومن نفس الصنف.

ما عمل الدوال الخاصة  __init__ و __new__ و __call__ في بايثون؟

تسمى هذه الدوال الخاصة باسم الدوال السحرية Magic Methods، حيث تتحكم بايثون من خلالها بسلوك الكائنات Objects بطرق خاصة، وتستخدم الدوال المعنية على النحو الآتي:

  • تُستخدم الدالة __new__ للتحكم في عملية إنشاء كائن من الصنف، وتُستدعى قبل __init__ تُفيد في حالات خاصة مثل حالة نمط التصميم singleton أو Metaclass
  • تُستخدم الدالة __init__ لتهيئة خصائص الكائن Object عند إنشائه، وتُستدعى مباشرة بعد __new__
  • تُستخدم الدالة __call__ لجعل الكائن قابلًا للاستدعاء كأنه دالة، بحيث يمكن تنفيذ كود عند استدعاء هذا الكائن مباشرةً

وضح مفهوم الصنف Metaclass في بايثون

Metaclass هو صنف خاص في بايثون مهمته تعريف سلوك الأصناف، حيث يتحكم بإنشاء وتعديل وتحديد سلوك هذه الأصناف قبل بناء كائنات منها. ينتُج عن Metaclass في العادة أصناف أخرى، فبينما تُعطي الأصناف Classes كائنات Objects، يعطينا الصنف Metacalss أصنافًا مخصصةً أو يغير خصائص وتوابع صنف ديناميكيًا.

ما هو نمط المفردة Singleton في بايثون وأين يُستخدم

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

اشرح مفهوم التجاوز Overriding في بايثون

يرتبط هذا المفهوم بالبرمجة كائنية التوجه في بايثون وبالوراثة تحديدًا، فلو كان لدينا صنف ابن Class يرث من صنف آخر أب وعرّفنا تابع Method في الصنف الابن بنفس البصمة Signature للدالة الموجودة في الصنف الأب، فإن دالة الابن ستتجاوز وتلغي وتستبدل دالة الأب تلقائيًا. تدعم بايثون التجاوز، وتقدم التابع super إن أردنا استدعاء تابع العنصر الأب الأصلي ضمن الابن.

ماهي المكررات Iterators في بايثون

المكررات Iterators في بايثون هي آلية تسمح لنا بالتنقل عبر مجموعة من العناصر مثل القوائم list أو الصفوف أو حتى السلاسل النصية تدريجيًا. وبدون الحاجة إلى حفظ جميع العناصر في الذاكرة مرةً واحدة.

يمكننا تحويل أي مجموعة قابلة للتكرار إلى مكرر باستخدام التابع ()iterالذي يعيد لنا مكررًا يمكن استخدامه للتنقل عبر العناصر، فلكي نتقل من عنصر إلى عنصر آخر في المكرر، سنستخدم الدالة ()next، وفي حال انتهت العناصر سنحصل على استنثاء من نوع StopIteration لنعرف أننا وصلنا لنهاية عناصر المكرر. فيما يلي مثال لمكرر سلسلة نصية:

text = "Ali"

# تحويل النص إلى مكرر
text_iterator = iter(text)

# التنقل عبر الأحرف باستخدام 
print(next(text_iterator))  # Output: A
print(next(text_iterator))  # Output: l
print(next(text_iterator))  # Output: i

# محاولة الوصول إلى حرف غير موجود
try:
    print(next(text_iterator))
except StopIteration:
    print("وصلنا إلى نهاية المكرر")

حدد استخدامات الكلمة المفتاحية with في بايثون مع ذكر مثال حول ذلك

تُستخدم with غالبًا لإدارة الموارد التي يعمل عليها التطبيق كالملفات وقواعد البيانات والاتصالات الشبكية، فمن خلالها سنضمن حيازة المورد واستخدامه بأمان، وإغلاقه تلقائيًا بعد الانتهاء منه حتى في حال وقوع أخطاء؛ فعندما نريد فتح ملف مثلًا، سنستخدم التعليمة open لفتح الملف، ولا بد من إغلاق الملف يدويًا عند الانتهاء باستخدام close، لكن عند استخدام with قبل open، فلا حاجة عندها لإغلاق الملف وسيُغلق تلقائيًا.

with open("file.txt", "r") as file:
    content = file.read()
    print(content)

ما الفرق بين الخيط Thread والعملية Process

الخيط هو آلية لتنفيذ مجموعة تعليمات متزامنة مع مجموعة تعليمات أخرى لكن باستخدام نفس الموارد، كمساحة الذاكرة والملفات مثلًا.

توحي الخيوط بمعالجة التعليمات على التوازي، لكن ما يجري في الواقع هو الانتقال السريع بين خيوط المعالجة، كما تتبادل الخيوط بيانات فيما بينها لتنسيق ماركة الموارد؛ أما العملية Process فهي آلية مشابهة لكن لكل عملية معزولة ولها مواردها الخاصة ولا تتشارك العمليات الموارد والبيانات فيما بينها إلا إن طُلب منها صراحة فعل ذلك بآليات تواصل خاصة.

ما هي فكرة GIL في بايثون، وما تأثيراتها على تنفيذ الشيفرة

تعدّ GIL أو مايعرف بالقفل العام للمفسر Global Interpreter Lock آليةً مهمة في بايثون تمنع أكثر من خيط معالجة Thread من تنفيذ شيفرة بايثون في نفس اللحظة ضمن نفس العملية. بمعنى آخر، حتى لو كانت لدينا عدة خيوط تعمل معًا، فإن GIL يسمح فقط لخيط واحد بتنفيذ تعليمات بشيفرة البايت Bytecode في كل وقت.

يؤثر وجود GIL بوضوح على أداء البرامج التي تعتمد على المعالجة المكثفة للمعالج CPU-bound، مثل معالجة الصور وتدريب نماذج تعلم الآلة والعمليات الحسابية الثقيلة، وذلك لأنه يمنع الاستفادة الكاملة من جميع أنوية المعالج المتاحة، مما يؤدي إلى أداء أقل من المتوقع.

مع ذلك، يمكن التغلب على هذه المشكلة باستخدام تقنية المعالجة المتعددة Multi-Processing بدلًا من الخيوط، بحيث تعمل كل عملية مستقلة بدون مشاركة GIL؛ كما يكمننا استخدام توزيعات بايثون لا تحتوي على GIL مثل Jython أو IronPython. ومن الحلول المتاحة أيضًا الاعتماد على مكتبات مكتوبة بلغة C أو لغات أخرى نتفادى قيد GIL، مثل NumPy وتنسرفلو TensorFlo.

هل هناك فرق بين Python و CPython و Jython

بالطبع، فبايثون Python هي مجموعة من المواصفات التي تحدد صياغة اللغة، بينما CPython و Jython هما طريقتان لتطبيق وتنفيذ هذه المواصفات؛ حيث أن CPython هي تنفيذ بايثون الرسمي بلغة C، أي أنها كُتبت باستخدام لغة C وتُصرّف إلى شيفرة البايت bytecode قبل أن ينفذها مفسّر مبني بلغة C؛ بينما Jython هي تنفيذ لبايثون بلغة جافا، فقد كُتبت باستخدام جافا وتُنفّذ باستخدام آلة جافا الافتراضية JVM وتدعم كل مكتبات جافا.

أسئلة حول المكتبات Libraries

فيما يلي أبرز الأسئلة التي قد تطرح على المتقدمين لوظيفة مطوري بايثون في مقابلات التوظيف حول مكتبات بايثون.

ما هي وظيفة المكتبة المضمّنة OS؟ وما عمل os.environ

تقدم هذه المكتبة وظائف للتفاعل مع نظام التشغيل، بما في ذلك إدارة الملفات ومعالجة العمليات وإدارة استدعاء وظائف نظام التشغيل؛ أما os.environ، فهو كائن شبيه بالقواميس يُستخدم للعمل مع متغيرات البيئة في حالات عديدة مثل ضبط الإعدادات والتعامل مع البيانات الحساسة بأمان.

ماهي وظيفة المكتبة asyncio ومتى تُستخدم

تُستخدم مكتبة asyncio في بايثون لتنفيذ عدة مهام في نفس الوقت، لاسيما في حال كانت هذه المهام تنتظر بيانات معينةم مثل انتظار رد من قاعدة بيانات أو من الإنترنت؛ فبدلًا من إيقاف البرنامج حتى ترد القاعدة أو السيرفر وحدوق حجب أو تعليق لعملية التنفيذ، تسمح asyncio للبرنامج بمواصلة عمله على مهام أخرى في نفس الوقت دون الحاجة لإنشاء خيوط Threads جديدة أو عمليات متعددة Multiprocessing.

يتم استخدام هذه الوظيفة عندما تكون لدينا عمليات مقيدة بالمدخلات والمخرجات I/O bound، أي عمليات تتوقف على انتظار بيانات، مثل إرسال طلبات لشبكة، أو قراءة ملفات، أو عند الحاجة لتنفيذ عدة أشياء بنفس الوقت على التزامن بدون استهلاك موارد كثيرة، وبكفاءة أعلى من الخيوط Threads، فهي تعد أفضل من الخيوط في بعض الحالات لأن بايثون يعتمد تقنية GIL التي تمنع تشغيل خيوط كثيرة بفعالية عالية، وبهذا تجنبنا asyncio هذه المشكلة، فتكون أسرع وأخف على الذاكرة.

ما هي المكتبات التي تدعم تقنيتي Multi-Threading و Multi-Processing في بايثون

تقدم بايثون المكتبة threading لدعم إنشاء خيوط المعالجة والتحكم بها. وتستخدم في العمليات المقيدة بأجهزة الدخل والخرج كتلك التي تنتظر الكتابة إلى وسيط أو القراءة منه؛ بينما تستخدم المكتبة multiprocessing لدعم العمليات المستقلة التي تقيدها الحمولة العالية للمعالج وعلى التوازي، مثل العمليات الحسابية المعقدة.

ما الفرق بين التابعين()copy و ()deepcopy في المكتبة copy

توفر المكتبة copy في بايثون طريقتين لنسخ الكائنات، هما:

  1. النسخ السطحي Shallow copy باستخدام الدالة ()copy
  2. النسخ العميق Deep copy باستخدام الدالة ()deepcopy

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

على سبيل المثال لو عرفنا كائن قائمة original يحتوي على قائمتين داخلية، ونسخنا منه نسختين سطحية shallow_copy وعميقة deep_copy كما في المثال التالي:

import copy

# قائمة بداخلها قوائم 
original = [[1, 2, 3], [4, 5, 6]]

# نسخ سطحي
shallow_copy = copy.copy(original)

# نسخ عميق
deep_copy = copy.deepcopy(original)

# نعدل على أحد العناصر الداخلية في القائمة الأصلية
original[0][0] = 'X'

# نطبع النتائج
print("القائمة الأصلية:", original)
print("النسخة السطحية:", shallow_copy)
print("النسخة العميقة:", deep_copy)

فستتعدل النسخة السطحية مع هذا التغيير وتبقى النسخة العميقة على حالها كما يوضح الخرج التالي:

القائمة الأصلية: [['X', 2, 3], [4, 5, 6]]
النسخة السطحية: [['X', 2, 3], [4, 5, 6]]
النسخة العميقة: [[1, 2, 3], [4, 5, 6]]

ما أشهر المكتبات المستخدمة للعمل مع المصفوفات والحسابات الرياضية في بايثون

توفر بايثون العديد من المكتبات القوية التي تساعدنا للعمل مع المصفوفات وإجراء الحسابات الرياضية المتقدمة وأشهرها:

  • Numpy: تدعم المصفوفات متعددة الأبعاد، وتقدم مجموعةً كبيرة من الدوال الرياضية للعمل معها
  • SciPy: مبنية على أساس Numpy وتقدم وظائف علمية وتقنية أكبر مثل التكامل والاستيفاء
  • Pandas: مكتبة قوية لمعالجة وتحليل البيانات تقدم هياكل بيانات مثل إطار البيانات DataFrame لتسهيل التعامل مع الجداول والبيانات الضخمة
  • SymPy: مكتبة للرياضيات الرمزية تتيح إجراء عمليات جبرية مثل حل المعادلات والتفاضل والتكامل

ما أشهر مكتبات التعامل مع الرسوميات في بايثون

يمكن ذكر المكتبات الآتية:

  • Matplotlib: لرسم صور ثنائية البعد ساكنة أو تفاعلية، وتقديم تمثيل رسومي متحرك
  • Pillow: مكتبة لمعالجة الصور، تسمح بفتحها وتعديلها وحفظها
  • Plotly: مكتبة قوية لإنشاء رسوميات تفاعلية ثلاثية الأبعاد وواجهات عرض ديناميكية تصلح للويب والتطبيقات التفاعلية

ما المكتبات التي يشيع استخدامها في تطبيقات الرؤية الحاسوبية

أبرز هذه المكتبات هي:

  • OpenCV: مكتبة بايثون قوية لإنجاز مهام الرؤية الحاسوبية، مثل معالجة الصور وتطبيق فلاتر مختلفة عليها وتحويلها بين أنظمة لونية مختلفة، كما تفيد في تحليل الفيديو واكتشاف الأشياء Object Detection
  • SimpleCV: هي مكتبة سهلة الاستخدام للمبتدئين في الرؤية الحاسوبية، تتيح الوصول لأدوات معالجة الصور والكاميرا بسرعة وسهولة

ما أشهر مكتبات بايثون لبرمجة الأنظمة المدمجة

يمكن الإشارة إلى مكتبتي:

  • MicroPython: تتبع أسلوب خاص في بناء Python3 لبرمجة المتحكمات الصغرية Microcontroller وتجهيزات الأنظمة المدمجة مثل الحساسات
  • PySerial: تقدم وظائف للتخاطب مع واجهات التخاطب التسلسلية مثل UART باستخدام بايثون

أسئلة حول اطر العمل Frameworks

فيما يلي أبرز الأسئلة التي قد تطرح على المتقدمين لوظيفة مطوري بايثون في مقابلات التوظيف حول اُطر العمل Frameworks

ما هو إطار العمل Django وما هي أهم ميزاته

يُعَد إطار جانغو Django أحد أشهر أطر العمل الشاملة لتطوير تطبيقات الويب يوفر الكثير من الأدوات الجاهزة المضمّنة لتنفيذ الكثير من المهام، مثل إدارة المستخدمين، والتحقق من الصلاحيات، ونظام إدارة المحتوى، والتعامل مع قواعد البيانات؛ ويستخدم أساسًا لبناء التطبيقات المتوسطة إلى كبيرة.

ماهو إطار العمل Flask وما هي أهم ميزاته؟

يُعَد فلاسك Flask إطار خفيف ومرن يسمح بتطوير تطبيقات ويب بمرونة عالية، لكنه لا يتضمن الكثير من الأدوات الجاهزة مثل جانغو Django، ويتطلب خطوات إعداد وتهيئة أكثر منه، وهو يصلح لبناء تطبيقات ويب صغيرة إلى متوسطة، كما يستخدم في تقديم خدمات ويب مصغّرة Microservices بالإضافة إلى بناء واجهات برمجية.

ماهو إطار العمل FastAPI وما هي أهم ميزاته؟

يُعَد FastAPI إطار عمل حديثًا وخفيف الوزن لبناء واجهات برمجة التطبيقات APIs سريعة وقوية وعالية الأداء باستخدام لغة بايثون.؛ هو يعتمد كثيرًا على ميزتين قويتين في بايثون هما:

  • تحديد نوع البيانات المتوقعة للمتغيرات Type Hints
  • البرمجة غير المتزامنة Asynchronous Programming

ما هي اُطر العمل التي يشيع استخدامها في بناء الشبكات العصبونية وتعلم الآلة

يمكن ذكر الآتي:

  • TensorFlow: إطار عمل يُستخدم لبناء وتدريب الشبكات العصبونية
  • PyTorch: إطار عمل مفتوح المصدر يقدم أدوات لبناء وتدريب الشبكات العصبونية

ختامًا

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

المراجع

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...