EduFlow
Python لتحليل البيانات
⁦0%⁩

الوحدة 1 · أساسيات Python للمحللين

الدوال والـ f-strings وقراءة رسائل الخطأ

20 دقراءة 4 دتمرين Python

الدرس في لمحة

غلّف المنطق المتكرّر في دوال لها مُدخلات وقيم مُعادة، ونسّق الأرقام للتقارير باستخدام f-strings، واقرأ الـ traceback في Python لتجد المشكلة الحقيقية وتصلحها.

  1. 1تعريف دالة
  2. 2دوال التنظيف
  3. 3الـ f-strings: أرقام يستطيع الناس قراءتها
  4. 4قراءة الأخطاء دون ذعر

لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.

حتى الآن نظّفت السعر " $129.00" مرة، وحسبت إيراد بند واحد مرة، وطبعت بضعة أرقام. لدى Cartwheel ‏3,991 بندًا في الطلبات. لا تريد نسخ كود التنظيف إلى كل مكان يحتاجه، ثم إصلاح خطأ واحد في سبع نسخ. الدوال تتيح لك كتابة المنطق مرة واحدة، ومنحه اسمًا، واستدعاءه حيثما احتجته.

تعريف دالة

Python
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 وقد أصبحت قابلة لإعادة الاستخدام. تتعامل مع علامة الدولار والمسافات الزائدة وفواصل الآلاف:

Python
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، تتيح لك وضع القيم داخل النص بين {} وتنسيقها بمواصفة بعد نقطتين رأسيتين:

Python
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 (تتبّع الخطأ). المبتدئون يقرؤونه من الأعلى فيتوهون. اقرأه من الأسفل:

Text
Traceback (most recent call last):
  File "report.py", line 9, in <module>
    total = parse_money(row["Total"])
                        ~~~^^^^^^^^^
KeyError: 'Total'

السطر الأخير هو نوع الخطأ ورسالته: طُلب من قاموس المفتاح 'Total' وهو غير موجود فيه. وفوقه بسطر الكود الذي فشل، مع علامات تحت التعبير بالضبط، وفوق ذلك الملف ورقم السطر. والإصلاح هنا هو الاسم الحقيقي للعمود، 'total'.

traceback من ثلاث طبقات. في الأسفل: نوع الخطأ ورسالته، وتُقرأ أولًا. في الوسط: سطر الكود الذي فشل مع العلامات. في الأعلى: الملف ورقم السطر، وتستخدمهما لتجد المكان في كودك. File "report.py", line 9 total = parse_money(row["Total"]) KeyError: 'Total' 1. ما الخطأ 2. أيّ تعبير 3. أين تبحث
اقرأ الـ traceback من الأسفل إلى الأعلى

الأخطاء التي ستقابلها أكثر من غيرها، وما تعنيه في أغلب الأحيان:

الخطأ السبب المعتاد
NameError خطأ كتابي في اسم متغيّر، أو استخدامه قبل إسناد قيمة له
KeyError مفتاح قاموس أو عمود DataFrame غير موجود (افحص الكتابة وحالة الأحرف)
TypeError خلط بين الأنواع، مثل نص زائد رقم، أو استدعاء دالة بوسائط خاطئة
ValueError النوع صحيح لكن المحتوى ليس كذلك، مثل float("$65.00")
IndexError موقع في القائمة بعد نهايتها
AttributeError استدعاء method لا تملكها القيمة، وكثيرًا ما يحدث مع None

التعامل مع خطأ تتوقّعه

بعض حالات الفشل جزء من البيانات، لا أخطاء في الكود. مجموع فوضوي مثل "N/A" لن يصبح رقمًا أبدًا. تتيح لك try / except أن تقرّر ما يحدث بدلًا من ذلك:

Python
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 للتعامل مع خطأ تتوقّعه، مثل نص لا يمكن أن يصبح رقمًا؛ ولا تستخدمها أبدًا لإخفاء أخطاء لا تفهمها.

قراءات إضافية

تحقّق من فهمك

4 أسئلة

السؤال 1 من 4

ما قيمة result بعد تشغيل هذا الكود؟

Python
def add_tax(amount):
    print(amount * 1.2)

result = add_tax(100)
السؤال 2 من 4

أيّ f-string تطبع Revenue: $146,825.44 حين تكون revenue = 146825.4412؟

السؤال 3 من 4

السطر الأخير من الـ traceback يقول:

Text
KeyError: 'Total'

ما السبب الأرجح؟

السؤال 4 من 4

متى يكون تغليف الكود بـ try / except فكرة جيدة؟

تدريب

تمرين Python

ثلاث دوال مساعدة للتقرير

أكمل ثلاث دوال. parse_money(text) تعيد عددًا عشريًا من نصوص مثل " $1,234.50" أو "$129.00" أو "18.00". وline_revenue(quantity, unit_price, discount=0.0) تعيد الكمية × سعر الوحدة × (1 − الخصم)، مقرّبًا إلى منزلتين عشريتين؛ والخصم الافتراضي 0. وformat_money(amount) تعيد نصًا مثل "$1,234.50": علامة دولار، وفواصل للآلاف، ومنزلتان عشريتان بالضبط. يجب أن تُعيد كل دالة نتيجتها بـ return، لا أن تطبعها.

def parse_money(text):
    """' $1,234.50' -> 1234.5"""
    pass


def line_revenue(quantity, unit_price, discount=0.0):
    """quantity x unit_price x (1 - discount), rounded to 2 decimals"""
    pass


def format_money(amount):
    """1234.5 -> '$1,234.50'"""
    pass


print(parse_money(" $1,234.50"), line_revenue(2, 129.0, 0.15), format_money(1234.5))
جارٍ تحميل المحرّر…

Ctrl/⌘ + Enter للتشغيل · يعمل في بيئة معزولة داخل متصفّحك. لا شيء يغادر جهازك.

(لا مخرجات)

الفحوص

  • parse_money تتعامل مع "18.00" و" $129.00"
  • parse_money تتعامل مع فواصل الآلاف: "$1,234.50" تصبح 1234.5
  • line_revenue تطبّق الخصم وتقرّب إلى منزلتين عشريتين
  • line_revenue تعمل دون تمرير وسيط الخصم
  • format_money(1234.5) تعيد "$1,234.50"