المستوى المطلوب: مبتدئ. المقال ده مكتوب لحد لسه في أول طريقه مع بايثون. هتفهم فكرة النسخ من الأول بمثال بسيط، وبعد كده بالتفصيل العلمي الدقيق.
لو عدّلت "نسخة" من قائمة في بايثون ولقيت القائمة الأصلية اتغيّرت معاها، انت مش لاقي باج غريب. ده سلوك متوقّع اسمه النسخ السطحي، وفهمه هيوفّر عليك ساعات تصحيح.
النسخ السطحي والعميق في بايثون: ليه تعديل النسخة بيغيّر الأصل؟
المشكلة باختصار
في بايثون ما فيش أمر واحد اسمه "انسخ". فيه طريقتين، وكل واحدة بتعمل حاجة مختلفة تمامًا. لو خلطت بينهم، تعديل بسيط في مكان ممكن يغيّر بيانات في مكان تاني من غير ما تقصد. ده بالظبط اللي بيوقّع المبتدئين.
الفكرة بمثال بسيط
تخيّل عندك ملف على Google Docs. لو بعت "اللينك" لصاحبك، هو مأخدش نسخة، هو فتح نفس الملف. أي تعديل منه بيظهر عندك على طول، وأي تعديل منك بيوصله. ده هو النسخ السطحي: انت نسخت "الإشارة" للملف، مش الملف نفسه.
لكن لو ضغطت "Download a copy" وبعتله الملف المحمّل، هو بقى عنده ملف مستقل بالكامل. يعدّل زي ما هو عايز، وحاجة عندك متتغيّرش. ده النسخ العميق: نسخت المحتوى كله، مش الإشارة.
التفسير العلمي: الإشارة مش المحتوى
القوائم والقواميس في بايثون كائنات قابلة للتغيير (mutable) بتتخزّن في الذاكرة، والمتغيّر مجرد "إشارة" (reference) بتشاور على مكانها. لما تكتب b = a، انت مبتنسخش القائمة، انت بتنسخ الإشارة بس. فـ a وb بيشاوروا على نفس الكائن.
الطريقة a.copy() أو a[:] بتعمل نسخة سطحية: بتبني قائمة خارجية جديدة، بس العناصر اللي جواها لسه بتشاور على نفس الكائنات الأصلية. أما copy.deepcopy(a) بتنزل جوه كل مستوى وتكرّر كل كائن، فتطلع نسخة مستقلة تمامًا.
مثال شغّال تجرّبه دلوقتي
import copy
a = [[1, 2], 3]
b = a.copy() # نسخة سطحية: القائمة الخارجية بس هي الجديدة
b[0].append(99)
print(a) # [[1, 2, 99], 3] ← الأصل اتغيّر!
c = copy.deepcopy(a) # نسخة عميقة: كل حاجة جوه اتكرّرت
c[0].append(1000)
print(a) # [[1, 2, 99], 3] ← الأصل زي ما هو
ركز في أول سطر طباعة. انت عدّلت b، بس a اتغيّرت. السبب إن b[0] وa[0] نفس القائمة الداخلية بالظبط، مشتركين في نفس المكان في الذاكرة.
سيناريو واقعي
افرض عندك قاموس إعدادات افتراضية بتوزّعه على 500 عميل، وكل عميل بتديله default_config.copy() علشان يعدّل على راحته. لأن دي نسخة سطحية، أول عميل يعدّل قيمة متداخلة (list جوه الـ dict مثلًا) هيغيّرها عند الـ 499 الباقيين كمان. باج زي ده بيظهر في الإنتاج بعد أسابيع، ويكون صعب توصله لأنه "بيشتغل على جهازك".