Yaliyomo

Wiki 5: Files, Exceptions na Virtual Environments

Mwezi 2 | Lengo kuu: Mwanafunzi aweze kusoma na kuandika files (txt, CSV, JSON), kushughulikia makosa kwa try/except, na kutengeneza virtual environment yenye requirements.txt.

Maandalizi ya Mwalimu (soma kabla ya wiki kuanza)

  • Soma:
  • Fanya mazoezi mwenyewe kwanza: andika code zote za sehemu "Andika code hii live" kwenye kompyuta yako ya kwanza KABLA ya kipindi. Usiandike code kwa mara ya kwanza mbele ya mwanafunzi.
  • Andaa folder: C:\Users\<jina>\Documents\python_kozi\wiki05\ na ufungue folder hilo kwenye VS Code (File → Open Folder). Hii ni muhimu kwa sababu files zinazoundwa na Python zitaonekana upande wa kushoto (Explorer).
  • Hakikisha: python --version inaonyesha 3.12 au zaidi kwenye PowerShell. Hakikisha una internet kwa Kipindi 3 (pip itapakua packages).
  • Kidokezo: Kwenye Windows, files zinaweza kuwa na encoding tofauti. Tutatumia encoding="utf-8" KILA mara tunapofungua file la maandishi — hii inazuia makosa ya herufi kama "é" au emoji.

Malengo ya Wiki (mwisho wa wiki mwanafunzi ataweza...)

  1. Kufungua file kwa open() na with, na kueleza modes "r", "w", "a".
  2. Kusoma file nzima, mstari kwa mstari, na kuandika/kuongeza maandishi.
  3. Kutumia pathlib.Path kujenga njia (paths), kuangalia kama file lipo, na kusoma/kuandika kwa haraka.
  4. Kusoma na kuandika CSV kwa csv.reader, csv.writer, csv.DictReader, csv.DictWriter.
  5. Kuhifadhi na kusoma data kwa JSON (json.dump, json.load, json.dumps, json.loads).
  6. Kutumia try / except / else / finally na kuchagua exception sahihi.
  7. Kutumia raise na kutengeneza custom exceptions.
  8. Kutengeneza na ku-activate virtual environment kwenye PowerShell, kusakinisha package kwa pip, na kutengeneza requirements.txt.

Kipindi 1 — Files: open, with, txt na pathlib

Mtiririko wa kipindi

  1. Marudio ya kazi ya nyumbani ya Wiki 4 (modules) + salamu
  2. Kwa nini files? open(), modes, close()
  3. with statement — live coding: kuandika na kusoma file
  4. Kusoma mstari kwa mstari, strip(), mode "a"
  5. Mapumziko mafupi
  6. pathlib.Path — paths, exists(), read_text(), write_text()
  7. Zoezi darasani
  8. Q&A + kazi ya nyumbani

Elezo kwa mwalimu (soma kwanza wewe)

Mpaka sasa, data zote za programu zetu zinapotea programu inapoisha (variables zinaishi kwenye RAM). File ni njia ya kuhifadhi data kwenye disk ili ibaki hata kompyuta ikizimwa.

open(jina, mode, encoding) inarudisha "file object". Modes muhimu:

  • "r" — read (soma). Ni default. File lisipokuwepo → FileNotFoundError.
  • "w" — write (andika). Inafuta maudhui yaliyokuwepo! Kama file halipo, linaundwa.
  • "a" — append (ongeza mwishoni). Haifuti kilichokuwepo.
  • "x" — create; inashindwa kama file tayari lipo (FileExistsError).

Baada ya kufungua lazima ufunge (f.close()), vinginevyo data inaweza isiandikwe kikamilifu. Ndio maana tunatumia with — "context manager" — inafunga file yenyewe hata kama kosa limetokea ndani.

Njia za kusoma:

  • f.read() → string moja yenye kila kitu.
  • f.readlines() → list ya mistari (kila mmoja una \n mwishoni).
  • for line in f: → mstari mmoja mmoja (bora kwa files kubwa).

f.write(text) haiongezi \n yenyewe — lazima uiweke wewe. (Tofauti na print.)

Relative path kama "data.txt" inatafutwa kwenye current working directory (folder ambalo terminal iko). Kwenye VS Code, ukibofya "Run" ▶, terminal inaweza kuwa kwenye folder tofauti na la script! Ndio maana pathlib na Path(__file__).parent ni muhimu: inatupa folder ambalo script yenyewe iko.

pathlib.Path ni njia ya kisasa ya kushughulikia paths:

  • Path("data") / "majina.txt" — operator / inaunganisha sehemu za path (inafanya kazi Windows na Linux).
  • p.exists(), p.is_file(), p.name, p.suffix, p.stem, p.parent
  • p.read_text(encoding="utf-8"), p.write_text(text, encoding="utf-8")
  • p.mkdir(parents=True, exist_ok=True) — tengeneza folder
  • Path.cwd() — folder la sasa; p.glob("*.txt") — tafuta files

Sema hivi kwa mwanafunzi

  • "Fikiria file kama daftari. open ni kufungua daftari. Mode "r" ni kusoma tu. Mode "w" ni kuchana kurasa zote na kuanza upya — hatari! Mode "a" ni kuendelea kuandika ukurasa unaofuata."
  • "with ni kama mlango wa kujifunga wenyewe (automatic door). Ukitoka chumbani, mlango unajifunga hata kama ulikuwa unakimbia kwa sababu ya moto (kosa)."
  • "RAM ni ubao wa darasani — ukifutwa, umepotea. Disk ni daftari — unalibeba nyumbani."
  • "Path ni kama anwani ya nyumba: mkoa / wilaya / mtaa / nyumba. Tunaunganisha sehemu kwa /."

Andika code hii live (share screen)

Hatua 1: Tengeneza file files_intro.py.

python
# files_intro.py
# Kuandika file kwa njia ya zamani (bila with)
f = open("salamu.txt", "w", encoding="utf-8")
f.write("Habari za asubuhi!\n")
f.write("Karibu kwenye kozi ya Python.\n")
f.close()
print("Nimeandika file.")

Run kwenye terminal: python files_intro.py. Onyesha salamu.txt imetokea kwenye Explorer ya VS Code. Ifungue.

Hatua 2: Badilisha kutumia with, na soma file.

python
with open("salamu.txt", "w", encoding="utf-8") as f:
    f.write("Habari za asubuhi!\n")
    f.write("Karibu kwenye kozi ya Python.\n")

with open("salamu.txt", "r", encoding="utf-8") as f:
    maudhui = f.read()

print(maudhui)
print(type(maudhui))

Output inayotarajiwa:

text
Habari za asubuhi!
Karibu kwenye kozi ya Python.

<class 'str'>

Uliza: "Kwa nini kuna mstari mtupu baada ya maandishi?" (Jibu: \n ya mwisho kwenye file + print inaongeza \n yake.)

Hatua 3: Mode "a" na kusoma mstari kwa mstari.

python
with open("majina.txt", "w", encoding="utf-8") as f:
    f.write("Asha\n")
    f.write("Baraka\n")

with open("majina.txt", "a", encoding="utf-8") as f:
    f.write("Neema\n")

with open("majina.txt", encoding="utf-8") as f:
    for namba, mstari in enumerate(f, start=1):
        print(namba, mstari.strip())

Output:

text
1 Asha
2 Baraka
3 Neema

Onyesha nini kinatokea bila .strip() (mistari mitupu katikati) — print(repr(mstari)) inaonyesha 'Asha\n'.

Hatua 4: Kuandika list kwa mara moja.

python
matunda = ["embe", "nanasi", "papai"]
with open("matunda.txt", "w", encoding="utf-8") as f:
    for tunda in matunda:
        f.write(tunda + "\n")
# au: f.write("\n".join(matunda) + "\n")

Hatua 5: pathlib.

python
from pathlib import Path

folder_la_script = Path(__file__).parent
print("Script iko:", folder_la_script)
print("Terminal iko:", Path.cwd())

data = folder_la_script / "data"
data.mkdir(exist_ok=True)

faili = data / "kumbukumbu.txt"
faili.write_text("Leo tumejifunza files.\n", encoding="utf-8")

print(faili.exists())        # True
print(faili.name)            # kumbukumbu.txt
print(faili.stem)            # kumbukumbu
print(faili.suffix)          # .txt
print(faili.read_text(encoding="utf-8"))

for p in folder_la_script.glob("*.txt"):
    print("Nimeona:", p.name)

Eleza: write_text inafungua, inaandika, inafunga — kwa mstari mmoja. Ni rahisi kwa files ndogo.

Hatua 6: Onyesha kosa kwa makusudi:

python
with open("halipo.txt", encoding="utf-8") as f:
    print(f.read())

Output: FileNotFoundError: [Errno 2] No such file or directory: 'halipo.txt' — sema: "Kipindi 2 tutajifunza kushughulikia makosa kama haya. Kwa sasa tunaweza kuangalia kwanza kwa Path.exists()."

Maswali ya kumuuliza mwanafunzi

  1. Mode "w" inafanya nini kama file tayari lina maandishi? — Inafuta kila kitu na kuanza upya.
  2. Kwa nini tunapendelea with? — Inafunga file yenyewe, hata kosa likitokea.
  3. f.write("Asha") mara mbili itatoa nini kwenye file? — AshaAsha (hakuna \n automatically).
  4. f.read() inarudisha aina gani ya data? — str.
  5. Tofauti ya Path.cwd() na Path(__file__).parent? — cwd ni folder la terminal; __file__ parent ni folder la script.
  6. Unaongezaje jina jipya bila kufuta majina ya zamani? — Mode "a".

Makosa ya kawaida

Kosa Ujumbe wa error Suluhisho
File halipo au liko folder jingine FileNotFoundError: [Errno 2] No such file or directory: 'data.txt' Angalia jina; tumia Path(__file__).parent / "data.txt"; hakikisha terminal iko folder sahihi (cd).
Kuandika kitu kisicho string TypeError: write() argument must be str, not int f.write(str(namba)) au f-string.
Kusoma file lililofunguliwa kwa "w" io.UnsupportedOperation: not readable Fungua kwa "r".
Kusahau encoding (herufi za ajabu kama é) au UnicodeDecodeError: 'charmap' codec can't decode... — Ongeza encoding="utf-8".
Backslash kwenye Windows path: "C:\new\test.txt" (\n ni newline!) Path isiyo sahihi / OSError Tumia r"C:\new\test.txt", au /, au Path.
Kutumia f nje ya with ValueError: I/O operation on closed file. Fanya kazi zote za file ndani ya block ya with.

Zoezi darasani

Zoezi 1.1: Andika programu inayomwomba mtumiaji majina 3 (kwa input) na kuyahifadhi kwenye wanafunzi.txt, kila jina mstari wake.

Zoezi 1.2: Andika programu inayosoma wanafunzi.txt na kuchapisha idadi ya majina na jina refu zaidi.

Zoezi 1.3: Tengeneza "shajara" (diary): kila mara programu inapoendeshwa, inaomba ujumbe mmoja na kuuongeza mwishoni mwa shajara.txt pamoja na tarehe (tumia from datetime import date).

Jibu
python
# 1.1
with open("wanafunzi.txt", "w", encoding="utf-8") as f:
    for i in range(3):
        jina = input(f"Jina la mwanafunzi {i + 1}: ")
        f.write(jina + "\n")

# 1.2
with open("wanafunzi.txt", encoding="utf-8") as f:
    majina = [mstari.strip() for mstari in f if mstari.strip()]
# (Kama comprehension bado ni mpya, tumia loop ya kawaida na append)
print("Idadi:", len(majina))
print("Jina refu zaidi:", max(majina, key=len))

# 1.3
from datetime import date
from pathlib import Path

shajara = Path(__file__).parent / "shajara.txt"
ujumbe = input("Andika ujumbe wa leo: ")
with open(shajara, "a", encoding="utf-8") as f:
    f.write(f"{date.today()}: {ujumbe}\n")
print(shajara.read_text(encoding="utf-8"))

Kumbuka: max(..., key=len) ni mpya — kama mwanafunzi hajui, mwache atumie loop:

python
refu = ""
for jina in majina:
    if len(jina) > len(refu):
        refu = jina

Kipindi 2 — CSV, JSON na Exceptions

Mtiririko wa kipindi

  1. Marudio ya kazi ya nyumbani (word counter)
  2. CSV: csv.writer, csv.reader, DictWriter, DictReader
  3. JSON: dump/load, dumps/loads
  4. Mapumziko
  5. Exceptions: try/except/else/finally
  6. Zoezi darasani
  7. Q&A + kazi ya nyumbani

Elezo kwa mwalimu (soma kwanza wewe)

CSV (Comma-Separated Values) ni file la maandishi lenye jedwali: kila mstari ni row, na safu (columns) zimetenganishwa na koma. Excel inaweza kulifungua. Kwa nini tusitumie split(",")? Kwa sababu thamani inaweza kuwa na koma ndani (mf. "Dar es Salaam, Tanzania") — module csv inashughulikia hilo kwa quotes.

Muhimu kwa Windows: fungua CSV kwa newline="" unapoandika, vinginevyo utapata mistari mitupu kati ya rows.

  • csv.writer(f) → writer.writerow([...]), writer.writerows([[...], [...]])
  • csv.reader(f) → kila row ni list ya strings (hata namba ni string! lazima int()/float()).
  • csv.DictWriter(f, fieldnames=[...]) → writeheader(), writerow({...})
  • csv.DictReader(f) → kila row ni dict; mstari wa kwanza unatumika kama keys.

JSON (JavaScript Object Notation) ni format ya kuhifadhi data zenye muundo (dict, list) — inatumiwa na web APIs kila mahali. Ramani ya aina: | Python | JSON | |--------|------| | dict | object {} | | list, tuple | array [] | | str | string (lazima " mbili) | | int, float | number | | True/False | true/false | | None | null |

  • json.dump(data, f) — andika kwenye file. json.load(f) — soma kutoka file.
  • json.dumps(data) — geuza kuwa string. json.loads(text) — string → Python.
  • (Kumbuka: "s" = string.) Tumia indent=2 kusoma kwa urahisi, na ensure_ascii=False kuhifadhi herufi kama "é" moja kwa moja.
  • Keys za dict zinakuwa strings daima kwenye JSON: {1: "a"} → {"1": "a"}. Set haiwezi kuwa JSON (TypeError).

Exceptions: Kosa linapotokea wakati programu inaendeshwa, Python "inarusha" (raises) exception. Isiposhikwa, programu inasimama na kuonyesha traceback. try/except inatuwezesha kuishika.

text
try:        -> code inayoweza kuleta kosa
except X:   -> inaendeshwa kama kosa la aina X limetokea
else:       -> inaendeshwa kama HAKUNA kosa
finally:    -> inaendeshwa DAIMA (kosa au la) — kwa usafi (cleanup)

Kanuni: shika exception maalum (ValueError, FileNotFoundError), si except: tupu — hiyo inaficha bugs na hata Ctrl+C. except Exception as e: inakubalika kama kinga ya mwisho, ukichapisha e.

Exceptions za kawaida: ValueError (int("abc")), ZeroDivisionError, KeyError (d["haipo"]), IndexError, TypeError ("a" + 1), FileNotFoundError, json.JSONDecodeError (JSON mbovu; ni aina ya ValueError).

Sema hivi kwa mwanafunzi

  • "CSV ni kama daftari la mahudhurio lenye mistari na safu. JSON ni kama fomu yenye sehemu zenye majina: 'Jina: ...', 'Umri: ...', na fomu ndani ya fomu."
  • "try/except ni kama mlinda lango (goalkeeper). Unajaribu (try) kitu; mpira (kosa) ukija, goalkeeper (except) anaudaka badala ya kufungwa goli (programu kufa)."
  • "finally ni kama kuzima taa unapotoka ofisini — unafanya hivyo kila siku, kazi iwe imeenda vizuri au vibaya."
  • "else ni zawadi: inaendeshwa tu kama kila kitu kilienda salama."

Andika code hii live (share screen)

Hatua 1: CSV writer/reader — csv_demo.py

python
import csv

wanafunzi = [
    ["jina", "umri", "mji"],
    ["Asha", 17, "Arusha"],
    ["Baraka", 18, "Dar es Salaam, Kinondoni"],
    ["Neema", 16, "Mwanza"],
]

with open("wanafunzi.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.writer(f)
    writer.writerows(wanafunzi)

with open("wanafunzi.csv", newline="", encoding="utf-8") as f:
    reader = csv.reader(f)
    kichwa = next(reader)          # ruka mstari wa kwanza (header)
    print("Header:", kichwa)
    for row in reader:
        print(row)

Output:

text
Header: ['jina', 'umri', 'mji']
['Asha', '17', 'Arusha']
['Baraka', '18', 'Dar es Salaam, Kinondoni']
['Neema', '16', 'Mwanza']

Fungua wanafunzi.csv uonyeshe: Baraka,18,"Dar es Salaam, Kinondoni" — quotes zimeongezwa. Onyesha '17' ni string.

Hatua 2: DictReader na hesabu

python
import csv

with open("wanafunzi.csv", newline="", encoding="utf-8") as f:
    reader = csv.DictReader(f)
    jumla = 0
    idadi = 0
    for row in reader:
        print(row["jina"], "anaishi", row["mji"])
        jumla += int(row["umri"])
        idadi += 1

print("Wastani wa umri:", jumla / idadi)

Output ya mwisho: Wastani wa umri: 17.0

Hatua 3: DictWriter

python
import csv

bidhaa = [
    {"jina": "Sukari", "bei": 3000, "idadi": 20},
    {"jina": "Mchele", "bei": 2500, "idadi": 50},
]
with open("bidhaa.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["jina", "bei", "idadi"])
    writer.writeheader()
    writer.writerows(bidhaa)

Hatua 4: JSON — json_demo.py

python
import json

mwanafunzi = {
    "jina": "Asha",
    "umri": 17,
    "masomo": ["Python", "Hisabati"],
    "amelipa": True,
    "simu": None,
}

with open("mwanafunzi.json", "w", encoding="utf-8") as f:
    json.dump(mwanafunzi, f, indent=2, ensure_ascii=False)

with open("mwanafunzi.json", encoding="utf-8") as f:
    data = json.load(f)

print(data["masomo"][0])   # Python
print(type(data))          # <class 'dict'>

maandishi = json.dumps(mwanafunzi)
print(maandishi)
print(type(maandishi))     # <class 'str'>

nyuma = json.loads('{"a": 1, "b": [true, null]}')
print(nyuma)               # {'a': 1, 'b': [True, None]}

Fungua mwanafunzi.json uonyeshe true, null na quotes mbili.

Hatua 5: Exceptions — makosa_demo.py. Kwanza onyesha programu ikifa:

python
umri = int(input("Umri wako: "))   # andika "kumi"

ValueError: invalid literal for int() with base 10: 'kumi'. Fundisha kusoma traceback: soma mstari wa mwisho kwanza (aina ya kosa na ujumbe), kisha mstari wenye line N.

Kisha:

python
try:
    umri = int(input("Umri wako: "))
except ValueError:
    print("Tafadhali andika namba, mfano 17.")
else:
    print(f"Mwakani utakuwa na miaka {umri + 1}.")
finally:
    print("Asante kwa kutumia programu.")

Endesha mara mbili: 17 na kumi.

Hatua 6: Except nyingi na as e

python
def gawanya():
    try:
        a = int(input("Namba ya kwanza: "))
        b = int(input("Namba ya pili: "))
        jibu = a / b
    except ValueError:
        print("Hiyo si namba.")
    except ZeroDivisionError as e:
        print("Huwezi kugawanya kwa sifuri:", e)
    else:
        print("Jibu:", jibu)

gawanya()

Hatua 7: Loop mpaka mtumiaji aandike sahihi (pattern muhimu sana):

python
while True:
    try:
        namba = int(input("Andika namba kati ya 1 na 10: "))
        break
    except ValueError:
        print("Si namba, jaribu tena.")
print("Umeandika", namba)

Hatua 8: File + JSON + exception pamoja

python
import json
from pathlib import Path

faili = Path("mipangilio.json")
try:
    with open(faili, encoding="utf-8") as f:
        mipangilio = json.load(f)
except FileNotFoundError:
    print("Hakuna mipangilio, natumia default.")
    mipangilio = {"lugha": "sw", "rangi": "bluu"}
except json.JSONDecodeError:
    print("File la JSON limeharibika!")
    mipangilio = {}
print(mipangilio)

Onyesha: andika {lugha: sw (JSON mbovu) kwenye mipangilio.json kisha endesha tena → "File la JSON limeharibika!".

Maswali ya kumuuliza mwanafunzi

  1. csv.reader inarudisha namba kama int au string? — String daima; lazima ugeuze.
  2. Kwa nini newline=""? — Kuzuia mistari mitupu kati ya rows kwenye Windows.
  3. Tofauti ya json.dump na json.dumps? — dump inaandika kwenye file; dumps inarudisha string.
  4. True ya Python inakuwa nini kwenye JSON? — true. None → null.
  5. else kwenye try inaendeshwa lini? — Kama hakuna exception iliyotokea ndani ya try.
  6. finally inaendeshwa lini? — Daima.
  7. Kwa nini except: tupu ni mbaya? — Inashika kila kitu, hata makosa ya kuandika code (bugs) na Ctrl+C, kwa hiyo hujui kilichoharibika.

Makosa ya kawaida

Kosa Ujumbe wa error Suluhisho
Kusahau kugeuza string ya CSV TypeError: unsupported operand type(s) for +=: 'int' and 'str' int(row["umri"])
Key isiyo sahihi kwenye DictReader (mf. nafasi au herufi kubwa) KeyError: 'Jina' Chapisha reader.fieldnames uone keys halisi.
Mistari mitupu kwenye CSV (Windows) — newline=""
Kuhifadhi set au object kwenye JSON TypeError: Object of type set is not JSON serializable Geuza kuwa list: list(s).
JSON yenye quotes moja {'a': 1} json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes JSON inahitaji " mbili.
json.load("file.json") (kupitisha jina badala ya file object) AttributeError: 'str' object has no attribute 'read' Fungua kwanza kwa with open(...) as f: json.load(f)
except ValueError imewekwa lakini kosa ni ZeroDivisionError Programu bado inakufa Ongeza except ya aina hiyo.
Variable iliyoundwa ndani ya try inatumika baada ya kosa NameError: name 'umri' is not defined Itumie ndani ya else, au ipe thamani ya default kabla ya try.

Zoezi darasani

Zoezi 2.1: Tengeneza alama.csv yenye columns jina,alama kwa wanafunzi 4 (kwa csv.writer). Kisha soma file na uchapishe aliyepata alama ya juu na wastani.

Zoezi 2.2: Andika function hifadhi_mawasiliano(jina, simu) inayoongeza mtu kwenye mawasiliano.json (dict ya jina → simu). Kama file halipo, ianze na dict tupu.

Zoezi 2.3: Andika programu inayouliza jina la file na kuchapisha idadi ya mistari. Kama file halipo, sema "File halipo" badala ya kufa.

Jibu
python
# 2.1
import csv

with open("alama.csv", "w", newline="", encoding="utf-8") as f:
    w = csv.writer(f)
    w.writerow(["jina", "alama"])
    w.writerows([["Asha", 88], ["Baraka", 74], ["Neema", 93], ["Juma", 65]])

bora_jina = None
bora_alama = -1
jumla = 0
idadi = 0
with open("alama.csv", newline="", encoding="utf-8") as f:
    for row in csv.DictReader(f):
        alama = int(row["alama"])
        jumla += alama
        idadi += 1
        if alama > bora_alama:
            bora_alama = alama
            bora_jina = row["jina"]
print(f"Bora: {bora_jina} ({bora_alama})")
print(f"Wastani: {jumla / idadi:.1f}")
# Bora: Neema (93)
# Wastani: 80.0

# 2.2
import json
from pathlib import Path

FAILI = Path("mawasiliano.json")

def hifadhi_mawasiliano(jina, simu):
    try:
        with open(FAILI, encoding="utf-8") as f:
            data = json.load(f)
    except FileNotFoundError:
        data = {}
    data[jina] = simu
    with open(FAILI, "w", encoding="utf-8") as f:
        json.dump(data, f, indent=2, ensure_ascii=False)

hifadhi_mawasiliano("Asha", "0712345678")
hifadhi_mawasiliano("Juma", "0755111222")
print(FAILI.read_text(encoding="utf-8"))

# 2.3
jina = input("Jina la file: ")
try:
    with open(jina, encoding="utf-8") as f:
        mistari = f.readlines()
except FileNotFoundError:
    print("File halipo")
else:
    print("Idadi ya mistari:", len(mistari))

Kipindi 3 — raise, Custom Exceptions, venv na pip

Mtiririko wa kipindi

  1. Marudio ya kazi ya nyumbani (CSV/JSON)
  2. raise na custom exceptions
  3. Virtual environment: kwa nini, python -m venv, activate, execution policy
  4. Mapumziko
  5. pip install, pip list, pip freeze > requirements.txt, pip install -r
  6. Zoezi darasani (mradi mdogo: kitabu cha matumizi + package rich)
  7. Q&A + kazi ya nyumbani + muhtasari wa wiki

Elezo kwa mwalimu (soma kwanza wewe)

raise: Mpaka sasa Python ndiyo imekuwa ikirusha exceptions. Sisi pia tunaweza: raise ValueError("Umri hauwezi kuwa hasi"). Hii ni njia ya function kusema "nimepewa data mbaya, siwezi kuendelea" — badala ya kurudisha thamani ya ajabu kimya kimya. Anayeita function ndiye anayeamua kufanya nini (kwa try/except).

Custom exceptions: tunatengeneza aina yetu ya kosa kwa kurithi (inherit) kutoka Exception:

python
class SalioHalitoshi(Exception):
    pass

(Mwanafunzi bado hajasoma classes — Wiki 6! Sema tu: "hii ni namna ya kutengeneza aina mpya ya kosa; tutaelewa class kikamilifu wiki ijayo." Ni sawa kuitumia kama "template".) Faida: tunaweza kushika makosa yetu tu, bila kuchanganya na ValueError za kawaida.

raise bila kitu ndani ya except inarusha tena kosa lile lile (re-raise). raise NewError(...) from e inaunganisha makosa — taja tu kwa ufupi.

Virtual environment (venv): Ni folder lenye "nakala binafsi" ya Python na packages kwa ajili ya mradi mmoja. Kwa nini? Mradi A unahitaji requests 2.28, mradi B unahitaji requests 2.32. Bila venv, packages zote zinasakinishwa sehemu moja (global) na zinagongana. Kila mradi → venv yake.

Hatua kwenye PowerShell (ndani ya folder la mradi):

powershell
python -m venv .venv            # tengeneza venv kwenye folder .venv
.\.venv\Scripts\Activate.ps1    # activate

Baada ya kuactivate, prompt inaanza na (.venv). Sasa python na pip ni za venv. deactivate kutoka.

Tatizo maarufu la Windows: kuactivate kunaweza kuleta:

text
.\.venv\Scripts\Activate.ps1 : File C:\...\Activate.ps1 cannot be loaded because running scripts is disabled on this system.

Hii ni kwa sababu PowerShell kwa default inazuia scripts. Suluhisho (mara moja tu, kwa user wako, haihitaji Administrator):

powershell
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

Jibu Y ikiuliza. Njia mbadala ya muda (kwa terminal hii tu): Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process.

VS Code: baada ya kutengeneza .venv, bonyeza Ctrl+Shift+P → "Python: Select Interpreter" → chagua ile yenye .venv. Terminal mpya za VS Code zitaactivate venv zenyewe.

pip ni program ya kusakinisha packages kutoka PyPI (pypi.org). Tumia python -m pip ... — inahakikisha pip ni ya Python unayoitumia.

  • python -m pip install rich — sakinisha
  • python -m pip list — orodha
  • python -m pip show rich — taarifa
  • python -m pip uninstall rich
  • python -m pip freeze > requirements.txt — hifadhi orodha ya packages na versions
  • python -m pip install -r requirements.txt — sakinisha zote (mf. kwenye kompyuta nyingine)

Kumbuka: kwenye PowerShell ya Windows 5.1, > inaandika file kwa UTF-16, ambalo pip install -r bado inasoma vizuri kwenye matoleo mapya; lakini kama kuna tatizo, tumia python -m pip freeze | Out-File -Encoding utf8 requirements.txt.

Folder .venv halitumwi kwa wengine wala kwenye GitHub (Wiki 8: .gitignore); tunatuma requirements.txt tu.

Sema hivi kwa mwanafunzi

  • "raise ni kama mwamuzi kupiga filimbi: 'Faulo! Mchezo usimame.' Function inasema 'data hii si sahihi!'"
  • "Custom exception ni kama kutengeneza kadi yako mwenyewe — si 'kadi ya njano' ya kawaida bali 'kadi ya SalioHalitoshi'. Unaweza kuidaka hiyo hasa."
  • "Virtual environment ni kama sanduku la vifaa la kila fundi. Fundi wa umeme na fundi wa bomba hawachanganyi vifaa vyao. Kila mradi una sanduku lake."
  • "requirements.txt ni kama orodha ya manunuzi: unampa mtu orodha, si duka zima. Yeye ananunua (pip install -r) mwenyewe."

Andika code hii live (share screen)

Hatua 1: raise — raise_demo.py

python
def weka_umri(umri):
    if not isinstance(umri, int):
        raise TypeError("Umri lazima uwe namba kamili (int).")
    if umri < 0 or umri > 130:
        raise ValueError(f"Umri {umri} si sahihi.")
    return umri

print(weka_umri(20))

try:
    weka_umri(-5)
except ValueError as e:
    print("Kosa:", e)

try:
    weka_umri("ishirini")
except TypeError as e:
    print("Kosa:", e)

Output:

text
20
Kosa: Umri -5 si sahihi.
Kosa: Umri lazima uwe namba kamili (int).

Hatua 2: Custom exception — benki_mini.py

python
class SalioHalitoshi(Exception):
    """Inarushwa pale mtu anapotoa pesa zaidi ya salio."""
    pass


class KiasiSiSahihi(Exception):
    pass


def toa_pesa(salio, kiasi):
    if kiasi <= 0:
        raise KiasiSiSahihi("Kiasi lazima kiwe zaidi ya sifuri.")
    if kiasi > salio:
        raise SalioHalitoshi(f"Salio ni {salio}, umeomba {kiasi}.")
    return salio - kiasi


salio = 10_000
for ombi in [3_000, 20_000, -50]:
    try:
        salio = toa_pesa(salio, ombi)
    except SalioHalitoshi as e:
        print("Samahani:", e)
    except KiasiSiSahihi as e:
        print("Kosa:", e)
    else:
        print(f"Umetoa {ombi}. Salio jipya: {salio}")

Output:

text
Umetoa 3000. Salio jipya: 7000
Samahani: Salio ni 7000, umeomba 20000.
Kosa: Kiasi lazima kiwe zaidi ya sifuri.

Eleza 10_000 — underscore ni kwa kusoma rahisi tu, ni sawa na 10000.

Hatua 3: venv — kwenye terminal ya VS Code (PowerShell). Tengeneza folder jipya:

powershell
mkdir mradi_venv
cd mradi_venv
python -m venv .venv
.\.venv\Scripts\Activate.ps1

Kama kosa la "running scripts is disabled" litatokea — hii ni nafasi nzuri ya kufundisha:

powershell
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
.\.venv\Scripts\Activate.ps1

Thibitisha:

powershell
python -c "import sys; print(sys.prefix)"

Output inapaswa kuishia na ...\mradi_venv\.venv. Linganisha baada ya deactivate — itaonyesha folder la Python ya global.

Hatua 4: pip

powershell
python -m pip install rich
python -m pip list
python -m pip freeze > requirements.txt
Get-Content requirements.txt

requirements.txt itakuwa na kitu kama:

text
markdown-it-py==4.0.0
mdurl==0.1.2
Pygments==2.19.2
rich==14.2.0

(Versions zinaweza kutofautiana — si tatizo.) Eleza: rich inahitaji packages nyingine (dependencies), ndio maana ziko nne.

Tengeneza rangi.py ndani ya mradi_venv:

python
from rich import print
from rich.table import Table

print("[bold green]Habari![/bold green] Karibu kwenye [red]Python[/red].")

jedwali = Table(title="Wanafunzi")
jedwali.add_column("Jina")
jedwali.add_column("Alama", justify="right")
jedwali.add_row("Asha", "88")
jedwali.add_row("Baraka", "74")
print(jedwali)

Endesha python rangi.py. Kisha deactivate na endesha tena → ModuleNotFoundError: No module named 'rich' (kama rich haiko global). Hii inathibitisha venv inafanya kazi.

Hatua 5: Kuunda upya mazingira (kuiga kompyuta nyingine):

powershell
deactivate
Remove-Item -Recurse -Force .venv
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -r requirements.txt
python rangi.py

Maswali ya kumuuliza mwanafunzi

  1. Kwa nini function itumie raise badala ya print("kosa")? — Print haisimamishi programu wala haimjulishi anayeita; raise inamlazimisha anayeita kushughulikia kosa.
  2. Custom exception inarithi kutoka wapi? — Exception.
  3. Utajuaje venv iko active? — Prompt ina (.venv) mwanzoni; sys.prefix inaonyesha folder la venv.
  4. Kwa nini tusitume folder .venv kwa rafiki? — Ni kubwa, lina paths za kompyuta yako; anatengeneza lake kwa requirements.txt.
  5. Amri gani inasakinisha packages zote kutoka requirements.txt? — python -m pip install -r requirements.txt
  6. Kosa la "running scripts is disabled" linatatuliwaje? — Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

Makosa ya kawaida

Kosa Ujumbe wa error Suluhisho
Execution policy Activate.ps1 cannot be loaded because running scripts is disabled on this system Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
Kuandika source .venv/bin/activate (amri ya Linux/Mac) source : The term 'source' is not recognized... Windows: .\.venv\Scripts\Activate.ps1
Kusakinisha bila kuactivate venv Package inaenda global; ndani ya venv ModuleNotFoundError Activate kwanza, kisha python -m pip install.
VS Code inatumia interpreter tofauti Import "rich" could not be resolved (mstari wa njano) Ctrl+Shift+P → Python: Select Interpreter → .venv
pip haitambuliki pip : The term 'pip' is not recognized... Tumia python -m pip
Kuita file lako json.py au csv.py AttributeError: module 'json' has no attribute 'dump' Badilisha jina la file lako; futa __pycache__.
raise "kosa" (string) TypeError: exceptions must derive from BaseException raise ValueError("kosa")

Zoezi darasani

Zoezi 3.1: Andika function angalia_alama(alama) inayorusha ValueError kama alama si kati ya 0 na 100, vinginevyo inarudisha grade ("A" ≥ 80, "B" ≥ 65, "C" ≥ 50, "F" vinginevyo). Ijaribu kwa 85, 105, 40.

Zoezi 3.2: Tengeneza custom exception BidhaaHaipo. Andika function bei_ya(bidhaa, orodha) inayorusha BidhaaHaipo kama bidhaa haiko kwenye dict ya bei.

Zoezi 3.3 (venv): Tengeneza folder matumizi, venv ndani yake, sakinisha rich, tengeneza requirements.txt. Andika programu matumizi.py inayosoma matumizi.csv (columns kitu,kiasi) na kuonyesha jedwali la rich pamoja na jumla. Kama mstari una kiasi kisicho namba, iruke na kuonyesha onyo.

Jibu
python
# 3.1
def angalia_alama(alama):
    if not 0 <= alama <= 100:
        raise ValueError(f"Alama {alama} lazima iwe kati ya 0 na 100.")
    if alama >= 80:
        return "A"
    elif alama >= 65:
        return "B"
    elif alama >= 50:
        return "C"
    return "F"

for a in [85, 105, 40]:
    try:
        print(a, "->", angalia_alama(a))
    except ValueError as e:
        print("Kosa:", e)
# 85 -> A
# Kosa: Alama 105 lazima iwe kati ya 0 na 100.
# 40 -> F

# 3.2
class BidhaaHaipo(Exception):
    pass

def bei_ya(bidhaa, orodha):
    if bidhaa not in orodha:
        raise BidhaaHaipo(f"'{bidhaa}' haipo dukani.")
    return orodha[bidhaa]

bei = {"sukari": 3000, "chumvi": 800}
try:
    print(bei_ya("sukari", bei))
    print(bei_ya("unga", bei))
except BidhaaHaipo as e:
    print("Kosa:", e)
# 3000
# Kosa: 'unga' haipo dukani.

3.3 — amri za PowerShell:

powershell
mkdir matumizi; cd matumizi
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install rich
python -m pip freeze > requirements.txt

matumizi.csv:

text
kitu,kiasi
nauli,2000
chakula,5000
vocha,abc
maji,1000

matumizi.py:

python
import csv
from pathlib import Path

from rich import print
from rich.table import Table

faili = Path(__file__).parent / "matumizi.csv"
jedwali = Table(title="Matumizi ya Leo")
jedwali.add_column("Kitu")
jedwali.add_column("Kiasi (TSh)", justify="right")

jumla = 0
try:
    with open(faili, newline="", encoding="utf-8") as f:
        for row in csv.DictReader(f):
            try:
                kiasi = int(row["kiasi"])
            except ValueError:
                print(f"[yellow]Onyo:[/yellow] '{row['kiasi']}' si namba, nimeruka '{row['kitu']}'.")
                continue
            jumla += kiasi
            jedwali.add_row(row["kitu"], f"{kiasi:,}")
except FileNotFoundError:
    print("[red]matumizi.csv halipo![/red]")
else:
    jedwali.add_row("[bold]JUMLA[/bold]", f"[bold]{jumla:,}[/bold]")
    print(jedwali)

Kazi ya Nyumbani

(Inatakiwa: kipindi kijacho)

Kazi 1 — Word counter (baada ya Kipindi 1): Andika programu inayosoma file la maandishi (hadithi.txt — mwanafunzi aandike aya 2–3 za Kiswahili) na kuchapisha: idadi ya mistari, idadi ya maneno, na neno lililotumika mara nyingi zaidi (bila kujali herufi kubwa/ndogo).

Kazi 2 — Daftari la alama (baada ya Kipindi 2): Programu yenye menu: 1. Ongeza mwanafunzi, 2. Onyesha wote, 3. Toka. Data ihifadhiwe kwenye alama.json (list ya dicts {"jina":..., "alama":...}) ili isipotee programu ikifungwa. Alama isiyo namba isilete crash.

Kazi 3 — Hamisha (baada ya Kipindi 3): Andika function json_kwenda_csv(json_path, csv_path) inayogeuza alama.json ya Kazi 2 kuwa alama.csv. Rusha custom exception FailiTupu kama JSON ina list tupu. Weka kazi zote ndani ya folder lenye .venv na requirements.txt (hata kama ni tupu).

Jibu
python
# Kazi 1
from pathlib import Path

maandishi = Path("hadithi.txt").read_text(encoding="utf-8")
mistari = maandishi.splitlines()
maneno = maandishi.lower().split()

hesabu = {}
for neno in maneno:
    neno = neno.strip(".,!?;:\"'()")
    if neno:
        hesabu[neno] = hesabu.get(neno, 0) + 1

print("Mistari:", len(mistari))
print("Maneno:", len(maneno))
if hesabu:
    neno_bora = max(hesabu, key=hesabu.get)
    print(f"Neno linalorudiwa zaidi: '{neno_bora}' mara {hesabu[neno_bora]}")
python
# Kazi 2
import json
from pathlib import Path

FAILI = Path(__file__).parent / "alama.json"

def pakia():
    try:
        with open(FAILI, encoding="utf-8") as f:
            return json.load(f)
    except (FileNotFoundError, json.JSONDecodeError):
        return []

def hifadhi(wanafunzi):
    with open(FAILI, "w", encoding="utf-8") as f:
        json.dump(wanafunzi, f, indent=2, ensure_ascii=False)

wanafunzi = pakia()
while True:
    print("\n1. Ongeza mwanafunzi\n2. Onyesha wote\n3. Toka")
    chaguo = input("Chagua: ")
    if chaguo == "1":
        jina = input("Jina: ").strip()
        try:
            alama = int(input("Alama: "))
        except ValueError:
            print("Alama lazima iwe namba.")
            continue
        wanafunzi.append({"jina": jina, "alama": alama})
        hifadhi(wanafunzi)
        print("Imehifadhiwa.")
    elif chaguo == "2":
        if not wanafunzi:
            print("Hakuna mwanafunzi bado.")
        for w in wanafunzi:
            print(f"{w['jina']:<15}{w['alama']:>5}")
    elif chaguo == "3":
        print("Kwaheri!")
        break
    else:
        print("Chaguo si sahihi.")
python
# Kazi 3
import csv
import json

class FailiTupu(Exception):
    pass

def json_kwenda_csv(json_path, csv_path):
    with open(json_path, encoding="utf-8") as f:
        data = json.load(f)
    if not data:
        raise FailiTupu(f"{json_path} haina data.")
    with open(csv_path, "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=["jina", "alama"])
        writer.writeheader()
        writer.writerows(data)
    return len(data)

try:
    n = json_kwenda_csv("alama.json", "alama.csv")
    print(f"Nimehamisha wanafunzi {n}.")
except FileNotFoundError:
    print("alama.json halipo.")
except FailiTupu as e:
    print("Kosa:", e)

Ukiulizwa swali usilolijua

Checklist ya mwisho wa wiki

  • Anaeleza tofauti ya "r", "w", "a" bila kuangalia notes.
  • Anatumia with open(..., encoding="utf-8") kwa mazoea.
  • Anasoma file mstari kwa mstari na kutumia .strip().
  • Anatumia Path(__file__).parent / "jina" na exists().
  • Anasoma/kuandika CSV kwa DictReader/DictWriter na anakumbuka newline="".
  • Anahifadhi na kusoma dict/list kwa JSON.
  • Anaandika try/except/else/finally na kushika exception maalum.
  • Anasoma traceback (mstari wa mwisho kwanza).
  • Anatumia raise na kutengeneza custom exception.
  • Anatengeneza na kuactivate .venv kwenye PowerShell bila msaada.
  • Anatumia pip install, pip freeze > requirements.txt, pip install -r.
  • Kazi ya nyumbani ya Wiki 5 imekabidhiwa.