متتبع البصمة الكربونية
خياراتك اليومية تنبعث منها كربون: قيادة 10 كيلومترات ليست كركوب الدراجة 10 كيلومترات ولا كالقطار 10 كيلومترات، وأكل اللحم ليس كأكل النبات. يبني هذا المشروع متتبّع كربون صغيرًا نزيهًا في الطرفية ، سكربت Python واحد يعرف كم كيلوغرامًا من مكافئ ثاني أكسيد الكربون يكلف كل نشاط، ويعمل خلال أسبوع نموذجي من مدخلات تنقّل وتحكُّم غذائي وكهرباء، ويجمع كل شيء باليوم وبالفئة، ويرسم مخطط أعمدة ASCII، ويفحص الأسبوع مقابل ميزانية، ويحفظ كل شيء في CSV، ويصبح أخيرًا أمرًا حقيقيًا بأوامر فرعية add وreport وreset. يستخدم المكتبة القياسية فقط ، لا تركيبات، لا عشوائية، فالأرقام التي تراها هنا هي الأرقام التي ستراها بالضبط.
هذا يفترض قوائم وقواميس Python وحلقات for واستخدامًا أساسيًا للطرفية. إنه مشروع اختياري غير مُقيَّم ، راجع مشاريع من العالم الحقيقي للاطلاع على القائمة الكاملة والنامية. كل قطعة تعمل على تركيب Python أساسي (3.10+).
🎯 ما ستفعله
- تعريف عوامل الانبعاث وأسبوعًا نموذجيًا؛ وحساب CO2e لكل نشاط.
- تجميع الأسبوع باليوم وبالفئة، ورسم مخطط أعمدة ASCII.
- فحص الأسبوع مقابل ميزانية أسبوعية.
- حفظ كل الصفوف في
activities.csvوتحميلها ثانية. - تحويل السكربت إلى CLI بأوامر
addوreportوreset.
أين تُشغّل هذا
محليًا هو الموطن الحقيقي لأداة CLI: أنشئ أي مجلد فارغ وملفًا واحدًا.
mkdir carbon-tracker && cd carbon-tracker
touch carbon_tracker.py
Google Colab وKaggle Notebooks وBinder تعمل أيضًا ، كل كتلة Python عادي، لا حزم طرف ثالث. جَرٍّ شبيه بالطرفية (% python3 carbon_tracker.py …) غير متاح في الدفاتر؛ هناك تستطيع استدعاء دوال CLI مباشرة. الـCSV والقيم متطابقة في كل مكان.
الإعداد
مجلد فارغ واحد، ملف واحد، صفر حزم.
فحص البيئة
python3 --version
أي شيء 3.10+ سليم. ثم أنشئ ملف المشروع:
mkdir carbon-tracker && cd carbon-tracker
touch carbon_tracker.py
✅ قائمة التحقق
- ✅ يطبع
python3 --versionإصدار 3.10 أو أحدث. - ✅ يوجد
carbon_tracker.pyفي مجلدcarbon-tracker. - ✅ لا حاجةً لـ
pip install، المشروع كلهimport csvوimport sysومُدمجات Python.
🤔 سؤال (أسئلة) سقراطي(ة) :
- يحوّل المتتبّع المقادير (كم، كيلوواط-ساعة، وجبات) إلى kg من CO2e بضربها في عامل لكل نشاط. من يختار تلك العوامل، ولماذا يتفق متتبّعان في الظاهر عن نفس رحلة السيارة؟
- هذا المشروع بلا عشوائية إطلاقًا. لماذا تهم قابلية التكرار لأداة مناخ أكثر من لعبة؟
الخطوة 1: عوامل الانبعاث وأسبوع نموذجي
كل رياضيات الكربون تعيش في قواميس اثنين: emissions (كغ CO2e لكل وحدة واحدة) وweek (الأنشطة المسجَّلة).
1.1 العوامل
👟 تلميح البداية : قاموس يربط كل نشاط بكغ من CO2e لكل وحدة ، كمٌّ للتنقل، وكيلوواط-ساعة للكهرباء، وكل وجبة للطعام.
# carbon_tracker.py
import csv
import sys
emissions = {
"car": 0.18, "bus": 0.10, "train": 0.04, "bike": 0.0,
"flight": 0.25, "electricity": 0.42,
"meal_meat": 2.2, "meal_veg": 0.8,
}
كل رقم لاحق ينبع من هذا الجدول. bike: 0.0 هو الصفر الذي يجعل الباقي ذا معنى ، تقيس الأرقام الكربون الإضافي الذي يكلفه كل خيار، لا «القيمة».
🎯 الناتج المتوقع : لا شيء بعد ، العوامل بيانات فقط. تحقق بالعين: وجبة لحم كبيرة meal_meat (2.2) تكلف نحو ثلاث وجبات نباتية (0.8)؛ وساعة كهرباء (0.42 لكل كيلوواط-ساعة) تقارب وجبة لحم.
1.2 الأسبوع النموذجي
👟 تلميح البداية : week قائمة من صُوَر (day, category, amount) ، تنقّل وغذاء وطاقة لسبعة أيام.
# carbon_tracker.py (continued)
week = [
("Mon", "car", 12), ("Mon", "meal_meat", 2), ("Mon", "electricity", 6),
("Tue", "bike", 8), ("Tue", "meal_veg", 3), ("Tue", "electricity", 5),
("Wed", "train", 25), ("Wed", "meal_meat", 1), ("Wed", "electricity", 6),
("Thu", "bus", 9), ("Thu", "meal_veg", 2), ("Thu", "electricity", 7),
("Fri", "car", 8), ("Fri", "meal_meat", 2), ("Fri", "electricity", 5),
("Sat", "train", 60), ("Sat", "meal_veg", 3), ("Sat", "electricity", 4),
("Sun", "bike", 20), ("Sun", "meal_veg", 2), ("Sun", "electricity", 4),
]
ثلاثة أوضاع تنقّل (لا رحلات جوية بعد)، ووجبات معدودة، وبعض كيلوواط-ساعات. تبقى الأرقام صغيرة كي يُتحقق من الحساب يدويًا.
🎯 الناتج المتوقع : لا شيء بعد ، البيانات معرّفة، لا مطبوعة.
1.3 احسب صفوف الكربون
👟 تلميح البداية : صف واحد لكل نشاط → تسطيح (day, category, amount) عبر emissions إلى (day, category, amount, kg)، بتقريب حاصل الضرب لرقمين عشريين.
# carbon_tracker.py (continued)
rows = []
for day, category, amount in week:
kg = round(emissions[category] * amount, 2)
rows.append({"day": day, "category": category, "amount": amount, "kg": kg})
for r in rows[:3]:
print(r)
total = round(sum(r["kg"] for r in rows), 2)
print("WEEK TOTAL:", total, "kg CO2e")
نمط القاموسين والحلقة الواحدة ، جدول حقائق من صفوف (day, category, amount, kg) ، هو الشكل ذاته الذي سيستخدمه csv وadd لاحقًا. كل ما بعده (المخططات، الميزانيات، الـCSV) يقرأ هذه القائمة، لا الصُوَر الخام.
🎯 الناتج المتوقع:
{'day': 'Mon', 'category': 'car', 'amount': 12, 'kg': 2.16}
{'day': 'Mon', 'category': 'meal_meat', 'amount': 2, 'kg': 4.4}
{'day': 'Mon', 'category': 'electricity', 'amount': 6, 'kg': 2.52}
WEEK TOTAL: 42.44 kg CO2e
🩹 إذا لم يعمل : إذا لم يكن kg لـcar 12 هو 2.16، انحرف مفتاح العامل (0.18 × 12 = 2.16). إذا طبع الإجمالي 84.88، فقائمتا weeks رُبطتا معًا ، أبقِ 21 صُوَرًا بالضبط.
1.4 تحقّق من الصفوف
✅ قائمة التحقق
- ✅ 21 صفًا بالضبط (7 أيام × 3 مدخلات)، كل منها بـ
dayوcategoryوamountوkg. - ✅
WEEK TOTAL: 42.44 kg CO2e، حتمي، لا عشوائية في أي مكان. - ✅ الإثنين: 2.16 (سيارة) + 4.4 (لحم) + 2.52 (طاقة) = 9.08.
🤔 سؤال (أسئلة) سقراطي(ة) :
- المنهجية: عوامل الانبعاث تضاعف الوحدات. إذا سجّلت «قدمت» فقط دون الكيلومترات، فما الذي لا يمكنك حسابه ، وماذا يقول ذلك عن أرخص طريقة لتحسين جودة البيانات (أعمدة أكثر لا صفوفًا أكثر)؟
- تكلف وجبات إثنين من اللحم (4.4 kg) ما تكلفه أيام نباتية مجمعة. متى سينبعث أسبوع بلا لحم أحمر أزيد من أسبوع به؟
الخطوة 2: التجميع باليوم وبالفئة
الصفوف المنفردة ضجيج؛ وظيفة المتتبّع التلخيص. تجمّع الخطوة 2 الإجماليات باليوم وبالفئة.
2.1 الإجماليات اليومية
👟 تلميح البداية : قاموس بمفتاح اليوم، يضيف kg كل صف.
# carbon_tracker.py (continued)
daily = {}
for r in rows:
daily[r["day"]] = round(daily.get(r["day"], 0) + r["kg"], 2)
for day in ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]:
print(f"{day} {daily[day]:>5} kg")
daily.get(day, 0) هي اصطلاحية المراكم: أول ظهور ليوم يبدأ من 0، وكل صف لاحق يضيف حصته. التقريب في النهاية (لا لكل خطوة) يُبقي المجموع نزيهًا.
🎯 الناتج المتوقع:
Mon 9.08 kg
Tue 4.5 kg
Wed 5.72 kg
Thu 5.44 kg
Fri 7.94 kg
Sat 6.48 kg
Sun 3.28 kg
🩹 إذا لم يعمل : إذا طبع الثلاثاء 8.6 بدل 4.5, فجولة الدراجة صفر-الكربون (8 كم × 0.0 = 0 كغ) عُدّت 8 ، تحقق من bike: 0.0 في emissions. إذا انحرفت الإجماليات بـ0.01، فتقريب kg لكل صف أولًا ثم الجمع يختلف عن الجمع ثم التقريب ، اختر قاعدة واحدة والتزمها.
2.2 مخطط أعمدة ASCII
👟 تلميح البداية : اطبق إجمالي كل يوم على "#" * round(v / max * 40).
# carbon_tracker.py (continued)
mx = max(daily.values())
for day in ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]:
bar = "#" * round(daily[day] / mx * 40)
print(f"{day} {daily[day]:>5} {bar}")
يعيد v / mx * 40 قياس أثقل يوم (الإثنين، 9.08) إلى عمود كامل من 40 محرفًا والباقي تناسبيًا ، مخطط أعمدة صديق للطابعة بلا مكتبة رسم. النقطة ليست الدقة؛ النمط ، الثلاثاء حتى الأحد أنحف مرئيًا من جري الإثنين.
🎯 الناتج المتوقع:
Mon 9.08 ########################################
Tue 4.5 ####################
Wed 5.72 #########################
Thu 5.44 ########################
Fri 7.94 ###################################
Sat 6.48 #############################
Sun 3.28 ##############
🩹 إذا لم يعمل : إذا كان عمود الإثنين قصيرًا، فحُسب max فوق الـمفاتيح (أسماء الأيام) لا القيم. إذا كانت الأعمدة 0 محرفًا, فلفّ round على نسبة صغيرة إلى 0 ، الأيام هنا كلها غير صفرية، فالعمود الفارغ يعني خطأ بيانات في المنبع.
2.3 تحقّق من التجميعات
✅ قائمة التحقق
- ✅ الإجماليات اليومية تعيد إنتاج الجدول أعلاه (الإثنين 9.08 … الأحد 3.28).
- ✅ الأعمدة تتدرج إلى 40
#للحد الأقصى (الإثنين) وتنكمش بعدل. - ✅ فحص الفئة المنطقية: النقل
7.9(4.31+1.0+0.9+3.4… مهلاً ، انظر السؤال السقراطي أدناه).
🤔 سؤال (أسئلة) سقراطي(ة) :
- قرّب الإجماليات حسب الفئة يدويًا: سيارة 20 كم (
0.18)، حافلة 9 كم (0.10)، قطار 85 كم (0.04)، دراجات (0)، لحم 5 وجبات (2.2)، نباتي 10 وجبات (0.8)، كهرباء 37 كيلوواط-ساعة (0.42). هل يصل مجموعها إلى 42.44 ، وأي فئة تحمل الأكثر؟ - مخططك يتدرج إلى الإثنين, أثقل يوم. غيّر المقام إلى أسبوع الإجمالي (42.44) بدل
max. تنكمش الأعمدة إلى ~20#. ما المقايضة بين «يعرض النمط» و«يعرض الكسر الحقيقي»؟ أي مقياس كنت ستعرضه لزميل صف؟
الخطوة 3: فحص الميزانية الأسبوعية
تحوّل الميزانية الإجماليات إلى قرارات. اختر 40 كغ/أسبوعًا كسقف.
3.1 فوق أم تحت؟
👟 تلميح البداية : قارن total بالميزانية وأبلغ عن الفائض/النقص المطلق والنسبي معًا.
# carbon_tracker.py (continued)
budget = 40.0
diff = round(total - budget, 2)
percent = round(total / budget * 100)
print(f"BUDGET: {budget} kg CO2e/week")
print(f"USED : {total} kg ({percent}% of budget)")
print(f"OVER : {diff} kg" if diff > 0 else f"UNDER: {-diff} kg saved")
النسبة هي أكثر رقم مفيد في الأداة: 106% تقول «متجاوز قليلًا» قبل أن تقرأ المطلق 42.44. سطر OVER/UNDER هو الحكم الموجه للإنسان.
🎯 الناتج المتوقع:
BUDGET: 40 kg CO2e/week
USED : 42.44 kg (106% of budget)
OVER : 2.44 kg
🩹 إذا لم يعمل : إذا رأيت UNDER: -2.44 فقد انقلبت الإشارة ، فرعا الثُلاثي على ذراعين خاطئين. إذا طبع 105% بعد التقريب، فقد قرّبت total لرقم واحد في مكان ما وتغيّرت المقارنة؛ احسب percent من الـtotal غير المقربة.
3.2 اجعل الحكم مفيدًا
👟 تلميح البداية : اطبع أثقل يوم وتلميحًا لأرخص إصلاح داخل الأسبوع.
# carbon_tracker.py (continued)
worst = max(daily, key=daily.get)
print(f"Biggest day: {worst} ({daily[worst]} kg)")
train_swap = 0.18 - 0.04
print(f"Ride the train: swap one 10-km car trip and save {round(train_swap * 10, 2)} kg")
إبلاغ السبب نصف أداة العمل البيئي. حكم ميزانية بلا أكبر يوم درجة بلا تغذية راجعة. يختار daily.get بوصفه وسيطة key لـmax المفتاح الأعلى قيمةً ، لا الأسبق أبجديًا ، وهو الاستخدام الكلاسيكي لـkey=.
🎯 الناتج المتوقع:
Biggest day: Mon (9.08 kg)
Ride the train: swap one 10-km car trip and save 1.4 kg
🩹 إذا لم يعمل : إذا طبع Biggest day القيمة Sun, فمررت max(daily) بدل max(daily, key=daily.get) ، فالأول يعيد سلسلة المفتاح الأقصى. إذا أظهر توفير الاستبدال 0.14، ففرق العامل 0.18 − 0.04 = 0.14 لكل كم ، ×10 كم = 1.4 كغ؛ أبقِ الضرب في نفس السطر.
3.3 تحقّق من الميزانية
✅ قائمة التحقق
- ✅ 42.44 مستهلكة مقابل ميزانية 40.0 →
OVER : 2.44 kg،106%. - ✅ أكبر يوم الإثنين (9.08)، وأرخص إصلاح 10-كم 1.4 كغ (قطار مقابل سيارة).
- ✅ فحص الميزانية دالة صافية لـ
total، غيّرbudget, تحصل على حكم جديد, ولا يتحرك كود آخر.
🤔 سؤال (أسئلة) سقراطي(ة) :
- 106% تعني «2.44 كغ فوق». لو كانت الميزانية 25 كغ، فأي تغيير واحد كان سيرد الأسبوع كله تحتها بجدار؟ اللحوم، أم القيادة، أم شيء آخر؟
- ميزانية مضبوطة على 40 كغ/أسبوع تخفي مَن ينبعث: أسبوعك النموذجي يفترض سيارة وحافلة وقطارات وثلاث وجبات لحم. لو أعدت بناء الأسبوع برحلة جوية، فصار حكم نفس ميزانية 40 كغ سخيفًا ، ماذا يقول ذلك عن مطابقة ميزانية لأسلوب الحياة المُقاس؟
الخطوة 4: احفظ الصفوف وأعد تحميلها
لا أداة تنجو من إعادة التشغيل بإعادة كتابة البيانات يدويًا. تكتب الخطوة 4 rows إلى activities.csv وتقرؤه ثانية.
4.1 اكتب الـCSV
👟 تلميح البداية : csv.DictWriter مع writeheader() ثم كل الصفوف.
# carbon_tracker.py (continued)
with open("activities.csv", "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=["day", "category", "amount", "kg"])
writer.writeheader()
writer.writerows(rows)
print("Saved", len(rows), "rows to activities.csv")
قائمة rows والـCSV هما الأعمدة الأربعة نفسها، فيمثل DictWriter كل قاموس سطرًا مباشرة. يوقف newline="" الأسطر الفارغة بين السجلات على Windows.
🎯 الناتج المتوقع : Saved 21 rows to activities.csv ، وملف أسطوره الأولى تبدو هكذا
day,category,amount,kg
Mon,car,12,2.16
Mon,meal_meat,2,4.4
🩹 إذا لم يعمل : إذا غاب الرأس أو تبدلت الأعمدة، فقائمة fieldnames لا تطابق مفاتيح القواميس. إذا رأيت أسطرًا فارغة داخل الـCSV، فاحذف newline="".
4.2 أعد التحميل وأعد حساب الأسبوع
👟 تلميح البداية : csv.DictReader، وجمع فوق عمود kg (سلاسل → عوامات).
# carbon_tracker.py (continued)
with open("activities.csv", newline="") as f:
loaded = list(csv.DictReader(f))
reload_total = round(sum(float(r["kg"]) for r in loaded), 2)
print("Reloaded", len(loaded), "rows, week total", reload_total, "kg")
الذهاب والعودة يثبت أن الحفظ بلا خسارة: الصفوف المحمَّلة تنتج نفس الـ42.44. لاحظ التحويل ، الـCSV يخزن نصًا، فعل float(r["kg"]) أن يحوّل "2.16" إلى رقم قبل الجمع.
🎯 الناتج المتوقع : Reloaded 21 rows, week total 42.44 kg
🩹 إذا لم يعمل : إذا رمى إعادة التحميل ValueError: could not convert string…، فتسرّب سطر بلا رأس أو محرَّر يدويًا؛ افحص الـCSV بمحرر نصوص. إذا اختلف الإجمالي عن 42.44، فتحويل العوامة أو صف فارغ إضافي يعودان إلى المجموع.
4.3 تحقّق من الذهاب والعودة
✅ قائمة التحقق
- ✅
activities.csvيحوي 4 أعمدة × 21 صف بيانات + رأس. - ✅ إعادة التحميل تعيد إنتاج
WEEK TOTAL: 42.44 kg. - ✅ الـCSV طلبية قابلة للقراءة البشرية ، يستطيع أي شخص فتحه في جدول بيانات.
🤔 سؤال (أسئلة) سقراطي(ة) :
- يكتب البرنامج حاليًا من
rowsفي كل جري، مستبدلًا الملف. حالما يوجدaddالـCLI من الخطوة 5، قد تمحو إعادة التشغيل المدخلات الجديدة. حين تصطدم بذلك، ما التغيير الأدنى ، اكتب مرة, ثم ألحق؟ - يعيد
DictReaderسلاسل؛ ومن السهل الخلط بين الأشكال والأرقام. سمِّ تحويل عمود-نوع آخر، مثل تحليل التواريخ، التي كانت وستحتاجها تطبيق «حقيقي» قبل أن يصبح هذا الـCSV جديرًا بالثقة.
الخطوة 5: تحويله إلى CLI
الخطوة الأخيرة تجعل المتتبّع أداة حقيقية: أوامر فرعية add وreport وreset مدفوعة بـsys.argv.
5.1 Report
👟 تلميح البداية : دالة report() تقرأ الـCSV وتعيد حساب الإجماليات والمخطط وحكم الميزانية.
# carbon_tracker.py (continued)
def load_rows():
with open("activities.csv", newline="") as f:
return list(csv.DictReader(f))
def report():
loaded = load_rows()
total = round(sum(float(r["kg"]) for r in loaded), 2)
daily = {}
for r in loaded:
daily[r["day"]] = round(daily.get(r["day"], 0) + float(r["kg"]), 2)
print(f"WEEK TOTAL: {total} kg ({round(total / 40.0 * 100)}% of budget)")
mx = max(daily.values())
for day in ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]:
print(f"{day} {daily.get(day, 0):>5} {'#' * round(daily.get(day, 0) / mx * 40)}")
report() هي الحساب ذاته للخطوتين 2–3، لكنها تقرأ من الملف المحفوظ ، الـCLI والتحليل دالة واحدة. ما زال daily.get(day, 0) يبلّغ عن يومٍ مفقودٍ كـ0 كغ بدل أن يتحطم.
🎯 الناتج المتوقع:
WEEK TOTAL: 42.44 kg (106% of budget)
Mon 9.08 ########################################
Tue 4.5 ####################
Wed 5.72 #########################
Thu 5.44 ########################
Fri 7.94 ###################################
Sat 6.48 #############################
Sun 3.28 ##############
🩹 إذا لم يعمل : إذا لم يطبع الـCLI شيئًا، فدالة report() لم تُستدعَ قط ، إرسال sys.argv (5.3) يأتي لاحقًا؛ الآن شغّل python3 carbon_tracker.py وأضف استدعاء report() عاديًا في أسفل الملف مؤقتًا.
5.2 Add و reset
👟 تلميح البداية : add(day, category, amount) تُلحِق صفًا مُحسبًا إلى الـCSV؛ وreset() تعيد كتابة الأسبوع النموذجي.
# carbon_tracker.py (continued)
def add(day, category, amount):
kg = round(emissions[category] * float(amount), 2)
with open("activities.csv", "a", newline="") as f:
writer = csv.DictWriter(f, fieldnames=["day", "category", "amount", "kg"])
writer.writerow({"day": day, "category": category, "amount": amount, "kg": kg})
report()
def reset():
rows = [{"day": d, "category": c, "amount": a,
"kg": round(emissions[c] * a, 2)} for d, c, a in week]
with open("activities.csv", "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=["day", "category", "amount", "kg"])
writer.writeheader()
writer.writerows(rows)
يفتح add في نمط الإلحاق ("a") فلا يعيد كتابة الملف ، تنضم الصفوف الجديدة إلى التاريخ، ويعيد report() الجمع من القرص. يعيد reset عمدًا بناء الأسبوع النموذجي الصنعي كي يبدأ كل مثال صفي من نفس خط الأساس 42.44.
🎯 الناتج المتوقع : لا ناتج بذاته ، يعيد كل من add وreset استدعاء report() في النهاية، فناتجهما المخطط الذي رأيته في 5.1.
5.3 المُوزِّع
👟 تلميح البداية : اربط أول وسيطة sys.argv بالدالة الصحيحة بـif/elif صغيرة.
# carbon_tracker.py (continued)
if __name__ == "__main__":
if len(sys.argv) < 2:
report()
elif sys.argv[1] == "report":
report()
elif sys.argv[1] == "add":
add(sys.argv[2], sys.argv[3], sys.argv[4])
elif sys.argv[1] == "reset":
reset()
else:
print("Commands: report | add <day> <category> <amount> | reset")
if __name__ == "__main__" تعني أن الملف يعمل كـبرنامج حين يُنفَّذ مباشرة (python3 carbon_tracker.py …) لكنه يبقى قابلًا للاستيراد كدوال حين يُستخدم في دفتر. الموزِّع هو الباب الأمامي للـCLI: سلسلة واحدة داخلة، دالة واحدة خارجة.
🎯 لنشغّله. عينة جديدة:
python3 carbon_tracker.py report
🎯 الناتج المتوقع:
WEEK TOTAL: 42.44 kg (106% of budget)
Mon 9.08 ########################################
Tue 4.5 ####################
Wed 5.72 #########################
Thu 5.44 ########################
Fri 7.94 ###################################
Sat 6.48 #############################
Sun 3.28 ##############
ثم رحلة سيارة 5 كم تُضاف يوم الجمعة:
python3 carbon_tracker.py add Fri car 5
🎯 الناتج المتوقع (الرأس، والإجمالي الجديد):
WEEK TOTAL: 43.34 kg (108% of budget)
Fri 8.84 ####################################
…
مهلاً ، قيادة 5 كم بعد reset تغيّر النتيجة نظيفًا: 42.44 + 0.90 = 43.34. الآن الاختيار الوحيد الذي يهم:
python3 carbon_tracker.py reset
python3 carbon_tracker.py add Sat flight 450
🎯 الناتج المتوقع (الرأس):
WEEK TOTAL: 154.94 kg (387% of budget)
رحلة جوية واحدة بطول 450 كم هي 0.25 × 450 = 112.5 كغ ، نحو ثلاثة أضعاف ميزانية هذا الأسبوع كله، وعمود الـ40-# في المخطط الآن يخص يوم السبت. هذه هي العناوين النزيهة التي وُجد المتتبّع ليقدّمها.
🩹 إذا لم يعمل : إذا أظهر add القيمة 108% أول مرة و387% في الثانية بالفعل، فلم يُعاد تعيين ملف العينة بين الجريتين (الإلحاقات تتراكم). reset أولًا، ثم add ، العينة مرساتك القابلة للتكرار.
🤔 سؤال (أسئلة) سقراطي(ة) :
- يأخذ
addملصق يوم (Fri) ، أيام الأسبوع النموذجي ملصقات لا تواريخ. ماذا كان سيتغير لو أصبحdayYYYY-MM-DDحقيقيًا؟ أي أجزاء منreport()(مفتاح المخطط، النافذة الأسبوعية) كانت ستضطر للتوقف عن ترميز الملصقات السبعة؟ - تبلغ هذه الأداة عن كغ لكل أسبوع لشخص واحد. تبعث الأسر في ماساتشوستس الذي في الترتيب 15,000 كج/عام. كم أسبوعًا نموذجيًا ذلك تقريبًا ، وماذا تخبرك النسبة بين بصمة الفرد والمتوسط الوطني عن مدى معنى الميزانيات الشخصية فعلًا؟
5.4 تحقّق من الـCLI
✅ قائمة التحقق
- ✅
reportمنresetطازج →42.44 kg (106%). - ✅
add Fri car 5بعد reset →43.34 kg (108%)؛ عمود الجمعة يكبر شقًا. - ✅
add Sat flight 450بعد reset →154.94 kg (387%)، والسبت يملك عمود الـ40 محرفًا. - ✅ الأوامر المجهولة تطبع سطر الاستخدام، لا تحطمًا.
⚠️ مآزق شائعة
max(daily)مقابلmax(daily, key=daily.get). الأول يختار أكبر سلسلة مفتاح («Wed»)، والثاني أكبر قيمة. خلطهما يسم أثقل يوم خطأً.- ترتيب التقريب. تقريب
rowsلرقمين عشريين ثم الجمع سليم ، لكن تقريب وسيط آخر (كالإجمالي اليومي) قبل مقارنة نزيهة يغيّر الجواب بمقدار 0.01. اختر سياسة تقريب واحدة والتزمها. - الإلحاق مقابل الاستبدال.
open(..., "w")يختار الاستبدال؛open(..., "a")يُلحِق. يجب أن يستخدمresetالنمط"w"وaddالنمط"a"، تبديلهما يكسر العرض (إما يمحو التاريخ أو يكدّس عليه). - نسيان تحويل العوامة. يعيد
DictReaderسلاسل؛ وsum(float(r["kg"]) for r in loaded)مطلوبة. جمع السلاسل إما يتحطم أو يلصق «2.164.4…». - ميزانية تتجاهل الفئة. 106% من الميزانية هي الحكم ، لكن فئة الأسطول (النقل) وفئة الطعام تجمعان أكثر من نصف الأسبوع؛ أصلح الخطأ فتظل الميزانية منفجرة.
- لا
resetبين عروض الـCLI. تشغيلاتaddالمتكررة تنمّي الـCSV بلا حدود. أعد التعيين ، أو وثّق خط الأساس ، وإلا «أسبوعك» يصبح شهرًا بهدوء.
ما بنيته للتو
متتبّع كربون طرفي من طرف إلى طرف: عوامل انبعاث، وجدول حقائق من صفوف (day, category, amount, kg), وتجميع يومي وفئوي بقواميس عادية، ومخطط أعمدة ASCII بلا تبعيات، وحكم ميزانية معبّر عنه كنسبة مئوية، وتثبيت CSV بذهاب وعودة بلا خسارة، وCLI من ثلاثة أوامر على sys.argv. الأفكار القابلة للانتقال هنا هي النمط: جدول وحدات يحوّل مقادير أنشطة عشوائية إلى رقم واحد قابل للمقارنة؛ ادمج الصفوف الضيقة في إجماليات يومية وفئوية بقاموس مكدَّس؛ اجعل الحكم نسبة مئوية لا كغ خام؛ اجعل الـCSV سجل الحقيقة فيكون التقرير دائمًا دالة للملف؛ وأبرز مقارنة مروعة واحدة (رحلة الـ450 كم) لأن أداة تطبع إجمالياتها فحسب تنسى ما تعنيه الأرقام.
شغّل نسخة أكمل دون أي إعداد محلي
examples/carbon-tracker/ في مستودع الدورة يحوي المتتبّع كاملًا كدفتر ، العوامل، والأسبوع النموذجي، والمخطط، والميزانية، وذهاب وعودة الـCSV، وCLI add/report/reset، قابل للتشغيل في Colab/Kaggle/Binder. استنسخ المستودع أو افتحه في Codespace.
إلى أين تذهب من هنا
- تتبّع أسبوعًا حقيقيًا: أبقِ المخطط ذاته، واستبدل
weekبمدخلاتك، واعرف رقمك الفعلي مقابل ميزانية 40 كغ حددتها لواقعك. - تحول من ملصقات الأيام إلى تواريخ حقيقية بـ
datetime.date, واجعلreportنافذةً «آخر 7 أيام» بدل مفتاح الإثنين–الأحد المرمَّز. - أضف مُوصي «الاستبدال»: ابحث عن النشاط المفرد الذي يقطع استبداله (
car → train,meal_meat → meal_veg) أكثر الكغ تحت الميزانية. - ارسم بـmatplotlib بدل
#: قاموسdailyذاته يغذّيplt.bar(days, values)بجهد أقل من رسم الأعمدة بنفسك.
شارك مشروعك مع الصف
بنيت شيئًا تفخر به؟ examples/student-projects/ معرض لمشاريع قدّمها طلاب آخرون ، وREADME الخاص به يحوي شرحًا كاملًا وودودًا للمبتدئين لإضافة مشروعك عبر pull request، حتى لو لم تستخدم git من قبل قط: عمل fork للمستودع، وإنشاء فرع، وتثبيت ملفاتك، وفتح الـ PR، خطوة بخطوة. لا يُفترض أي خبرة سابقة بـ git.
مرحبًا بك في كتابة Python خارج المتصفح. 🎓
أكمل كل خطوة ثم حدد المشروع كمكتمل لجمع نقاطه.