أحمد حايس
الرئيسيةمن أناالدوراتالمدونةالمناهج والباقات
أحمد حايس

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

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

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • المناهج والباقات
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع
محتاج مسار سريع؟
ابدأ من الدوراتتواصل معناالأسئلة الشائعة

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالمناهجالمدونةالدخول
البرمجة بالعربي

Pass by Value و Pass by Reference للمبتدئ: ليه دالة بتغيّر الـ list من ورا ضهرك

مبتدئ١٦ يونيو ٢٠٢٦4 دقائق قراءة
Pass by Value و Pass by Reference للمبتدئ: ليه دالة بتغيّر الـ list من ورا ضهرك

المستوى المطلوب لقراءة هذا المقال: مبتدئ. لو لسه بتتعلم الدوال (functions) والمتغيرات، المقال ده هيوفّر عليك ساعات تدوير في الأخطاء. هتعرف بالظبط ليه دالة بتعدّل على بياناتك من غير ما تطلب منها كده، وإزاي توقف السلوك ده وقت ما تحب.

الخلاصة الأول: لما تبعت رقم أو نص لدالة، الدالة بتشتغل على نسخة، وبياناتك الأصلية بتفضل سليمة. لكن لما تبعت list أو dictionary، الدالة بتشتغل على نفس الشيء الأصلي، فأي تعديل جوّاها بيظهر برّاها. ده الفرق اللي بيوقّع المبتدئين كل يوم.

المشكلة باختصار

تخيّل إنك كاتب دالة بتضيف عنصر على list علشان تطبع النتيجة بس. بعد ما الدالة تخلص، تلاقي الـ list الأصلية اتغيّرت كمان. انت معملتش return، ومع ذلك البيانات اتبدّلت. الموقف ده مش غلطة في اللغة، ده اسمه التعديل عبر المرجع (pass by reference)، وفهمه بيفرق بين كود بتثق فيه وكود بيفاجئك.

شاشة كود برمجي ملوّن تعرض دالة بتعدّل على مصفوفة، ترمز لمفهوم تمرير القيمة مقابل المرجع في الذاكرة

المفهوم بمثال: الورقة والأوضة

تخيّل عندك أوضة فيها صندوق. القيمة (value) معناها إنك بتدّي صاحبك صورة من اللي جوّا الصندوق على ورقة. لو هو شخبط على الورقة، صندوقك مش هيتأثر، لأنه معاه نسخة بس.

المرجع (reference) معناه إنك بتدّي صاحبك مفتاح الأوضة نفسها. لو دخل وغيّر اللي في الصندوق، هتلاقي التغيير لما تدخل انت، لأنكم الاتنين بتفتحوا نفس الأوضة بنفس المفتاح.

دلوقتي بالشكل العلمي: المتغيّر في الذاكرة بيشاور (points) على عنوان. مع الأنواع البسيطة زي الأرقام والنصوص، الدالة بتاخد نسخة من القيمة. مع الأنواع المركّبة زي list و dict، الدالة بتاخد نسخة من العنوان نفسه، فالاتنين بيشاوروا على نفس الكائن (object) في الذاكرة. تعديل محتوى الكائن بيبان عند الطرفين.

كود شغّال يوريك الفرق

الكود ده اتجرّب على Python 3.13. لاحظ إن الرقم رجع زي ما هو، لكن الـ list اتغيّرت:

Python
# رقم: بيتبعت بالقيمة، الأصل ما بيتأثرش
def add_ten(n):
    n = n + 10
    return n

x = 5
add_ten(x)
print(x)          # 5  ← الأصل سليم

# list: بتتبعت بالمرجع، الأصل بيتأثر
def append_item(items):
    items.append(99)   # تعديل في نفس الكائن

my_list = [1, 2, 3]
append_item(my_list)
print(my_list)    # [1, 2, 3, 99]  ← اتغيّرت من غير return

نفس السلوك في JavaScript: الـ primitives (number, string, boolean) بالقيمة، والـ objects والـ arrays بالمرجع:

JavaScript
function pushItem(arr) {
  arr.push(99);   // نفس المصفوفة الأصلية
}
const list = [1, 2, 3];
pushItem(list);
console.log(list); // [1, 2, 3, 99]
صناديق تخزين متشابهة عليها ملصقات أسماء، تمثّل المتغيرات اللي بتشاور على نفس عنوان الذاكرة

الحل: انسخ قبل ما تعدّل

لو عايز الدالة تشتغل من غير ما تلمس الأصل، اعمل نسخة جوّاها. في Python فيه طريقتين، وكل واحدة بتمنها:

  1. نسخة سطحية (shallow copy): بـ items[:] أو list(items). بتنسخ المستوى الأول بس. سريعة، بس لو جوّا الـ list فيه lists تانية، دي لسه بتتشارك.
  2. نسخة عميقة (deep copy): بـ copy.deepcopy(items). بتنسخ كل حاجة لآخر مستوى. آمنة تمامًا، بس أبطأ وبتاكل ذاكرة أكتر.
Python
import copy

def append_safe(items):
    local = items[:]      # نسخة سطحية
    local.append(99)
    return local

my_list = [1, 2, 3]
result = append_safe(my_list)
print(my_list)   # [1, 2, 3]      ← الأصل اتحمى
print(result)    # [1, 2, 3, 99]  ← التعديل في النسخة

الـ trade-offs اللي لازم تعرفها

التعديل عبر المرجع مش عيب، ده ميزة في حالات. لكن كل اختيار له ثمن:

  • التعديل المباشر (in-place): بتكسب سرعة وذاكرة أقل، لأنك مش بتكرّر البيانات. بتخسر الأمان: أي حد بيستدعي الدالة ممكن يتفاجئ. مناسب لو الـ list صغيرة وانت اللي ماسك الكود كله.
  • النسخة قبل التعديل: بتكسب أمان ووضوح، الدالة بقت pure ومش بتأثر على برّا. بتخسر شوية أداء وذاكرة. لو الـ list فيها مليون عنصر، النسخة العميقة ممكن تاخد وقت محسوس.

الافتراض هنا إنك شغّال على بيانات صغيرة لمتوسطة (آلاف العناصر مش ملايين). فوق كده، اقيس الفرق بنفسك قبل ما تقرر تنسخ في كل نداء.

متى متشغلش بالك

لو الدالة بتقرأ البيانات بس وما بتعدّلش (زي sum أو len أو طباعة)، مفيش أي خطر، وما تحتاجش تنسخ حاجة. كمان لو الكائن غير قابل للتعديل أصلًا زي الـ tuple في Python أو الـ string، اللغة بتحميك تلقائيًا، فأي محاولة تعديل بتطلّع خطأ أو بتعمل كائن جديد. النسخ الزيادة في الحالات دي بياكل ذاكرة من غير فايدة.

الخطوة التالية

دلوقتي افتح أي دالة عندك بتاخد list أو dict كـ parameter. لو الدالة بتعدّل فيها وانت مش قاصد ده يطلع برّا، ضيف نسخة في أول سطر: items = items[:]. شغّل الكود وشوف هل النتيجة بقت متوقّعة. لو لسه بتتفاجئ، غالبًا فيه list جوّا list ومحتاج deepcopy.

المصادر

  • توثيق Python الرسمي — قسم نموذج التنفيذ والدوال (docs.python.org).
  • وحدة copy في Python: copy() و deepcopy() (docs.python.org/3/library/copy.html).
  • MDN Web Docs — Primitive vs Object، وكيفية تمرير الوسائط في JavaScript (developer.mozilla.org).
  • Real Python — Passing Mutable Objects and Side Effects.

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة