Bài 29

Nhận biết lỗi chương trình

Biết và trình bày được ý nghĩa của phạm vi hoạt động của biến trong chương trình và hàm, một biến được định nghĩa trong chương trình chính (bên ngoài các hàm) thì sẽ được sử dụng như thế nào bên trong các hàm, một biến được khai báo bên trong một hàm thì có sử dụng được ở bên ngoài hàm đó hay không.

🚀

1. Khởi động (Engagement)

Bài này sẽ giúp em tìm câu trả lời cho các câu hỏi sau:

  • Biết và trình bày được ý nghĩa của phạm vi hoạt động của biến trong chương trình và hàm
  • Một biến được định nghĩa trong chương trình chính (bên ngoài các hàm) thì sẽ được sử dụng như thế nào bên trong các hàm?
  • Một biến được khai báo bên trong một hàm thì có sử dụng được ở bên ngoài hàm đó hay không?

💡 Câu hỏi suy ngẫm: Giả sử có các lệnh sau:

a, b = 1, 2
def f(a, b):
    a = a + b
    b = b * a
    return a + b
Python Script

Giá trị của a, b bằng bao nhiêu sau khi thực hiện lệnh sau? a) f(1, 2) b) f(10, 20)

Ta có thể khai báo một biến bên trong hàm trùng tên với biến đã khai báo trước đó bên ngoài hàm không?

📖

2. Hình thành kiến thức (Knowledge)

1. Phạm vi của biến khai báo trong hàm

Quan sát các lệnh sau để tìm hiểu phạm vi có hiệu lực của biến khi khai báo bên trong một hàm.

Quy tắc: Các biến được khai báo bên trong một hàm chỉ được sử dụng bên trong hàm đó. Chương trình chính không sử dụng được.

Trong Python tất cả các biến khai báo bên trong hàm đều có tính địa phương (cục bộ), không có hiệu lực ở bên ngoài hàm.

Ví dụ:

def f(n):
    t = n + 1
    return t

t = 10
f(5)  # Trả về 6
print(t)  # Vẫn là 10, không thay đổi
Python Script

2. Phạm vi của biến khai báo ngoài hàm

a) Biến khai báo bên ngoài hàm không có tác dụng bên trong hàm

Ví dụ:

def f(n):
    t = n + 1
    return t

t = 10
f(5)    # 6
print(t)  # 10
Python Script

b) Bên trong hàm có thể truy cập để sử dụng giá trị của biến đã khai báo trước đó ở bên ngoài hàm

Ví dụ:

def f(a, b):
    return a + N

N = 10
f(1, 2)  # 13
Python Script

Trong chương trình chính, biến N được khai báo và gán giá trị 10. Khi gọi hàm f(1, 2), giá trị trả lại là biểu thức có N tham gia. Vậy trong hàm f() được phép truy cập giá trị của biến N.

3. Từ khóa global

Nếu muốn biến bên ngoài vẫn có tác dụng bên trong hàm thì cần khai báo lại biến này bên trong hàm với từ khóa global.

Ví dụ:

def f(n):
    global t
    t = 2*n + 1
    return t

t = 10
f(1)    # 3
print(t)  # 3 - đã thay đổi
Python Script

Biến t được khai báo với từ khóa global. Biến t khai báo trong chương trình chính và được gán giá trị 10. Sau khi thực hiện f(1), giá trị t đã thay đổi.

Lưu ý: Biến đã khai báo bên ngoài sẽ không có tác dụng bên trong hàm như một biến. Nếu muốn có tác dụng thì cần khai báo lại biến này trong hàm với từ khóa global.

4. Ví dụ phân tích

Giả sử hàm f(x,y) được định nghĩa như sau:

def f(x, y):
    a = 2*(x + y)
    print(a + n)
Python Script

Kết quả nào được in ra khi thực hiện các lệnh sau?

n = 10
f(1, 2)  # In ra: 2*(1+2) + 10 = 6 + 10 = 16
Python Script
🧩

3. Luyện tập (Practice)

Bài tập thực hành

Bài tập 1:

Giả sử có các lệnh sau:

a, b = 1, 2
def f(a, b):
    a = a + b
    b = b * a
    return a + b
Python Script

Giá trị của a, b bằng bao nhiêu sau khi thực hiện lệnh sau? a) f(1, 2) b) f(10, 20)

Trả lời:

  • a) f(1, 2) = (1+2) + (2*(1+2)) = 3 + 6 = 9
  • b) f(10, 20) = (10+20) + (20*(10+20)) = 30 + 600 = 630

Sau khi gọi hàm, biến a, b bên ngoài vẫn giữ nguyên giá trị (1, 2) vì a, b trong hàm là biến cục bộ.

Bài tập 2:

Ta có thể khai báo một biến bên trong hàm trùng tên với biến đã khai báo trước đó bên ngoài hàm không?

Trả lời: Có thể được. Biến bên trong hàm và biến bên ngoài hàm là hai biến khác nhau, dù có cùng tên.

Ví dụ:

x = 10

def f():
    x = 20  # Biến cục bộ, không ảnh hưởng đến x bên ngoài
    print("Bên trong hàm:", x)

f()           # In: Bên trong hàm: 20
print("Bên ngoài:", x)  # In: Bên ngoài: 10
Python Script

Bài tập 3:

Viết hàm với đầu vào là danh sách A chứa các số và số thực x. Hàm trả lại một danh sách kết quả B từ danh sách A bằng cách chỉ giữ lại các phần tử lớn hơn hoặc bằng x.

Chương trình mẫu:

def Select(A, x):
    B = []
    for k in range(len(A)):
        if A[k] >= x:
            B.append(A[k])
    return B

# Sử dụng hàm
danh_sach = [1, 5, 3, 8, 2, 7]
nguong = 4
ket_qua = Select(danh_sach, nguong)
print("Kết quả:", ket_qua)  # [5, 8, 7]
Python Script

Thực hành tại máy:

Viết hàm với đầu vào là xâu kí tự Str và số c, đầu ra là danh sách các từ được tách ra từ xâu Str nhưng đã được chuyển thành chữ in hoa hoặc chữ in thường, hoặc chỉ chuyển kí tự đầu các từ thành chữ in hoa tuỳ thuộc vào tham số đầu vào c như sau:

  • Nếu c = 0, danh sách B là các từ được chuyển thành chữ in hoa
  • Nếu c = 1, danh sách B là các từ được chuyển thành chữ in thường
  • Nếu c = 2, danh sách B là các từ được chuyển viết chữ hoa kí tự đầu của mỗi từ
🌟

4. Vận dụng (Application)

Bài tập vận dụng

Bài tập 1: Hàm đếm từ theo điều kiện

Viết hàm dem_theo_dieu_kien(text, dieu_kien) đếm số từ trong xâu text thỏa mãn điều kiện:

  • dieu_kien = 0: đếm từ có độ dài > 3
  • dieu_kien = 1: đếm từ bắt đầu bằng chữ 'a' hoặc 'A'
  • dieu_kien = 2: đếm từ kết thúc bằng chữ 'n' hoặc 'N'

Gợi ý:

def dem_theo_dieu_kien(text, dieu_kien):
    danh_sach_tu = text.split()
    dem = 0
    for tu in danh_sach_tu:
        if dieu_kien == 0 and len(tu) > 3:
            dem += 1
        elif dieu_kien == 1 and tu.lower().startswith('a'):
            dem += 1
        elif dieu_kien == 2 and tu.lower().endswith('n'):
            dem += 1
    return dem

# Sử dụng hàm
van_ban = "An đi học và làm bài tập về nhà"
print("Từ dài > 3:", dem_theo_dieu_kien(van_ban, 0))
print("Từ bắt đầu bằng 'a':", dem_theo_dieu_kien(van_ban, 1))
print("Từ kết thúc bằng 'n':", dem_theo_dieu_kien(van_ban, 2))
Python Script

Bài tập 2: Hàm xử lý điểm số

Viết chương trình quản lý điểm học sinh với các hàm sau:

  • nhap_diem(): nhập danh sách điểm từ bàn phím
  • tinh_diem_trung_binh(diem): tính điểm trung bình
  • xep_loai(dtb): xếp loại học lực

Gợi ý:

def nhap_diem():
    diem = []
    n = int(input("Nhập số môn học: "))
    for i in range(n):
        d = float(input(f"Nhập điểm môn {i+1}: "))
        diem.append(d)
    return diem

def tinh_diem_trung_binh(diem):
    return sum(diem) / len(diem)

def xep_loai(dtb):
    if dtb >= 8:
        return "Giỏi"
    elif dtb >= 6.5:
        return "Khá"
    elif dtb >= 5:
        return "Trung bình"
    else:
        return "Yếu"

# Sử dụng các hàm
ds_diem = nhap_diem()
dtb = tinh_diem_trung_binh(ds_diem)
xl = xep_loai(dtb)
print(f"Điểm trung bình: {dtb:.2f}")
print(f"Xếp loại: {xl}")
Python Script

Bài tập 3: Hàm sử dụng biến toàn cục

Viết hàm dem_so_lan_goi() đếm số lần hàm được gọi bằng cách sử dụng biến toàn cục.

Gợi ý:

so_lan_goi = 0

def dem_so_lan_goi():
    global so_lan_goi
    so_lan_goi += 1
    return so_lan_goi

# Sử dụng hàm
print(dem_so_lan_goi())  # 1
print(dem_so_lan_goi())  # 2
print(dem_so_lan_goi())  # 3
Python Script

Thảo luận:

  • Khi nào nên dùng biến toàn cục và khi nào nên dùng tham số?
  • Lợi ích và nhược điểm của việc sử dụng biến toàn cục là gì?
  • Tại sao nên hạn chế sử dụng biến toàn cục trong lập trình?

Ghi nhớ kiến thức 🎯

  • ✅ Biến cục bộ: khai báo trong hàm, chỉ hiệu lực bên trong hàm.
  • ✅ Biến toàn cục: khai báo ngoài hàm, có thể truy cập trong hàm.
  • ✅ global: dùng để thay đổi biến toàn cục bên trong hàm.
  • ✅ Nên ưu tiên dùng tham số thay vì biến toàn cục.
  • ✅ Phạm vi biến giúp tránh xung đột tên và lỗi logic.

Chúc mừng bạn đã hoàn thành bài học này! 🏆