Bài 6 · Vận dụng · 22 phút· Cập nhật 11/06/2026
Hàm & phạm vi trong Python
Biên soạn bởi Nguyễn Anh Tuấn
Hàm trong Python: def, tham số mặc định, *args/**kwargs, phạm vi biến & quy tắc LEGB, bẫy mutable default - hàm là object hạng nhất (first-class).
Hàm gom một việc lặp lại thành một khối có tên, nhận tham số và return kết quả. Định nghĩa bằng def:
ham.py
def chao(ten):
return f"Xin chao, {ten}!"
def cong(a, b):
return a + b
print(chao("Lan"))
print(cong(3, 5)) Kết quả khi chạy
Xin chao, Lan! 8
- ▸def ten(tham_số): rồi thân hàm thụt vào; return trả giá trị.
- ▸Không viết return → hàm trả về None.
- ▸Gọi hàm: ten(đối_số). Đối số khớp tham số theo vị trí (hoặc theo tên).
Tham số có thể có giá trị mặc định; *args gom các đối số vị trí dư thành tuple; **kwargs gom các đối số từ khoá dư thành dict:
thamso.py
def f(a, b=2, *args, **kwargs):
print(a, b, args, kwargs)
f(1) # b dung mac dinh
f(1, 3, 4, 5, x=9) # b=3; args=(4,5); kwargs={'x':9} Kết quả khi chạy
1 2 () {}
1 3 (4, 5) {'x': 9}- ▸Mặc định: def f(b=2) - dùng khi không truyền b.
- ▸*args: gom đối số VỊ TRÍ dư → tuple; **kwargs: gom đối số TỪ KHOÁ dư → dict.
- ▸Gọi theo tên (keyword) cho rõ: ve(rong=5, cao=3) - khỏi nhớ thứ tự.
Khi gặp một tên, Python tìm theo thứ tự LEGB: Local (trong hàm) → Enclosing (hàm bao ngoài) → Global (module) → Built-in. Bấm thử từng tên để xem Python tìm ở đâu:
global & nonlocal
Giá trị mặc định được tạo MỘT LẦN lúc định nghĩa hàm, rồi dùng chung cho mọi lần gọi. Nếu mặc định là list (mutable), nó sẽ “nhớ” dữ liệu cũ:
bay.py - SAI
def them(x, gio=[]): # BAY: list mac dinh dung chung
gio.append(x)
return gio
print(them(1)) # [1]
print(them(2)) # [1, 2] <- van con 1! Kết quả khi chạy
[1] [1, 2]
sua.py - ĐÚNG
def them(x, gio=None):
if gio is None: # tao list MOI moi lan goi
gio = []
gio.append(x)
return gio
print(them(1)) # [1]
print(them(2)) # [2] Kết quả khi chạy
[1] [2]
- ▸ĐỪNG dùng list/dict/set làm giá trị mặc định.
- ▸Dùng None làm mặc định, rồi tạo object mới bên trong hàm.
- ▸Object immutable (int, str, None) làm mặc định thì an toàn.
Như bài “mọi thứ là object”: hàm cũng là object. Bạn gán nó cho biến, bỏ vào list, hay truyền làm đối số cho hàm khác:
hangnhat.py
def binh_phuong(n):
return n * n
def ap_dung(ham, gt): # nhan MOT HAM lam doi so
return ham(gt)
print(ap_dung(binh_phuong, 5)) # truyen ham binh_phuong Kết quả khi chạy
25
Vì hàm truyền được, Python có sẵn hàm bậc cao (higher-order) nhận hàm làm đối số: map (biến đổi từng phần tử), filter (lọc), và reduce (gộp dần về một giá trị). Kèm lambda (hàm ẩn danh một dòng) rất gọn:
map / filter / reduce + lambda
from functools import reduce
so = [1, 2, 3, 4, 5]
binh_phuong = list(map(lambda n: n * n, so)) # [1, 4, 9, 16, 25]
chan = list(filter(lambda n: n % 2 == 0, so)) # [2, 4]
tong = reduce(lambda a, b: a + b, so) # 15
print(binh_phuong)
print(chan)
print(tong) Kết quả khi chạy
[1, 4, 9, 16, 25] [2, 4] 15
Pythonic: thường nên dùng comprehension
Sắp tới
Câu hỏi thường gặp
Trả về None. Trong Python mọi hàm đều trả về một giá trị; nếu bạn không viết return (hoặc viết return trống), giá trị đó là None. Vì vậy x = ham_in_ra(...) có thể vô tình bằng None.
*args gom các đối số VỊ TRÍ dư thành một tuple; **kwargs gom các đối số TỪ KHOÁ (key=value) dư thành một dict. Vd def f(a, *args, **kwargs): gọi f(1, 2, 3, x=9) thì a=1, args=(2, 3), kwargs={"x": 9}. Tên args/kwargs chỉ là quy ước; dấu * và ** mới quan trọng.
Là thứ tự Python tìm một TÊN: Local (trong hàm hiện tại) → Enclosing (hàm bao ngoài) → Global (cấp module) → Built-in (len, print…). Tìm thấy ở đâu thì dùng ở đó và dừng; không thấy ở cả 4 nơi thì NameError.
Mặc định, GÁN một tên bên trong hàm tạo biến LOCAL. Muốn gán đè biến ở cấp module, khai báo global ten; muốn gán đè biến ở hàm bao ngoài (enclosing), dùng nonlocal ten. Dùng tiết kiệm - lạm dụng global làm code khó dò.
Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.
Trả lời vài câu để chắc rằng em đã nắm bài.
Một hàm không có lệnh return thì trả về gì?
- 1
Hàm đầu tiên
Viết hàm
dien_tich(dai, rong)trả về diện tích hình chữ nhật; indien_tich(4, 5).Hoàn thành khi:
def dien_tich(dai, rong): return dai * rong→ 20. - 2
Tham số mặc định
Viết hàm
chao(ten, loi="Xin chao")in "Xin chao, <ten>!". Gọi cả có và không truyềnloi.Hoàn thành khi:
chao("Lan")vàchao("Nam", "Hi")đều chạy; mặc định dùng khi không truyền. - 3
Tổng tuỳ ý
Viết hàm
tong(*so)cộng mọi đối số. Gọitong(1, 2, 3, 4).Hoàn thành khi:
def tong(*so): return sum(so)→ 10.*sogom thành tuple. - 4
LEGB
Dùng công cụ Bước 3: tra cứu
z,y,x,len,khong_co. Mỗi tên tìm thấy ở scope nào?Hoàn thành khi:
z→Local,y→Enclosing,x→Global,len→Built-in,khong_co→NameError. - 5
Sửa bẫy mặc định
Sửa
def them(x, gio=[])để mỗi lần gọi không “nhớ” list cũ.Hoàn thành khi:
def them(x, gio=None): if gio is None: gio = []; gio.append(x); return gio. - 6
Hàm first-class
Viết
ap_dung(ham, gt)trả vềham(gt). Gọiap_dungvới một hàm bình phương và 6.Hoàn thành khi:
ap_dung(lambda n: n*n, 6)hoặc truyền hàm đãdef→ 36.