الوحدة 1 · أساسيات Python للمحللين
الدوال والـ f-strings وقراءة رسائل الخطأ
20 دقراءة 4 دتمرين Python
الدرس في لمحة
غلّف المنطق المتكرّر في دوال لها مُدخلات وقيم مُعادة، ونسّق الأرقام للتقارير باستخدام f-strings، واقرأ الـ traceback في Python لتجد المشكلة الحقيقية وتصلحها.
لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.
حتى الآن نظّفت السعر " $129.00" مرة، وحسبت إيراد بند واحد مرة، وطبعت بضعة أرقام. لدى Cartwheel 3,991 بندًا في الطلبات. لا تريد نسخ كود التنظيف إلى كل مكان يحتاجه، ثم إصلاح خطأ واحد في سبع نسخ. الدوال تتيح لك كتابة المنطق مرة واحدة، ومنحه اسمًا، واستدعاءه حيثما احتجته.
تعريف دالة
def line_revenue(quantity, unit_price, discount=0.0):
"""Revenue of one order line: quantity x price, minus the discount."""
return round(quantity * unit_price * (1 - discount), 2)
print(line_revenue(2, 129.0, 0.15)) # 219.3
print(line_revenue(1, 39.0)) # discount defaults to 0.0
print(line_revenue(quantity=3, unit_price=24.0, discount=0.25))الأجزاء هي: def، ثم اسم الدالة، ثم المُعامِلات بين قوسين، ثم نقطتان رأسيتان، ثم جسم مُزاح. وdiscount=0.0 قيمة افتراضية تُستخدم حين يتركها المستدعي. والسطر المحاط بثلاث علامات تنصيص تحت def هو docstring، يوثّق ما تفعله الدالة؛ وتعرضه المحرّرات حين تمرّر المؤشر فوق الاسم.
ترسل return قيمة إلى المستدعي، فيصبح الاستدعاء line_revenue(2, 129.0, 0.15) هو تلك القيمة. تستطيع تخزينها، أو جمعها، أو تمريرها إلى دالة أخرى. والاستدعاء بالأسماء، كما في المثال الثالث، يجعل قوائم الوسائط الطويلة مقروءة، ويحميك من تبديل رقمين بالخطأ.
دوال التنظيف
هذه أداة تنظيف المبالغ من الدرس 1.2 وقد أصبحت قابلة لإعادة الاستخدام. تتعامل مع علامة الدولار والمسافات الزائدة وفواصل الآلاف:
def parse_money(text):
"""Turn strings like ' $1,234.50' into the float 1234.5."""
cleaned = text.strip().replace("$", "").replace(",", "")
return float(cleaned)
for raw in [" $129.00", "18.00", "$1,234.50"]:
print(raw, "->", parse_money(raw))امنح الدوال أسماء أفعال تقول ما تعيده (parse_money وline_revenue وclean_country)، واجعل لكل منها مهمة واحدة؛ الدوال الصغيرة سهلة الاختبار ببضعة استدعاءات لـ print مثل الحلقة السابقة. الآن يستطيع كل مجموع فوضوي في الملف المُصدَّر أن يمرّ عبر دالة واحدة مُختبَرة. وإذا اكتشفت صيغة جديدة الشهر القادم (لنقل USD في نهاية النص)، فتصلحها في مكان واحد.
الـ f-strings: أرقام يستطيع الناس قراءتها
تقرير يقول 146825.4412 يجعل القرّاء يضيّقون أعينهم. الـ f-string، أي نص يسبق علامة تنصيصه الأولى حرف f، تتيح لك وضع القيم داخل النص بين {} وتنسيقها بمواصفة بعد نقطتين رأسيتين:
revenue = 146825.4412
orders = 642
share = 0.4493
print(f"Q4 2025 revenue: ${revenue:,.2f}") # thousands separator, 2 decimals
print(f"Orders: {orders}, average {revenue / orders:.2f} per order")
print(f"Share of the year: {share:.1%}") # percent with 1 decimal
print(f"|{'Egypt':<12}|{orders:>6}|") # left- and right-aligned columnsالمواصفات التي ستستخدمها أكثر من غيرها: ,.2f للمبالغ المالية، و.1% للنِّسَب (تضرب في 100 نيابةً عنك)، و,.0f للأعداد الصحيحة الكبيرة، و</> مع عرض محدّد لمحاذاة النص. وأي تعبير يعمل داخل الأقواس المعقوفة، بما في ذلك عمليات حسابية مثل revenue / orders.
قراءة الأخطاء دون ذعر
حين لا تستطيع Python المتابعة، تُطلق استثناءً (exception) وتطبع traceback (تتبّع الخطأ). المبتدئون يقرؤونه من الأعلى فيتوهون. اقرأه من الأسفل:
Traceback (most recent call last):
File "report.py", line 9, in <module>
total = parse_money(row["Total"])
~~~^^^^^^^^^
KeyError: 'Total'السطر الأخير هو نوع الخطأ ورسالته: طُلب من قاموس المفتاح 'Total' وهو غير موجود فيه. وفوقه بسطر الكود الذي فشل، مع علامات تحت التعبير بالضبط، وفوق ذلك الملف ورقم السطر. والإصلاح هنا هو الاسم الحقيقي للعمود، 'total'.
الأخطاء التي ستقابلها أكثر من غيرها، وما تعنيه في أغلب الأحيان:
| الخطأ | السبب المعتاد |
|---|---|
NameError |
خطأ كتابي في اسم متغيّر، أو استخدامه قبل إسناد قيمة له |
KeyError |
مفتاح قاموس أو عمود DataFrame غير موجود (افحص الكتابة وحالة الأحرف) |
TypeError |
خلط بين الأنواع، مثل نص زائد رقم، أو استدعاء دالة بوسائط خاطئة |
ValueError |
النوع صحيح لكن المحتوى ليس كذلك، مثل float("$65.00") |
IndexError |
موقع في القائمة بعد نهايتها |
AttributeError |
استدعاء method لا تملكها القيمة، وكثيرًا ما يحدث مع None |
التعامل مع خطأ تتوقّعه
بعض حالات الفشل جزء من البيانات، لا أخطاء في الكود. مجموع فوضوي مثل "N/A" لن يصبح رقمًا أبدًا. تتيح لك try / except أن تقرّر ما يحدث بدلًا من ذلك:
def parse_money_or_none(text):
try:
return float(text.strip().replace("$", "").replace(",", ""))
except ValueError:
return None
print(parse_money_or_none("$65.00"), parse_money_or_none("N/A"))التقط الاستثناء المحدّد الذي تتوقّعه (ValueError هنا) ولا شيء غيره. أما except: المجرّدة فستبتلع أيضًا خطأً كتابيًا في كودك أنت، وستحصل على None في كل مكان دون أي فكرة عن السبب.
بهذا تكتمل عُدّتك من Python. القسم 2 يضعها في العمل على نطاق واسع: pandas، حيث يعمل سطر واحد على كل صفوف الجدول.
أهم النقاط
- الدالة تمنح جزءًا من المنطق اسمًا؛ المُعامِلات (parameters) هي مُدخلاتها، و
returnتعيد مُخرجها. - الدالة التي تطبع بدلًا من أن تُعيد تعطيك
None، فلا يمكن استخدام نتيجتها في حسابات لاحقة. - الـ f-strings تنسّق القيم داخل النص:
f"{revenue:,.2f}"تعطي1,234.50، وf"{share:.1%}"تعطي12.5%. - اقرأ الـ traceback من الأسفل - السطر الأخير يسمّي نوع الخطأ ورسالته، والأسطر التي فوقه تبيّن أين حدث.
- استخدم
try/exceptللتعامل مع خطأ تتوقّعه، مثل نص لا يمكن أن يصبح رقمًا؛ ولا تستخدمها أبدًا لإخفاء أخطاء لا تفهمها.