بعد أن تتعلم القوائم والقواميس والدوال والملفات في بايثون، تحتاج إلى مشروع صغير يجمع هذه المهارات داخل برنامج واحد مفيد. من الأمثلة المناسبة للمبتدئ برنامج دفتر جهات اتصال تستطيع من خلاله إضافة الأسماء وأرقام الهواتف، وعرض البيانات، والبحث عن شخص، وتعديل معلوماته أو حذفها.
لكن تخزين جهات الاتصال داخل قائمة عادية لا يكفي؛ لأن البيانات ستختفي بمجرد إغلاق البرنامج. لذلك سنطوّر المثال تدريجيًا حتى نحفظ جميع جهات الاتصال داخل ملف JSON، ثم نقرأها تلقائيًا في المرة التالية التي نشغّل فيها البرنامج.
في هذا المقال من سلسلة بايثون بالمثال ستبني برنامجًا كاملًا يعمل من سطر الأوامر، وستتعلم كيف تنظّم البيانات داخل قائمة من القواميس، وتتحقق من المدخلات، وتقسم البرنامج إلى دوال واضحة، وتحفظ البيانات بطريقة تجعلها باقية بعد إغلاق البرنامج.
{alertInfo} الفكرة ببساطة: سنخزن كل جهة اتصال داخلDictionaryيحتوي على الاسم ورقم الهاتف والبريد، ثم نضع جميع القواميس داخلList. بعد كل إضافة أو تعديل أو حذف، نحفظ القائمة داخل ملفcontacts.json.
{getToc} $title={محتوى المقال}
ماذا سنبني في هذا المثال؟
سننشئ برنامج دفتر جهات اتصال يوفر الخيارات التالية:
- إضافة جهة اتصال جديدة.
- عرض جميع جهات الاتصال.
- البحث عن جهة اتصال بالاسم.
- تعديل رقم الهاتف أو البريد الإلكتروني.
- حذف جهة اتصال بعد التأكيد.
- حفظ البيانات تلقائيًا داخل ملف
JSON. - تحميل البيانات السابقة عند تشغيل البرنامج.
- التعامل مع ملف مفقود أو فارغ أو غير صالح.
سيعمل البرنامج من خلال قائمة نصية تظهر في Terminal أو CMD، ويختار المستخدم العملية بكتابة رقم من 1 إلى 6.
المهارات التي ستتدرب عليها
| المهارة | كيف سنستخدمها؟ |
|---|---|
List | تخزين جميع جهات الاتصال داخل قائمة واحدة. |
Dictionary | تخزين الاسم ورقم الهاتف والبريد لكل شخص. |
| الدوال | تقسيم الإضافة والبحث والحذف والحفظ إلى وظائف مستقلة. |
if وwhile | التحقق من المدخلات وتشغيل القائمة الرئيسية باستمرار. |
ملفات JSON | حفظ البيانات وقراءتها بين مرات تشغيل البرنامج. |
try وexcept | منع توقف البرنامج عند وجود مشكلة في ملف البيانات. |
pathlib | تحديد مسار ملف جهات الاتصال بطريقة واضحة. |
هيكل ملفات المشروع
أنشئ مجلدًا جديدًا باسم contact_book، ثم أنشئ داخله ملف Python باسم contact_book.py.
contact_book/
│
├── contact_book.py
└── contacts.json
لا تحتاج إلى إنشاء ملف contacts.json يدويًا. سيقوم البرنامج بإنشائه عند حفظ أول جهة اتصال. وضعناه في المخطط فقط حتى تفهم شكل المشروع بعد تشغيله.
كيف سننظم بيانات جهات الاتصال؟
كل جهة اتصال تحتوي على أكثر من معلومة، لذلك القاموس Dictionary مناسب لتمثيلها.
contact = {
"name": "Ali",
"phone": "+967 777 123 456",
"email": "ali@example.com"
}
المفاتيح في القاموس هي name للاسم، وphone لرقم الهاتف، وemail للبريد الإلكتروني.
ولأن البرنامج سيحتوي على أكثر من جهة اتصال، سنضع القواميس داخل قائمة:
contacts = [
{
"name": "Ali",
"phone": "+967 777 123 456",
"email": "ali@example.com"
},
{
"name": "Sara",
"phone": "+967 733 987 654",
"email": "sara@example.com"
}
]
بهذا التنظيم يمكنك المرور على جميع جهات الاتصال باستخدام حلقة، أو البحث داخلها، أو تحويلها بسهولة إلى ملف JSON.
النسخة الأولى: إضافة جهة اتصال إلى قائمة
سنبدأ بنسخة بسيطة لا تحفظ البيانات في ملف بعد. أنشئ قائمة فارغة، ثم اطلب من المستخدم إدخال البيانات.
contacts = []
name = input("أدخل الاسم: ").strip()
phone = input("أدخل رقم الهاتف: ").strip()
email = input("أدخل البريد الإلكتروني: ").strip()
contact = {
"name": name,
"phone": phone,
"email": email
}
contacts.append(contact)
print(contacts)
استخدمنا strip() لإزالة المسافات الزائدة من بداية ونهاية الإدخال، ثم أنشأنا قاموسًا وأضفناه إلى القائمة باستخدام append().
تحويل الإضافة إلى دالة مستقلة
من الأفضل وضع منطق الإضافة داخل دالة، حتى نستطيع استدعاءه من القائمة الرئيسية كلما اختار المستخدم إضافة جهة اتصال.
def add_contact(contacts):
name = input("أدخل الاسم: ").strip()
phone = input("أدخل رقم الهاتف: ").strip()
email = input("أدخل البريد الإلكتروني: ").strip()
contact = {
"name": name,
"phone": phone,
"email": email
}
contacts.append(contact)
print("تمت إضافة جهة الاتصال بنجاح.")
الدالة تستقبل القائمة نفسها، ثم تضيف القاموس الجديد إليها. لأن القائمة قابلة للتعديل، ستبقى جهة الاتصال مضافة بعد انتهاء الدالة.
التحقق من الاسم ورقم الهاتف
لا نريد قبول اسم فارغ أو رقم هاتف مكوّن من حروف. نبدأ بدالة تتحقق من رقم الهاتف بعد إزالة المسافات والشرطات وعلامة + في البداية.
def is_valid_phone(phone):
cleaned_phone = phone.replace(" ", "").replace("-", "")
if cleaned_phone.startswith("+"):
cleaned_phone = cleaned_phone[1:]
return cleaned_phone.isdigit() and len(cleaned_phone) >= 7
هذا تحقق مبسط للتدريب، وليس نظامًا عالميًا لجميع أرقام الهواتف؛ لأن أطوال وصيغ الأرقام تختلف بين الدول.
التحقق من البريد الإلكتروني
سنجعل البريد اختياريًا. إذا تركه المستخدم فارغًا نقبله، وإذا كتب قيمة نتحقق بصورة مبسطة من وجود @ ونقطة داخل اسم النطاق.
def is_valid_email(email):
if not email:
return True
if "@" not in email:
return False
domain = email.split("@", 1)[1]
return "." in domain
منع تكرار جهة الاتصال بالاسم
ننشئ دالة تبحث عن الاسم وتعيد موقعه داخل القائمة. نستخدم casefold() حتى لا يجعل اختلاف الحروف الكبيرة والصغيرة الاسم يبدو جديدًا.
def find_contact_index(contacts, name):
normalized_name = name.casefold()
for index, contact in enumerate(contacts):
if contact["name"].casefold() == normalized_name:
return index
return None
دالة الإضافة بعد التحقق من البيانات
def add_contact(contacts):
name = input("أدخل الاسم: ").strip()
if not name:
print("الاسم لا يمكن أن يكون فارغًا.")
return
if find_contact_index(contacts, name) is not None:
print("توجد جهة اتصال بهذا الاسم مسبقًا.")
return
phone = input("أدخل رقم الهاتف: ").strip()
if not is_valid_phone(phone):
print("رقم الهاتف غير صالح.")
return
email = input(
"أدخل البريد الإلكتروني أو اتركه فارغًا: "
).strip()
if not is_valid_email(email):
print("البريد الإلكتروني غير صالح.")
return
contacts.append({
"name": name,
"phone": phone,
"email": email
})
print("تمت إضافة جهة الاتصال بنجاح.")
عرض جميع جهات الاتصال
نستخدم حلقة for مع enumerate() لعرض كل جهة اتصال برقم متسلسل.
def list_contacts(contacts):
if not contacts:
print("لا توجد جهات اتصال محفوظة.")
return
print("\n--- جهات الاتصال ---")
for number, contact in enumerate(contacts, start=1):
email = contact["email"] or "غير مضاف"
print(f"\n{number}. الاسم: {contact['name']}")
print(f" الهاتف: {contact['phone']}")
print(f" البريد: {email}")
البحث عن جهة اتصال بالاسم
سنسمح بالبحث باستخدام جزء من الاسم، وليس الاسم كاملًا فقط. نستخدم قائمة مشتقة لجمع النتائج، ثم نعيد استخدام دالة العرض.
def search_contacts(contacts):
query = input("أدخل الاسم أو جزءًا منه: ").strip()
if not query:
print("اكتب اسمًا للبحث.")
return
normalized_query = query.casefold()
matches = [
contact
for contact in contacts
if normalized_query in contact["name"].casefold()
]
if not matches:
print("لم يتم العثور على جهة اتصال مطابقة.")
return
list_contacts(matches)
تعديل جهة اتصال موجودة
نطلب الاسم الكامل، ثم نصل إلى القاموس المطلوب. إذا ضغط المستخدم Enter دون كتابة قيمة جديدة، نحتفظ بالقيمة الحالية.
def update_contact(contacts):
name = input("أدخل الاسم الكامل لجهة الاتصال: ").strip()
index = find_contact_index(contacts, name)
if index is None:
print("جهة الاتصال غير موجودة.")
return
contact = contacts[index]
new_phone = input(
f"رقم الهاتف الجديد [{contact['phone']}]: "
).strip()
new_email = input(
f"البريد الجديد [{contact['email'] or 'غير مضاف'}]: "
).strip()
if new_phone:
if not is_valid_phone(new_phone):
print("رقم الهاتف الجديد غير صالح.")
return
contact["phone"] = new_phone
if new_email:
if not is_valid_email(new_email):
print("البريد الإلكتروني الجديد غير صالح.")
return
contact["email"] = new_email
print("تم تعديل جهة الاتصال بنجاح.")
{alertInfo} في هذه النسخة، ترك البريد فارغًا أثناء التعديل يعني الاحتفاظ بالبريد الحالي، وليس حذفه. يمكنك لاحقًا إضافة خيار مستقل لمسح البريد.
حذف جهة اتصال بعد التأكيد
def delete_contact(contacts):
name = input("أدخل الاسم الكامل لجهة الاتصال: ").strip()
index = find_contact_index(contacts, name)
if index is None:
print("جهة الاتصال غير موجودة.")
return
contact = contacts[index]
confirmation = input(
f"هل تريد حذف {contact['name']}؟ (y/n): "
).strip().lower()
if confirmation == "y":
contacts.pop(index)
print("تم حذف جهة الاتصال.")
else:
print("تم إلغاء الحذف.")
لماذا تختفي البيانات عند إغلاق البرنامج؟
حتى الآن تُحفظ البيانات داخل الذاكرة فقط. عندما ينتهي تشغيل البرنامج، تختفي القائمة وجميع القواميس الموجودة فيها.
لحل المشكلة نستخدم ملف JSON، لأنه مناسب للقوائم والقواميس، وسهل القراءة، ومكتبته مدمجة مع بايثون.
تحديد مسار ملف البيانات باستخدام pathlib
from pathlib import Path
DATA_FILE = Path("contacts.json")
حفظ جهات الاتصال باستخدام json.dump
import json
def save_contacts(contacts):
try:
with DATA_FILE.open("w", encoding="utf-8") as file:
json.dump(
contacts,
file,
ensure_ascii=False,
indent=4
)
except OSError as error:
print(f"تعذر حفظ البيانات: {error}")
يضمن encoding="utf-8" دعم النص العربي، ويجعل ensure_ascii=False العربية ظاهرة طبيعيًا، بينما ينظم indent=4 الملف.
قد يصبح محتوى الملف بعد إضافة جهتي اتصال بهذا الشكل:
[
{
"name": "Ali",
"phone": "+967 777 123 456",
"email": "ali@example.com"
},
{
"name": "Sara",
"phone": "+967 733 987 654",
"email": ""
}
]
قراءة جهات الاتصال عند تشغيل البرنامج
إذا لم يكن الملف موجودًا نعيد قائمة فارغة. وإذا كان فارغًا أو تالفًا، نعالج JSONDecodeError بدل توقف البرنامج.
def load_contacts():
if not DATA_FILE.exists():
return []
try:
with DATA_FILE.open("r", encoding="utf-8") as file:
contacts = json.load(file)
if not isinstance(contacts, list):
print("ملف البيانات لا يحتوي على قائمة صالحة.")
return []
return contacts
except json.JSONDecodeError:
print("ملف contacts.json فارغ أو غير صالح.")
return []
except OSError as error:
print(f"تعذر قراءة البيانات: {error}")
return []
متى نحفظ البيانات؟
سنحفظ مباشرة بعد كل إضافة أو تعديل أو حذف، حتى لا تضيع التغييرات إذا أُغلقت النافذة فجأة.
# بعد الإضافة
contacts.append(contact)
save_contacts(contacts)
# بعد التعديل
contact["phone"] = new_phone
save_contacts(contacts)
# بعد الحذف
contacts.pop(index)
save_contacts(contacts)
إنشاء القائمة الرئيسية
def show_menu():
print("\n=== دفتر جهات الاتصال ===")
print("1. إضافة جهة اتصال")
print("2. عرض جميع جهات الاتصال")
print("3. البحث عن جهة اتصال")
print("4. تعديل جهة اتصال")
print("5. حذف جهة اتصال")
print("6. خروج")
تشغيل البرنامج داخل حلقة while
def main():
contacts = load_contacts()
while True:
show_menu()
choice = input("اختر رقم العملية: ").strip()
if choice == "1":
add_contact(contacts)
elif choice == "2":
list_contacts(contacts)
elif choice == "3":
search_contacts(contacts)
elif choice == "4":
update_contact(contacts)
elif choice == "5":
delete_contact(contacts)
elif choice == "6":
print("تم إغلاق دفتر جهات الاتصال.")
break
else:
print("الخيار غير صحيح. اختر رقمًا من 1 إلى 6.")
تشغيل main بالطريقة الصحيحة
if __name__ == "__main__":
main()
الكود الكامل لبرنامج دفتر جهات الاتصال
ضع الكود التالي كاملًا داخل ملف contact_book.py:
import json
from pathlib import Path
DATA_FILE = Path("contacts.json")
def load_contacts():
if not DATA_FILE.exists():
return []
try:
with DATA_FILE.open("r", encoding="utf-8") as file:
contacts = json.load(file)
if not isinstance(contacts, list):
print("ملف البيانات لا يحتوي على قائمة صالحة.")
return []
return contacts
except json.JSONDecodeError:
print("ملف contacts.json فارغ أو غير صالح.")
return []
except OSError as error:
print(f"تعذر قراءة البيانات: {error}")
return []
def save_contacts(contacts):
try:
with DATA_FILE.open("w", encoding="utf-8") as file:
json.dump(
contacts,
file,
ensure_ascii=False,
indent=4
)
except OSError as error:
print(f"تعذر حفظ البيانات: {error}")
def is_valid_phone(phone):
cleaned_phone = phone.replace(" ", "").replace("-", "")
if cleaned_phone.startswith("+"):
cleaned_phone = cleaned_phone[1:]
return cleaned_phone.isdigit() and len(cleaned_phone) >= 7
def is_valid_email(email):
if not email:
return True
if "@" not in email:
return False
domain = email.split("@", 1)[1]
return "." in domain
def find_contact_index(contacts, name):
normalized_name = name.casefold()
for index, contact in enumerate(contacts):
if contact["name"].casefold() == normalized_name:
return index
return None
def add_contact(contacts):
name = input("أدخل الاسم: ").strip()
if not name:
print("الاسم لا يمكن أن يكون فارغًا.")
return
if find_contact_index(contacts, name) is not None:
print("توجد جهة اتصال بهذا الاسم مسبقًا.")
return
phone = input("أدخل رقم الهاتف: ").strip()
if not is_valid_phone(phone):
print("رقم الهاتف غير صالح.")
return
email = input(
"أدخل البريد الإلكتروني أو اتركه فارغًا: "
).strip()
if not is_valid_email(email):
print("البريد الإلكتروني غير صالح.")
return
contacts.append({
"name": name,
"phone": phone,
"email": email
})
save_contacts(contacts)
print("تمت إضافة جهة الاتصال بنجاح.")
def list_contacts(contacts):
if not contacts:
print("لا توجد جهات اتصال محفوظة.")
return
print("\n--- جهات الاتصال ---")
for number, contact in enumerate(contacts, start=1):
email = contact["email"] or "غير مضاف"
print(f"\n{number}. الاسم: {contact['name']}")
print(f" الهاتف: {contact['phone']}")
print(f" البريد: {email}")
def search_contacts(contacts):
query = input("أدخل الاسم أو جزءًا منه: ").strip()
if not query:
print("اكتب اسمًا للبحث.")
return
normalized_query = query.casefold()
matches = [
contact
for contact in contacts
if normalized_query in contact["name"].casefold()
]
if not matches:
print("لم يتم العثور على جهة اتصال مطابقة.")
return
list_contacts(matches)
def update_contact(contacts):
name = input("أدخل الاسم الكامل لجهة الاتصال: ").strip()
index = find_contact_index(contacts, name)
if index is None:
print("جهة الاتصال غير موجودة.")
return
contact = contacts[index]
new_phone = input(
f"رقم الهاتف الجديد [{contact['phone']}]: "
).strip()
new_email = input(
f"البريد الجديد [{contact['email'] or 'غير مضاف'}]: "
).strip()
if new_phone:
if not is_valid_phone(new_phone):
print("رقم الهاتف الجديد غير صالح.")
return
contact["phone"] = new_phone
if new_email:
if not is_valid_email(new_email):
print("البريد الإلكتروني الجديد غير صالح.")
return
contact["email"] = new_email
save_contacts(contacts)
print("تم تعديل جهة الاتصال بنجاح.")
def delete_contact(contacts):
name = input("أدخل الاسم الكامل لجهة الاتصال: ").strip()
index = find_contact_index(contacts, name)
if index is None:
print("جهة الاتصال غير موجودة.")
return
contact = contacts[index]
confirmation = input(
f"هل تريد حذف {contact['name']}؟ (y/n): "
).strip().lower()
if confirmation == "y":
contacts.pop(index)
save_contacts(contacts)
print("تم حذف جهة الاتصال.")
else:
print("تم إلغاء الحذف.")
def show_menu():
print("\n=== دفتر جهات الاتصال ===")
print("1. إضافة جهة اتصال")
print("2. عرض جميع جهات الاتصال")
print("3. البحث عن جهة اتصال")
print("4. تعديل جهة اتصال")
print("5. حذف جهة اتصال")
print("6. خروج")
def main():
contacts = load_contacts()
while True:
show_menu()
choice = input("اختر رقم العملية: ").strip()
if choice == "1":
add_contact(contacts)
elif choice == "2":
list_contacts(contacts)
elif choice == "3":
search_contacts(contacts)
elif choice == "4":
update_contact(contacts)
elif choice == "5":
delete_contact(contacts)
elif choice == "6":
print("تم إغلاق دفتر جهات الاتصال.")
break
else:
print("الخيار غير صحيح. اختر رقمًا من 1 إلى 6.")
if __name__ == "__main__":
main()
طريقة تشغيل البرنامج
افتح Terminal داخل مجلد المشروع، ثم شغّل الملف.
py contact_book.pyأو:
python contact_book.pyفي macOS أو Linux قد تستخدم:
python3 contact_book.py
مثال تشغيل
=== دفتر جهات الاتصال ===
1. إضافة جهة اتصال
2. عرض جميع جهات الاتصال
3. البحث عن جهة اتصال
4. تعديل جهة اتصال
5. حذف جهة اتصال
6. خروج
اختر رقم العملية: 1
أدخل الاسم: Ali
أدخل رقم الهاتف: +967 777 123 456
أدخل البريد الإلكتروني أو اتركه فارغًا: ali@example.com
تمت إضافة جهة الاتصال بنجاح.
بعد الإضافة سيظهر ملف contacts.json داخل مجلد المشروع. أغلق البرنامج وشغّله مرة أخرى، ثم اختر عرض جهات الاتصال؛ ستجد أن البيانات ما زالت موجودة.
كيف يعمل البرنامج خطوة بخطوة؟
- يبدأ التنفيذ من الشرط
if __name__ == "__main__". - تستدعي
main()الدالةload_contacts(). - تُقرأ البيانات القديمة من ملف JSON أو تبدأ قائمة فارغة.
- تعرض حلقة
whileالقائمة الرئيسية. - يُنفذ الخيار الذي يحدده المستخدم.
- بعد الإضافة أو التعديل أو الحذف تُحفظ القائمة مباشرة.
- تتكرر القائمة حتى يختار المستخدم الخروج.
أخطاء شائعة عند بناء دفتر جهات الاتصال
1. إعادة إنشاء القائمة داخل كل دورة
لا تكتب contacts = [] داخل حلقة القائمة؛ لأن ذلك يمسح البيانات في كل دورة. حمّل القائمة مرة واحدة قبل الحلقة.
2. نسيان الحفظ بعد التعديل
تعديل القاموس في الذاكرة لا يكفي. استدعِ save_contacts() بعد الإضافة والتعديل والحذف.
3. الخلط بين dump وdumps
json.dump() تكتب داخل ملف، بينما json.dumps() تعيد نص JSON داخل البرنامج.
4. نسيان ensure_ascii=False
استخدمه مع encoding="utf-8" حتى يظهر النص العربي طبيعيًا داخل ملف JSON.
5. محاولة قراءة ملف JSON فارغ
الملف الفارغ ليس JSON صالحًا، لذلك عالج JSONDecodeError وأعد قائمة فارغة.
6. الحذف دون تأكيد
اطلب من المستخدم تأكيدًا واضحًا قبل استخدام pop() حتى لا يحذف اسمًا بالخطأ.
7. اعتبار التحقق المبسط نهائيًا
فحص الهاتف والبريد في المثال مناسب للتعلم، لكنه ليس بديلًا عن قواعد أو مكتبات متخصصة في تطبيق حقيقي.
تحسينات يمكنك إضافتها لاحقًا
- إضافة الشركة والعنوان والملاحظات.
- البحث باستخدام رقم الهاتف.
- ترتيب الأسماء أبجديًا قبل العرض.
- منع تكرار رقم الهاتف.
- تصدير البيانات إلى CSV.
- إنشاء نسخة احتياطية من ملف JSON.
- تقسيم البرنامج إلى أكثر من ملف.
- كتابة اختبارات باستخدام
pytest. - تحويل البرنامج إلى واجهة رسومية باستخدام
Tkinter.
تمرين عملي
أضف المفتاح category لكل جهة اتصال، واجعل المستخدم يختار بين: العائلة، العمل، الأصدقاء، وأخرى. بعد ذلك أضف خيارًا يعرض جهات الاتصال حسب الفئة.
category = input(
"أدخل الفئة: العائلة، العمل، الأصدقاء، أخرى: "
).strip()
contact = {
"name": name,
"phone": phone,
"email": email,
"category": category
}
روابط داخلية مفيدة من بايثون العرب
- سلسلة بايثون بالمثال
- بايثون بالمثال 18: إنشاء برنامج قائمة مهام بسيطة
- شرح مكتبة JSON في Python للمبتدئين
- شرح Dictionary في Python للمبتدئين
- تنظيم ملفات مشروع Python بطريقة صحيحة
- حل خطأ JSONDecodeError في Python
- شرح try وexcept والتعامل مع الأخطاء
- شرح مكتبة pathlib في Python
مصادر خارجية رسمية للتوسع
- توثيق مكتبة json الرسمي في Python
- توثيق مكتبة pathlib الرسمي
- هياكل البيانات في توثيق Python الرسمي
- الأخطاء والاستثناءات في Python
الخلاصة
أنشأنا برنامج دفتر جهات اتصال كاملًا باستخدام بايثون. خزّنا كل شخص داخل قاموس يحتوي على الاسم والهاتف والبريد، ثم وضعنا القواميس داخل قائمة واحدة.
تعلمنا الإضافة والعرض والبحث والتعديل والحذف، وقسمنا البرنامج إلى دوال واضحة. ثم استخدمنا مكتبة json لحفظ القائمة داخل ملف، وpathlib للمسار، وtry وexcept للتعامل مع مشكلات القراءة والكتابة.
{alertSuccess} القاعدة المهمة: البيانات الموجودة داخل المتغيرات تختفي عند انتهاء البرنامج. إذا أردت الاحتفاظ بها، احفظها في ملف أو قاعدة بيانات، ثم اقرأها عند التشغيل التالي.
أسئلة شائعة
كيف أنشئ برنامج جهات اتصال ببايثون؟
خزّن كل جهة اتصال داخل قاموس، وضع القواميس داخل قائمة، ثم أنشئ دوالًا للإضافة والعرض والبحث والتعديل والحذف.
لماذا استخدمنا JSON؟
لأنه مناسب للقوائم والقواميس، وسهل القراءة والكتابة باستخدام مكتبة json المدمجة مع بايثون.
هل أحتاج إلى تثبيت مكتبة json؟
لا. يكفي أن تكتب import json.
ما الفرق بين json.dump وjson.load؟
json.dump() تكتب بيانات بايثون داخل ملف، بينما json.load() تقرأ الملف وتحوله إلى بيانات بايثون.
كيف أمنع تكرار جهة الاتصال؟
ابحث عن الاسم أو رقم الهاتف قبل الإضافة. في المثال استخدمنا find_contact_index() لمنع تكرار الاسم.
هل يمكن البحث بجزء من الاسم؟
نعم، استخدم casefold() لتوحيد الحروف، ثم العامل in للتحقق من وجود النص داخل الاسم.
هل يمكن تحويل البرنامج إلى واجهة رسومية؟
نعم، يمكنك استخدام Tkinter لاحقًا مع الاحتفاظ بدوال الحفظ والقراءة نفسها تقريبًا.
هل JSON مناسب لعدد كبير من جهات الاتصال؟
هو مناسب للمشروع التعليمي والبيانات الصغيرة. عند نمو التطبيق، تكون قاعدة بيانات مثل SQLite أنسب للبحث والتعديل وإدارة البيانات.



