القوائم المتقدمة والصفوف
في الدرس السابق، تعلمنا عمليات القوائم الأساسية. الآن دعنا نستكشف بعض المفاهيم الأكثر "بايثونية" — روعة القوائم الشاملة (سطر واحد يفعل عمل خمسة)، و الصفوف ("القائمة غير القابلة للتعديل") ومتى تستخدمها. بعد هذا، سيبدو كودك أكثر فأكثر كمبرمج بايثون حقيقي.
1. الترتيب المتقدم للقوائم
في الدرس 10، تعلمنا أساسيات sort() و sorted(). كما يقبلان معامل key لتحديد "أي قاعدة للترتيب."
# الترتيب حسب طول السلسلة النصية
words = ["Python", "Java", "JavaScript", "C", "Go"]
sorted_by_len = sorted(words, key=len)
print(sorted_by_len) # ['C', 'Go', 'Java', 'Python', 'JavaScript']
# الترتيب حسب آخر حرف
words = ["banana", "apple", "cherry", "date"]
sorted_by_last = sorted(words, key=lambda w: w[-1])
print(sorted_by_last) # ['banana', 'date', 'apple', 'cherry']
# الترتيب حسب عنصر معين في صف
scores = [("Zhang San", 85), ("Li Si", 92), ("Wang Wu", 78)]
sorted_scores = sorted(scores, key=lambda s: s[1], reverse=True)
print(sorted_scores) # [('Li Si', 92), ('Zhang San', 85), ('Wang Wu', 78)]
key مفيد جداً — يمكنك تمرير أي دالة تأخذ وسيطة واحدة وتُرجع قيمة. sorted() ستستخدم هذه القيمة المعادة للترتيب. lambda أعلاه هي دالة مجهولة، سنغطيها بالتفصيل لاحقاً.
مثال: إنشاء لوحة صدارة (الصعوبة ⭐⭐)
# لوحة صدارة اللعبة — ترتيب حسب النقاط تنازلياً
players = [
("Player 1", 3500),
("Player 2", 5200),
("Player 3", 2800),
("Player 4", 4100),
]
# ترتيب حسب النقاط تنازلياً
ranked = sorted(players, key=lambda p: p[1], reverse=True)
print("=== Leaderboard ===")
for i, (name, score) in enumerate(ranked, 1):
print(f"#{i}: {name} — {score} points")
المخرجات:
=== Leaderboard ===
#1: Player 2 — 5200 points
#2: Player 4 — 4100 points
#3: Player 1 — 3500 points
#4: Player 3 — 2800 points
2. القوائم الشاملة
القوائم الشاملة هي واحدة من أكثر ميزات بايثون المحبوبة — إنشاء قائمة جديدة بسطر واحد من الكود.
الصيغة الأساسية
[expression for variable in iterable]
الطريقة التقليدية مقابل الشاملة
# إنشاء مربعات الأرقام 0~9 — الطريقة التقليدية
squares = []
for i in range(10):
squares.append(i ** 2)
print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# باستخدام القائمة الشاملة — سطر واحد
squares = [i ** 2 for i in range(10)]
print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
القائمة الشاملة مع الشروط
# فلترة الأرقام الزوجية
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = [n for n in numbers if n % 2 == 0]
print(evens) # [2, 4, 6, 8, 10]
# تحويل السلاسل النصية إلى أحرف كبيرة
words = ["hello", "world", "python"]
upper_words = [w.upper() for w in words]
print(upper_words) # ['HELLO', 'WORLD', 'PYTHON']
# فلترة الكلمات بطول >= 5
words = ["cat", "elephant", "dog", "giraffe", "ant"]
long_words = [w for w in words if len(w) >= 5]
print(long_words) # ['elephant', 'giraffe']
مثال: معالجة البيانات (الصعوبة ⭐⭐)
# البيانات الخام — قد تحتوي على قيم فارغة ومسافات إضافية
raw_data = [" Zhang San ", "", " Li Si ", " Wang Wu ", "", " Zhao Liu "]
# تنظيف بخطوة واحدة باستخدام الشاملة: strip + فلترة الفارغ
cleaned = [name.strip() for name in raw_data if name.strip()]
print(cleaned) # ['Zhang San', 'Li Si', 'Wang Wu', 'Zhao Liu']
# معالجة رقمية
temps_c = [0, 10, 20, 30, 40]
temps_f = [c * 9 / 5 + 32 for c in temps_c]
print(temps_f) # [32.0, 50.0, 68.0, 86.0, 104.0]
3. ما هو الصف (Tuple)
يُعرّف الصف بـ الأقواس (). إنه مشابه للقوائم، لكن مع فرق رئيسي — الصفوف غير قابلة للتعديل؛ بمجرد إنشائها، لا يمكن تعديلها.
# تعريف الصفوف
point = (3, 5)
color = (255, 0, 0)
empty = ()
single = (42,) # ملاحظة: الصفوف ذات العنصر الواحد يجب أن تحتوي على فاصلة!
print(point) # (3, 5)
print(type(point)) # <class 'tuple'>
الصفوف غير قابلة للتعديل
point = (3, 5)
# point[0] = 10 ← خطأ! لا يمكن تعديل الصفوف
print(point[0]) # 3 — يمكن القراءة، لا يمكن التعديل
لماذا نحتاج الصفوف
عدم القابلية للتعديل يجلب ميزتين:
1. يمكن استخدامها كمفاتيح قاموس (القوائم لا يمكن، لأنها قابلة للتعديل)
# الصفوف يمكن أن تكون مفاتيح قاموس
locations = {
(35.68, 139.76): "Tokyo",
(31.23, 121.47): "Shanghai",
}
print(locations[(35.68, 139.76)]) # Tokyo
# القوائم لا يمكن أن تكون مفاتيح
# d = {[1, 2]: "error"} ← سيُسبب خطأ!
2. تمثل بيانات لا ينبغي تعديلها
# الإحداثيات، الألوان، الإعدادات — البيانات "غير المتغيرة" مناسبة للصفوف
RGB_RED = (255, 0, 0) # قيمة الأحمر لا ينبغي تعديلها
DEFAULT_CONFIG = ("localhost", 8080, "admin")
4. تفكيك الصفوف
واحدة من أكثر ميزات الصفوف فائدة — التفكيك، تعيين عناصر الصف مباشرة إلى متغيرات متعددة:
point = (3, 5)
x, y = point # تفكيك
print(x) # 3
print(y) # 5
# تبديل المتغيرات — أساساً تفكيك صف
a, b = 10, 20
a, b = b, a # الجانب الأيمن يُنشئ صفاً (20, 10)، ثم يُفكّك
print(a, b) # 20 10
# دالة تُرجع قيماً متعددة
def get_min_max(numbers):
return min(numbers), max(numbers)
result = get_min_max([3, 1, 4, 1, 5])
print(result) # (1, 5)
low, high = get_min_max([3, 1, 4, 1, 5])
print(f"Min: {low}, Max: {high}") # Min: 1, Max: 5
استخدام _ لتجاهل القيم غير المرغوب فيها
data = ("Zhang San", 25, "Beijing", "Engineer")
name, _, city, _ = data # استخدم _ لتعني "لا يهمني هذا"
print(f"{name} lives in {city}") # Zhang San lives in Beijing
مثال: حساب الإحداثيات (الصعوبة ⭐⭐)
# عرّف نقطتين
p1 = (1, 2)
p2 = (4, 6)
# فكّك لحساب المسافة
x1, y1 = p1
x2, y2 = p2
distance = ((x2 - x1) 2 + (y2 - y1) 2) ** 0.5
print(f"Distance: {distance:.2f}") # 5.00
# استخدام enumerate للتكرار المفهرس
fruits = ["apple", "banana", "orange"]
for i, fruit in enumerate(fruits, 1):
print(f"{i}. {fruit}")
المخرجات:
Distance: 5.00
1. apple
2. banana
3. orange
5. دليل اختيار القائمة مقابل الصف
| الميزة | القائمة | الصف |
|---|---|---|
| قابل للتعديل | ✅ يمكن إضافة/حذف/تغيير | ❌ غير قابل للتعديل |
| السرعة | أبطأ قليلاً | أسرع قليلاً |
| الذاكرة | أكبر قليلاً | أصغر قليلاً |
| يمكن أن يكون مفتاح قاموس | ❌ | ✅ |
| حالة الاستخدام | بيانات تُعدّل frequently | بيانات ثابتة غير متغيرة |
| الاستخدامات النموذجية | عربة تسوق، قائمة مهام، بيانات ديناميكية | إحداثيات، ألوان، قيم إرجاع الدوال |
حالات الاستخدام الشائعة
- ترتيب لوحة الصدارة: استخدم
sorted(key=lambda ...)لترتيب البيانات المعقدة بقواعد مخصصة. - تنظيف البيانات: استخدم القوائم الشاملة لفلترة وتحويل وتنظيف البيانات في سطر واحد.
- الإحداثيات والهندسة: استخدم الصفوف للنقاط والمستطيلات وألوان RGB، إلخ.
- دوال الإرجاع المتعدد: الدوال تُرجع صفوف
(min, max)؛ المستخدمون يفكّكون مباشرة. - التكرار المعدود:
enumerate()يُرجع صفوف(index, element)، تُفكّك مباشرة.
❓ أسئلة شائعة
(42) و (42,)؟ ج:الأقواس في (42) تُفسر كتجميع رياضي، وليس صفاً — type((42)) يُرجع <class 'int'>. (42,) هو صف. لذا الصفوف ذات العنصر الواحد يجب أن تتضمن فاصلة: (42,).
س:كيف يعمل معامل key في sorted()؟ أعط مثالاً عملياً. ج:السيناريو الأكثر شيوعاً هو الترتيب حسب سمة معينة. مثلاً، الترتيب حسب طول السلسلة: sorted(words, key=len). الترتيب حسب العنصر الثاني من الصفوف في قائمة: sorted(data, key=lambda x: x[1]). الترتيب حسب قيم القاموس: sorted(dict.items(), key=lambda x: x[1]). المفتاح هو فهم أن key يقبل دالة تُرسم كل عنصر إلى مفتاح ترتيب.📖 ملخص
- معامل
keyفيsorted()يحدد قواعد الترتيب؛ مدمجاً معlambdaفهو مرن جداً - القائمة الشاملة
[expression for variable in iterable if condition]تنشئ قائمة جديدة في سطر واحد - الصفوف تستخدم صيغة
()، غير قابلة للتعديل، ويمكن استخدامها كمفاتيح قاموس - الصفوف ذات العنصر الواحد يجب أن تحتوي على فاصلة:
(42,)— وإلا فهي عدد صحيح - تفكيك الصف يُسند قيماً متعددة لمتغيرات متعددة؛ تبديل المتغيرات يستفيد من هذا
- القوائم للبيانات القابلة للتعديل، الصفوف للبيانات الثابتة
📝 تمارين
-
مبتدئ (الصعوبة ⭐): استخدم قائمة شاملة لإنشاء مربعات جميع الأرقام بين 1 و 20 القابلة للقسمة على 3. تلميح:
[expression for n in range(...) if condition] -
متوسط (الصعوبة ⭐⭐): بالنظر إلى قائمة أسماء
names = [" alice ", "BOB", " Charlie", " david "]، استخدم قائمة شاملة في خطوة واحدة: strip للمسافات + كتابة أول حرف كبير وباقي الأحرف صغيرة. تلميح:strip()للمسافات،title()أوcapitalize()لحالة الأحرف. -
متقدم (الصعوبة ⭐⭐⭐): اكتب دالة
analyze_numbers(*args)تقبل أي عدد من الوسائط الرقمية وتُرجع صفاً(max, min, average, count_above_average). تلميح: استخدم*argsللوسائط متغيرة الطول؛ استخدم قائمة شاملة لحساب القيم فوق المتوسط.



