Why Python? — ليه Python للـ Backend؟
إعداد البيئة خطوة خطوة
Readable (مقروءة): الكود بيتكلم بلغة قريبة من اللغة الإنجليزية العادية — تقدر تركز على المنطق بدل الأقواس والفواصل.
Productive (إنتاجية عالية): تقدر تبني Prototype بسرعة وتختبر الأفكار في وقت أقل بكتير من لغات تانية.
Ecosystem ضخم: عندها Django و Flask و FastAPI وآلاف المكتبات الجاهزة.
مناسبة للتعليم: بتخلي الطالب يتعلم المنطق البرمجي بسهولة قبل ما يتعامل مع تعقيدات لغات تانية.
"Add Python to PATH" — من غير ده الـ Terminal مش هيعرف يشغل Python!python --version أو py --version — لو ظهر رقم الإصدار، كل حاجة تمام!python_backend_course، اعمل ملف first_program.py، واكتب print("Hello!") وشغّله من الـ Terminal بالأمر: python first_program.pyrunserver وmigrate هتتنفذ منه كمان.Variables & Data Types — المتغيرات وأنواع البيانات
أساس أي برنامج — إزاي بنحفظ المعلومات؟
المتغير (Variable) زي الصندوق المتسمّي — بنحط فيه قيمة ونستخدمها بعدين. علامة = هي الـ Assignment Operator، يعني "حط القيمة دي في المتغير ده".
student_name = "Mona" # str — نص
age = 20 # int — رقم صحيح
gpa = 3.8 # float — رقم عشري
is_active = True # bool — صح أو غلط
course = "Backend Python"
print(student_name)
print(type(age)) # بيطبع: <class 'int'>
type(): بتعرفك نوع المتغير — استخدمها لما الكود بيطلع نتيجة غريبة. كتير من الأخطاء بتيجي من إنك مش عارف النوع الحقيقي للقيمة.✅ صح
student_name = "Ali"
score1 = 90
_private = "hidden"
myVar = 5❌ غلط
1score = 90 # يبدأ برقم ❌
my-var = 5 # فيه شرطة ❌
my var = "x" # فيه مسافة ❌
for = 1 # كلمة محجوزة ❌my-var هو اسم غلط في Python — الشرطة العادية - مش مسموح بيها في أسماء المتغيرات. استخدم الشرطة السفلية my_var بدلها ✅| النوع | الاسم | مثال | الاستخدام |
|---|---|---|---|
str | String | "Ali" | أسماء، ايميلات، رسائل، أي نص |
int | Integer | 20 | أعداد صحيحة زي السن والعدد |
float | Float | 3.75 | أرقام عشرية زي الـ GPA والسعر |
bool | Boolean | True / False | حالات زي logged_in, is_admin |
/ في Python دايماً بترجع float. يعني 10 / 2 = 5.0 مش 5! لو عايز عدد صحيح استخدم // (Integer Division).f"اسمي {name} وسني {age}" — أوضح وأنضف من الـ Concatenation بـ +.name = "Sara"
city = "Cairo"
# الطريقة القديمة (Concatenation)
print("اسمي " + name + " من " + city)
# الطريقة الأحسن (f-string) ✅
print(f"اسمي {name} من {city}")
Input / Output & Comments — الإدخال والإخراج والتعليقات
إزاي البرنامج يتكلم مع المستخدم
دالة input() بتوقف البرنامج وتستنى المستخدم يكتب حاجة. النقطة المهمة: input() دايماً بترجع String، حتى لو المستخدم كتب رقم!
name = input("اكتب اسمك: ")
print(f"أهلاً {name}!")عشان تحول الـ String الجاي من input() لرقم، لازم تعمل Type Casting. استخدم int() للأعداد الصحيحة وfloat() للعشرية.
# int Casting
age = int(input("السن: "))
# float Casting
price = float(input("السعر: "))
print(age + 1) # شغال ✅التعليق بيبدأ بـ # وبيتجاهله Python عند التشغيل. استخدمه عشان تشرح النية وراء الكود — مش عشان تشرح الواضح.
❌ تعليق مش مفيد
# بطبع الاسم
print(name)✅ تعليق مفيد
# input() بترجع string
# لازم نحوّل لـ int للحساب
age = int(input("السن: "))Operators & Conditions — العمليات والشروط
إزاي البرنامج يفكر ويتخذ قرارات؟
| الرمز | الاسم | مثال | النتيجة |
|---|---|---|---|
+ | Addition | 10 + 3 | 13 |
- | Subtraction | 10 - 3 | 7 |
* | Multiplication | 10 * 3 | 30 |
/ | Division | 10 / 3 | 3.333... (float!) |
// | Integer Division | 10 // 3 | 3 (بدون كسر) |
% | Modulus (باقي القسمة) | 10 % 3 | 1 |
** | Exponent (الأسس) | 2 ** 3 | 8 |
/ دايماً تطلع float حتى لو الناتج عدد صحيح. 10 / 2 = 5.0 وليس 5!Comparison Operators — نتيجتهم دايماً True أو False:
score = 75
print(score == 75) # True
print(score != 100) # True
print(score > 50) # True
print(score <= 70) # FalseLogical Operators — لدمج أكتر من شرط:
age = 20
has_id = True
# and: لازم الاتنين صح
print(age >= 18 and has_id) # True
# or: واحد بس يكفي
print(age < 18 or has_id) # True
# not: يعكس النتيجة
print(not has_id) # False= بتحط قيمة في متغير (Assignment). علامة == بتقارن قيمتين (Comparison). الخلط بينهم من أشهر الأخطاء!Python بتعتمد على الـ Indentation (المسافات البادئة) عشان تعرف الـ Blocks. مفيش أقواس {} زي باقي اللغات. لو نسيت المسافة هيطلع IndentationError!
mark = 87
if mark >= 90:
print("Excellent") # مسافة 4 بادئة ✅
elif mark >= 80: # elif = "else if"
print("Very Good")
elif mark >= 65:
print("Good")
else:
print("Need Improvement")
if جوا if تاني — مفيد لحالات زي Login ثم فحص الـ Role. لو logged_in صح، فافحص هل هو admin ولا لأ.logged_in = True
is_admin = False
if logged_in:
if is_admin:
print("افتح لوحة الأدمن")
else:
print("افتح لوحة الطالب")
else:
print("من فضلك سجّل دخولك")
if 2 < 1: [indented] print("Two is less than one!") [not-indented] print("Two is less than one!")النتيجة: الـ print الأولى مش هتتنفذ (الشرط غلط)، الثانية هتتنفذ دايماً لأنها بره الـ if.
Loops — for & while
تنفيذ نفس الكود أكتر من مرة بشكل أوتوماتيكي
الـ for بنستخدمه لما عارف عدد التكرارات. دالة range() بتولد أرقام:
# range(5) = 0, 1, 2, 3, 4
for i in range(5):
print(i)
# range(1,6) = 1, 2, 3, 4, 5
for i in range(1, 6):
print(i)
# Loop على عناصر قائمة
students = ["Ali", "Mona", "Sara"]
for student in students:
print(student)for i in range(5); بفاصلة منقوطة بدل النقطتين فوق بعض، هيطلع SyntaxError!الـ while بيكمل طالما الشرط True. مهم دايماً تعدّل المتغير جوا اللوب عشان متدخلش في Loop لا نهائي!
count = 1
while count <= 5:
print(count)
count += 1 # مهم! عشان اللوب يوقف
# Output: 1, 2, 3, 4, 5🔴 break
- يخرج من اللوب فوراً
- يوقف كل التكرار
🟡 continue
- يتخطى الفردة الحالية
- يكمل اللوب للفردة اللي بعدها
⚪ pass
- ما بيعملش حاجة
- Placeholder فاضي للكود
for i in range(1, 6):
if i == 3:
continue # يتخطى 3
if i == 5:
break # يوقف عند 5
print(i)
# Output: 1, 2, 4
List & Tuple — القوائم والـ Tuples
هياكل بيانات مرتبة — الفرق بين المتغير والثابت
[ ]القائمة بتخزن عناصر بالترتيب وبتقدر تعدل فيها. كل عنصر بيبدأ من Index رقم 0.
students = ["Ali", "Mona", "Sara"]
print(students[0]) # Ali
print(students[-1]) # Sara (الأخير)
students.append("Nour") # يضيف للآخر
students.remove("Ali") # يحذف بالقيمة
students.pop() # يحذف ويرجع الأخير
students.pop(0) # يحذف الأول
print(len(students)) # عدد العناصرlst = [0, 1, 2, 3, 4]
# list[start:end] — end مش متضمنة!
print(lst[1:3]) # [1, 2]
txt = "Hello, My Friend"
print(txt[:8]) # "Hello, M"
# يبدأ من الأول حتى index 7x = ['C', 'b', 'a']
x.sort()
print(x) # ['C', 'a', 'b'] ← C أولاً!
# الحروف Capital بتيجي قبل Small
y = ['C', 'b', 'A']
y.sort(key=str.lower)
print(y) # ['A', 'b', 'C']
# key=str.lower: يرتب بدون اعتبار حالة الحرف
# لكن يحافظ على شكله الأصلي!•
sort() على list من lists بيقارن أول عنصر فقط
•
sort(key=str.lower) يرتب بدون اعتبار الـ Case لكن يحافظ على الشكل الأصلي
•
pop() بدون argument تشيل آخر عنصر دايماً
( )الـ Tuple زي الـ List بالظبط، الفرق الوحيد إنها Immutable — مش ممكن تعدل فيها بعد ما تنشئها. بتستخدمها لما البيانات المفروض تفضل ثابتة.
point = (10, 20)
print(point[0]) # 10
# Tuple بعنصر واحد — لازم الفاصلة!
t1 = ("apple",) # ✅ Tuple
t2 = ("apple") # ❌ String مش Tuple!
# Tuple Unpacking
tup = (1, 2, 3, 4)
(*k,) = tup
print(k) # [1, 2, 3, 4](*k,) = (1,2,3,4) → يحول كل العناصر لـ List: [1, 2, 3, 4] ✅(x, *k, y, z, m) = (1,2,3) → ValueError! المتغيرات الإجبارية (x, y, z, m) أكتر من العناصر.x = ("apple", "banana", "cherry") — هذه ليست List! دي Tuple لأنها بتستخدم قوسين عاديين ( ) مش أقواس مربعة [ ].lst1 = [1, 2]
lst2 = [3, 4]
lst1.append(lst2) # يضيف الـ list كعنصر واحد
print(lst1) # [1, 2, [3, 4]]
lst1 = [1, 2]
lst1.extend(lst2) # يضيف عناصر lst2 كلها
print(lst1) # [1, 2, 3, 4] ✅extend() — مش update() (ده للـ Set والـ Dict) ولا append() (ده يضيف كعنصر واحد كامل).Set & Dictionary — المجموعات والقواميس
بيانات فريدة وبيانات بـ Key-Value Pairs
{ }الـ Set بتخزن قيم فريدة (مش بتكرر) وبدون ترتيب (Unordered) وبدون Index. يعني مش تقدر تقول s[0]!
colors = {"red", "blue", "red", "green"}
print(colors) # red واحدة بس!
# pop() في Set عشوائي!!
s = {1, 2, 3}
x = s.pop() # مش عارف أيه هيتمسح!
# update() للـ Set: يضيف عناصر Set تانية
s1 = {1, 2}
s2 = {3, 4}
s1.update(s2) # {1, 2, 3, 4}• الـ Set هي Unordered AND Unindexed (مش Unordered AND Indexed)
•
pop() في Set يمسح عنصر عشوائي — مش دايماً الأخير ولا الأول• لدمج Set في Set تانية: استخدم
update() (مش extend())
{ key: value }الـ Dictionary بيخزن البيانات كأزواج من Key: Value. مناسب جداً لبيانات الـ Profile أو الـ Settings. الـ Keys لازم تكون فريدة.
student = {
"name": "Laila",
"age": 20,
"dept": "IS"
}
print(student["name"]) # Laila
# تحديث قيمة
student["age"] = 21
# إضافة Key جديد
student["gpa"] = 3.9
print(student)لو ضفت Key موجود في الـ Dictionary، القيمة الجديدة بتكتب فوق القديمة بدون Error.
مثال:
{"name": "Ahmed", "mobile": 123, "mobile": 987} → الـ mobile هيكون 987 (الأخيرة)
y = d مش بتعمل نسخة جديدة — الاتنين بيشاوروا على نفس الـ Dictionary. لو غيّرت في d، y هتتأثر برضو. عشان تعمل نسخة حقيقية استخدم d.copy() (بحرف سمول!)| الهيكل | الأقواس | مرتبة؟ | لها Index؟ | تتعدل؟ | بتكرر؟ | استخدامها |
|---|---|---|---|---|---|---|
list | [ ] | ✅ نعم | ✅ نعم | ✅ نعم | ✅ نعم | قوائم متغيرة بترتيب |
tuple | ( ) | ✅ نعم | ✅ نعم | ❌ لأ | ✅ نعم | بيانات ثابتة (Immutable) |
set | { } | ❌ لأ | ❌ لأ | ✅ نعم | ❌ لأ | قيم فريدة بدون تكرار |
dict | { } | ✅ نعم | بالـ Key | ✅ نعم | Keys لأ | بيانات بتسمية (Key-Value) |
Functions & Scope — الدوال ونطاق المتغيرات
كود قابل لإعادة الاستخدام — أساس Django Views
الـ Function بلوك كود بينفذ مهمة معينة ومش بيشتغل إلا لما تناديه (Call). بنعرفه بكلمة def. المهم تفهم الفرق بين تعريف الدالة واستدعاءها!
دالة بسيطة + Parameters
def greet(name):
print(f"مرحباً {name}")
greet("Mona")
greet("Omar")print vs return — الفرق المهم
def add(a, b):
return a + b # يرجع القيمة
result = add(5, 7)
print(result) # 12print بيعرض للشاشة وبس. return بيرجع القيمة للبرنامج عشان تستخدمها بعدين. كتير من الـ Django Views بترجع قيم بـ return.# *args: يجمع arguments في Tuple
def show(*args):
print(args)
show(1, 2, 3) # (1, 2, 3)
# **kwargs: يجمع keyword args في Dict
def person_info(**person):
print("اسمه: " + person["name"])
person_info(name="Ahmed", age=10)
# يطبع: اسمه: Ahmed
# الـ age بيتجاهل لأن الكود مش محتاجه**person بيجمع البيانات في Dictionary. الدالة بتطبع person["name"] بس — الـ age بيتجاهل بدون Error. ✅الـ Lambda دالة سريعة بسطر واحد بدون اسم. فكرتها: lambda arguments: expression
# سؤال بيتكرر في 2021 و2024!
y = lambda x: x / 20
print(y(100)) # 5.0 (مش 5!)
# القسمة بـ / دايماً float!
# دالة Lambda بدون Args
f = lambda: 10
print(f()) # 10y = lambda x: x / 20 ثم y(100) = 5.0 وليس 5! دي من أكتر الأسئلة اللي بتتكرر.المتغير اللي بتعرّفه جوا Function هو Local Variable — بيعيش بس جوا الـ Function ومينقدرش تستخدمه بره منها.
def test():
message = "أنا جوا الدالة" # Local
print(message)
test()
# print(message) ← هيطلع NameError!
Modules, Errors & Files — التنظيم والأخطاء والملفات
Python بتنمو من Script واحد لمشروع ضخم
الـ Module هو ملف Python بيحتوي كود قابل للاستيراد. Django نفسه مجموعة ضخمة من Modules!
# استيراد module جاهز
import math
print(math.sqrt(25)) # 5.0
print(math.pi) # 3.14159...
# استيراد من module ملف ثاني
# helpers.py:
def greet(name): return f"Hello {name}"
# main.py:
from helpers import greet
print(greet("Nour"))| النوع | المعنى | مثال |
|---|---|---|
SyntaxError | Python مش فاهم الكود | نسيت : بعد if |
NameError | متغير مش معرّف | كتبت اسم غلط |
TypeError | عملية على نوع غلط | "a" + 1 |
IndentationError | المسافات البادئة غلط | نسيت 4 مسافات |
ValueError | القيمة مش مناسبة | tuple unpacking فشل |
عشان البرنامج ميقفلش فجأة لو حصل خطأ، بنحيط الكود الخطر بـ try ونتعامل مع الخطأ في except.
try:
num = int(input("اكتب رقم: "))
print(num * 2)
except:
print("ده مش رقم! اكتب رقم صحيح")
Python تقدر تقرأ وتكتب في ملفات خارجية باستخدام دالة open(filename, mode).
قراءة ملف
file = open("notes.txt", "r")
content = file.read()
print(content)
file.close()كتابة ملف
file = open("report.txt", "w")
file.write("Backend Lec 2")
file.close()"w" بيمسح محتواه القديم ويكتب من الأول! استخدم Mode "a" (Append) لو عايز تضيف من غير ما تمسح.أسئلة امتحانات Python — 2021 & 2025
22 سؤال حقيقي من الامتحانات مرتبين حسب الشرح مع تفسيرات عربية مفصلة 🇪🇬
my-var is an incorrect variable name in Python. True or False?انتبه: الإجابة الصح هي A (True) مش B! الاسم
my-var فعلاً اسم غلط في Python لأن الشرطة العادية - مش مسموح بيها في أسماء المتغيرات. الصح هو استخدام الشرطة السفلية: my_var ✅. ملاحظة: السؤال بيسأل "هل هو غلط؟" والإجابة True يعني نعم هو غلط.
if 2 < 1:
print("Two is less than one!")
print("Two is less than one!")الشرط
2 < 1 طبعاً غلط (False)، فالـ print اللي جوا الـ if (اللي ليها Indentation) مش هتتنفذ. أما الـ print التانية فهي بره الـ if (مفيش Indentation)، وده معناه إنها هتتنفذ دايماً. المحاضرة بتركز على إن الـ Indentation هي اللي بتحدد إيه جوا الـ Block وإيه بره.
lst = []
nums = [15, 6]
lst.append(nums)
nums = [10, 30, 20]
lst.append(nums)
lst.sort()
print(lst)الـ
lst بيحتوي على list من lists: [[15, 6], [10, 30, 20]]. لما تعمل sort() على list من lists، Python بتقارن أول عنصر فقط في كل sub-list. الـ 10 أصغر من 15، فـ [10, 30, 20] بتيجي قبل [15, 6]. العناصر الداخلية لكل list مش بتتأثر وبتفضل بترتيبها الأصلي.
[] (empty list) is False. True or False?في Python أي حاجة فاضية (Empty) قيمتها المنطقية False: القائمة الفاضية
[]، الـ Dict الفاضي {}، الـ String الفاضية ""، والرقم 0. ده اسمه "Truthy and Falsy Values" في Python.
"Hello, My":
b = "Hello, My Friend"
print(b[:8])الـ Slicing بالصيغة
b[:8] بتاخد من أول النص لحد قبل index 8، يعني العناصر من index 0 إلى index 7 فقط. العد هنا:
H(0), e(1), l(2), l(3), o(4), ,(5), space(6), M(7)
إذن الناتج الحقيقي هو
"Hello, M" وليس "Hello, My". عشان تطبع "Hello, My" محتاج تستخدم b[:9] لأن حرف y موجود عند index 8.
['a', 'b', 'C']:
X = ['C', 'b', 'a']
X.sort()
print(X)sort() العادية (بدون key) بتعتمد على كود ASCII. في ASCII، الحروف الـ Capital (A-Z = 65-90) بتيجي قبل الـ Small (a-z = 97-122). يعني 'C' (67) بتيجي قبل 'a' (97) وقبل 'b' (98). النتيجة الصحيحة هي ['C', 'a', 'b'] وليس ['a', 'b', 'C'].
['a', 'b', 'c']:
X = ['C', 'b', 'A']
X.sort(key=str.lower)
print(X)key=str.lower بتخلي الترتيب يعتمد على النسخة الـ Lowercase من الحروف — يعني 'A' و'a' بيتعاملوا كـ 'a'. الترتيب الأبجدي بيطلع: A, b, C. لكن الحروف بتفضل بشكلها الأصلي! يعني الناتج هيكون ['A', 'b', 'C'] وليس ['a', 'b', 'c'].
myNumbers = [1, 2, 3]
x = myNumbers.pop()pop() بدون argument دايماً بتشيل آخر عنصر في الـ List. القائمة [1, 2, 3] — آخر عنصر هو 3. يعني x = 3 والقائمة تبقى [1, 2]. (السؤال ده اتكرر في 2024 برضو وكانت الإجابة نفسها).
myNumbers = [1, 2, 3]
x = myNumbers.pop()pop() بدون argument بتشيل آخر عنصر وهو 3، مش العنصر الأول (1). لو عايز تشيل أول عنصر اكتب pop(0). ده سؤال مصمم عشان يفرق بين الناس اللي فاهمين الـ pop() واللي مش فاهمين.
update() method. True or False?الخلاصة الامتحانية:
• لدمج List في List تانية: استخدم
extend()
• لدمج Set في Set تانية: استخدم
update()
• لدمج Dict في Dict تانية: استخدم
update()
update() مش بتشتغل على Lists!
extend() method. True or False?عشان تضيف عناصر Set في Set تانية، بنستخدم
update() مش extend(). الـ extend() بتشتغل مع الـ List فقط. فخ كتير طلاب بيقعوا فيه لأن الكلمتين شبه بعض!
الـ Set هي Unordered (بدون ترتيب) وكمان Unindexed (بدون Index). مش ممكن تقول
s[0]! السؤال ده اتكرر في 2021 و2025 بنفس الصياغة تقريباً — خد بالك منه كويس.
myNumbers = {1, 2, 3}
x = myNumbers.pop()لأن ده Set مش List! الـ
pop() في الـ Set بتشيل عنصر عشوائي (Random) لأن الـ Set مش مرتبة. ممكن يشيل 1 أو 2 أو 3 — مش ضمان. قارن ده بالـ List: pop() في List دايماً بتشيل الآخر.
x = ("apple", "banana", "cherry")ده Tuple مش List! الـ Tuple بتستخدم قوسين عاديين
( )، أما الـ List فبتستخدم أقواس مربعة [ ]. الفرق مهم جداً لأن الـ Tuple Immutable (مش ممكن تتعدل) والـ List Mutable.
y = ("apple",)نعم ده Tuple! الـ Tuple بعنصر واحد لازم تحط فاصلة بعد العنصر:
("apple",). لو ما حطتيش الفاصلة: y = ("apple") → ده هيبقى String مش Tuple!
newtuple = (1, 2, 3, 4)
(*k,) = newtuple
print(k)الصيغة
(*k,) = newtuple — النجمة * مع k بتجمع كل العناصر في List. يعني k هيكون [1, 2, 3, 4]. لو كانت (x, *k, y) = (1,2,3,4) فـ x=1, k=[2,3], y=4.
newtuple = (1, 2, 3)
(x, *k, y, z, m) = newtuple
print(k)الـ Tuple فيها 3 عناصر فقط، لكن الـ Unpacking بيطلب: x (1 عنصر) + k (0 على الأقل) + y (1) + z (1) + m (1) = 4 عناصر إجبارية كحد أدنى! العناصر مش كافية فبيطلع ValueError. لو كانت
(1,2,3,4,5) كانت هتنجح: x=1, k=[2,3], y=4, z=5, m=???... لأ برضو! مفتقرة لـ m.
x = {
"name": "Ahmed",
"id": "1",
"mobile": 123456789,
"mobile": 987654321
}
print(x)في الـ Dictionary، الـ Keys لازم تكون فريدة. لو حطيت نفس الـ Key أكتر من مرة، Python مش بيطلع Error — بس بيحتفظ بالقيمة الأخيرة فقط. "mobile": 987654321 هي القيمة الأخيرة، فهي اللي بتفضل.
def f(**person):
print("Person's name is " + person["name"])
f(name="Ahmed", age=10)**person بيجمع كل الـ keyword arguments في Dictionary: {"name": "Ahmed", "age": 10}. الكود بيطبع بس person["name"] = "Ahmed". الـ age موجود في الـ Dict لكن الكود مش طالبه، فبيتجاهله بدون Error.
y = lambda x: x / 20
print(y(100))القاعدة الذهبية اللي بتتكرر في كل امتحان: القسمة العادية بعلامة
/ في Python دايماً بترجع float. 100 / 20 = 5.0 وليس 5. لو عايز 5 عدد صحيح استخدم 100 // 20.
lst = [1, 2, 3, 4]
lst.pop()lst?pop() بدون argument بتشيل آخر عنصر وهو 4. القائمة تبقى [1, 2, 3].
دالة
format() مش بتغير نوع البيانات (Datatypes). هي بس بتنظم وتنسّق طريقة عرض الـ String. اللي بيغير النوع هو الـ Type Casting: int(), float(), str(), bool().