انتقل إلى المحتوى الرئيسي

الوحدة 2 — هياكل البيانات والاشتمالات

أربعة هياكل أصلية تحمل كلّ عمل التحضير في بايثون: القائمة والقاموس والصفّ (tuple) والمجموعة (set). معرفة أيّها تختار — وكيف تحوّل أحدها إلى آخر في سطر واحد — هي المهارة التي تفصل الكود المتعِب عن الكود السلس. وهي أيضاً الرياضة الذهنية التي ستجعل pandas طبيعياً.

القائمة: التسلسل متعدّد الأغراض

مرتّبة، قابلة للتعديل، غير متجانسة عند الحاجة (لكن لا تفعل ذلك بلا سبب):

scores = [0.91, 0.87, 0.94, 0.79]
scores.append(0.88) # إضافة في النهاية
scores[0] # العنصر الأول
scores[-1] # الأخير
len(scores), sum(scores) # 5, 4.39
sorted(scores, reverse=True) # قائمة جديدة مرتّبة

طريقتان تلتبسان: sorted(list) تعيد نسخة مرتّبة؛ وlist.sort() ترتّب في المكان وتعيد None — مصدر خطأ كلاسيكي (result = list.sort() تعطي None).

الترتيب بمفتاح يُستعمل باستمرار:

models = [("baseline", 0.71), ("forest", 0.86), ("boosting", 0.89)]
best = max(models, key=lambda m: m[1]) # ('boosting', 0.89)

القاموس: من مفاتيح إلى قيم

أهمّ هيكل في بايثون — وأُطُر بيانات pandas امتداد مفاهيمي له. الوصول بالمفتاح في زمن ثابت:

config = {"model": "xgboost", "depth": 6, "threshold": 0.5}
config["depth"] # 6 — يرفع KeyError إن غاب
config.get("cache", False) # False — قيمة افتراضية إن غاب
config["threshold"] = 0.4 # تعديل

المرورات الثلاثة:

for key in config:                    # المفاتيح
for value in config.values(): # القيم
for key, value in config.items(): # الاثنان — الأكثر شيوعاً

اصطلاح العدّ، الحاضر في كلّ استكشاف بيانات:

counts = {}
for category in category_column:
counts[category] = counts.get(category, 0) + 1
# أو في سطر واحد: from collections import Counter ثم Counter(category_column)

الصفّ والمجموعة: المتخصّصان

الصفّ (tuple) تسلسل غير قابل للتعديل: ما جُمِّد لا يُعدَّل بالخطأ. يُستعمل لمجموعات القيم المتلازمة — إحداثيات، أزواج (اسم، نتيجة) — وللقيم المرجعة المتعدّدة:

def evaluate(y_true, y_pred):
return precision, recall # يعيد صفّاً

precision, recall = evaluate(yt, yp) # تفكيك (unpacking)

المجموعة (set) تخزّن عناصر فريدة بلا ترتيب مع اختبار انتماء فوري. استعمالان يوميان في البيانات:

duplicates = len(ids) - len(set(ids))            # عدّ التكرارات

expected_columns = {"id", "amount", "date"}
missing = expected_columns - set(df_columns) # فرق مجموعات

اختبار x in a_set يجري في زمن ثابت، مقابل مسح كامل لـx in a_list — وعلى ملايين العناصر يُقاس الفرق بالدقائق.

الاشتمالات: التحويل في سطر واحد

اشتمال القائمة هو أكثر تراكيب بايثون اصطلاحيةً: تحويل تسلسل وترشيحه بلا حلقة صريحة.

# تحويل
amounts_incl_tax = [a * 1.15 for a in amounts]

# ترشيح
valid = [x for x in measures if x is not None]

# الاثنان معاً
error_logs = [l.strip() for l in lines if "ERROR" in l]

النمط العامّ: [تعبير for عنصر in تسلسل if شرط]. وله صيغتا قاموس ومجموعة:

price_by_id = {p["id"]: p["price"] for p in products}   # قاموس
extensions = {f.split(".")[-1] for f in files} # مجموعة
حدّ المقروئية

يتفوّق الاشتمال على الحلقة المكافئة ما دام يتّسع بوضوح في سطر واحد، بشرط if واحد على الأكثر. الاشتمال المتداخل على ثلاثة مستويات حلقةٌ متنكّرة في هيئة لغز: اكتب الحلقة. المعيار هو زميل يعيد القراءة، لا الإيجاز.

نمط التفكير هذا — «طبّق هذا التعبير على كلّ عنصر، واحتفظ بما يجتاز المرشّح» — هو بالضبط عقلية NumPy وpandas. [a * 1.15 for a in amounts] ستصبح amounts * 1.15 في الوحدة 4؛ والمرشّح سيصبح قناعاً منطقياً. الاشتمالات مدرسة التوجيه.

النسخ والمراجع: الفخّ البنيوي

متغيّرات بايثون مراجع. الإسناد لا ينسخ:

a = [1, 2, 3]
b = a # b يشير إلى القائمة نفسها
b.append(4)
a # [1, 2, 3, 4] — مفاجأة

للنسخ فعلاً: b = a.copy() (نسخ سطحي) أو copy.deepcopy(a) للهياكل المتداخلة. سيعود هذا السلوك في pandas، حيث تمييز العرض/النسخة في أُطُر البيانات وراء تحذير شهير (SettingWithCopyWarning، الوحدة 6).

نتيجة لازمة: لا تستخدم قائمة قيمةً افتراضية لوسيط أبداً (def f(x, acc=[])) — تُنشأ القائمة مرّة واحدة وتُشارَك بين الاستدعاءات. الاصطلاح الصحيح: acc=None ثم if acc is None: acc = [].

الخلاصة

  • القائمة للتسلسلات المرتّبة، والقاموس لربط مفتاح ← قيمة، والصفّ للمجموعات المجمّدة، والمجموعة للتفرّد والانتماء السريع.
  • sorted() تعيد، و.sort() تعدّل في المكان؛ الترتيب بمفتاح عبر key=.
  • الاشتمالات تحوّل وترشّح في سطر واحد — وتدرّب على عادة التوجيه؛ بعد if واحد، عُد إلى الحلقة.
  • المتغيّرات مراجع: .copy() للنسخ، ولا شيء قابلاً للتعديل قيمةً افتراضية لوسيط.

الوحدة التالية: الدوالّ وتنظيم الكود — الانتقال من النصّ المؤقّت إلى الوحدة القابلة لإعادة الاستخدام.