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

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

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

المنصة

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

الدعم

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

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

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

ليه القائمة الافتراضية في بايثون بتفضل تتذكر القيم القديمة؟

مبتدئ26 يوليو 20263 دقائق قراءة
ليه القائمة الافتراضية في بايثون بتفضل تتذكر القيم القديمة؟

يتطلب هذا المقال مستوى: مبتدئ

ليه القائمة الافتراضية في بايثون بتفضل تتذكر القيم القديمة؟

لو كتبت دالة وحطيت قيمة افتراضية cart=[]، وبعد شوية لقيت القائمة بتتراكم فيها قيم من استدعاءات قديمة خالص، المشكلة مش في كودك ولا في بايثون. ده أشهر فخ في اللغة، وفهمه هيوفر عليك باجات بتظهر في الإنتاج بس مبتظهرش وانت بتجرب.

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

القيمة الافتراضية القابلة للتغيير (list أو dict أو set) بتتشارك بين كل استدعاءات الدالة. يعني نفس القائمة الواحدة بتفضل موجودة من أول لما عرّفت الدالة، وكل استدعاء بيضيف عليها بدل ما يبدأ من فاضي.

مثال بسيط الأول

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

ده بالظبط اللي بيحصل مع القائمة الافتراضية. الكيس هو القائمة، والزبون هو الاستدعاء. لأن الكيس واحد مشترك، الحاجات بتتراكم فيه.

الشرح العلمي: القيمة الافتراضية بتتقيّم مرة واحدة

في بايثون، التعبير اللي بتحطه كقيمة افتراضية بيتنفّذ مرة واحدة بس، وقت تعريف الدالة، مش وقت كل استدعاء. النتيجة بتتخزن جوا كائن الدالة نفسه في السمة __defaults__. فلو القيمة دي كائن قابل للتغيير زي []، كل الاستدعاءات بتشير لنفس الكائن، وأي append بيفضل محفوظ.

Python
def add_item(item, cart=[]):
    cart.append(item)
    return cart

print(add_item("تفاحة"))   # ['تفاحة']
print(add_item("موزة"))    # ['تفاحة', 'موزة']  ← مفاجأة، مش ['موزة']
print(add_item("خوخة"))    # ['تفاحة', 'موزة', 'خوخة']

# الدليل: القائمة متخزنة جوا الدالة نفسها
print(add_item.__defaults__)  # (['تفاحة', 'موزة', 'خوخة'],)

لاحظ إن الاستدعاء التاني بدأ من ['تفاحة'] مش من قائمة فاضية. ده لأن cart هي نفس الكائن في كل مرة.

سيناريو واقعي بالأرقام

افترض عندك دالة build_response(item, log=[]) في خدمة ويب بتخدم 500 طلب في الدقيقة. مع كل طلب بتعمل log.append(...). لأن الـ log افتراضي ومشترك، بعد ساعة واحدة هيبقى فيه حوالي 30 ألف عنصر متراكم من كل المستخدمين مع بعض، وممكن بيانات مستخدم تتسرب لرد مستخدم تاني. الذاكرة بتكبر خطيًا وميتنضّفش أبدًا، وده بالظبط نوع الباج اللي بيعدي من الاختبارات وبيقع في الإنتاج.

الحل: استخدم None كقيمة افتراضية

القيمة None ثابتة (immutable)، فآمنة كقيمة افتراضية. بعدها تعمل قائمة جديدة جوا الدالة لو المستخدم مبعتش حاجة.

Python
def add_item(item, cart=None):
    if cart is None:
        cart = []
    cart.append(item)
    return cart

print(add_item("تفاحة"))   # ['تفاحة']
print(add_item("موزة"))    # ['موزة']  ← قائمة جديدة كل مرة

الـ trade-off

بتكسب صحة سلوك مضمونة: كل استدعاء يبدأ نظيف. بتخسر سطرين زيادة وفحص is None في كل استدعاء، وده تكلفته نانوثواني ولا يُذكر عمليًا. المقايضة في صالحك دايمًا هنا.

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

الفخ ده بيخص القيم القابلة للتغيير بس: list وdict وset. أما القيم الثابتة زي int وstr وtuple وNone وfrozenset فآمنة تمامًا كقيم افتراضية، لأنها مش بتتعدّل في مكانها. كمان في حالة نادرة بتستغل السلوك ده عن قصد لعمل كاش (cache) بيعيش بين الاستدعاءات، لكن ساعتها خليها واضحة ومقصودة بتعليق، مش صدفة.

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

افتح كودك ودوّر على أي تعريف دالة فيه =[] أو ={} في قائمة الوسائط. لو لقيت واحدة، حوّلها لنمط None فورًا. أمر سريع في الطرفية يلاقيلك المشبوهين: grep -rn "def .*=\[\]" . ثم كرّرها لـ ={}.

المصادر

  • Python Docs — Programming FAQ: "Why are default values shared between objects?": https://docs.python.org/3/faq/programming.html#why-are-default-values-shared-between-objects
  • Python Docs — Tutorial, Default Argument Values ("The default value is evaluated only once"): https://docs.python.org/3/tutorial/controlflow.html#default-argument-values
  • The Hitchhiker's Guide to Python — Common Gotchas: Mutable Default Arguments: https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments

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

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

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