Tham số và đối số
Bạn sẽ học được
- Phân biệt tham số (parameter) và đối số (argument).
- Truyền theo vị trí, theo tên, và trộn hai cách.
- Giá trị mặc định — cùng cái bẫy mutable default.
*args,**kwargsvà quy tắc thứ tự.- Tham số chỉ theo từ khoá và chỉ theo vị trí.
Khái niệm cốt lõi
Tham số là tên trong định nghĩa hàm; đối số là giá trị truyền khi gọi:
def area(width, height):
return width * height
print(area(3, 2))6width, height là tham số; 3, 2 là đối số. Truyền theo vị trí: 3 vào width, 2 vào height. Có thể truyền theo tên:
print(area(width=3, height=2))
print(area(height=2, width=3))6
6Truyền theo tên cho phép đổi thứ tự và làm lời gọi tự giải thích. Quy tắc: đối số vị trí phải đứng trước đối số từ khoá. area(width=3, 2) là SyntaxError.
Giá trị mặc định
def area(width, height=1.0):
return width * height
print(area(3), area(3, 2))3.0 6Tham số có mặc định phải nằm sau tham số không mặc định. Nếu viết def area(width=1.0, height) sẽ báo SyntaxError: non-default argument follows default argument.
Mặc định được đánh giá một lần khi def chạy, không phải mỗi lần gọi. Với giá trị bất biến như số, chuỗi, None, điều này vô hại. Với list/dict thì không:
def add_item(item, bucket=[]):
bucket.append(item)
return bucket
print(add_item("a"))
print(add_item("b"))['a']
['a', 'b']Lần gọi thứ hai dùng lại cùng một list đã bị sửa ở lần đầu. Mặc định không được "làm mới". Cách sửa chuẩn:
def add_item_ok(item, bucket=None):
if bucket is None:
bucket = []
bucket.append(item)
return bucket
print(add_item_ok("a"))
print(add_item_ok("b"))['a']
['b']Dùng None làm mặc định và tạo list bên trong thân hàm. Tương tự với {}, set(), và mọi đối tượng thay đổi được. Đây là một trong những lỗi Python nổi tiếng nhất, xuất hiện cả trong code production.
*args — nhiều đối số vị trí
def total(*nums):
return sum(nums)
print(total(1, 2, 3))
print(total())6
0Bên trong hàm, nums là tuple chứa mọi đối số vị trí thừa. Có thể truyền sẵn một list bằng cách mở gói:
values = [1, 2, 3]
print(total(*values))6Tên args chỉ là quy ước; *nums cũng đúng. Điều quan trọng là dấu *.
**kwargs — nhiều đối số từ khoá
def show(**info):
for key, value in info.items():
print(key, value)
show(name="An", age=28)name An
age 28info là dict chứa các đối số từ khoá không khớp tham số nào khác. Mở gói dict khi gọi:
person = {"name": "An", "age": 28}
show(**person)Lưu ý: tên khóa phải là chuỗi hợp lệ làm tên tham số; **{"first-name": "An"} sẽ lỗi khi gọi hàm nhận **kwargs? Thực tế Python cho phép khóa bất kỳ trong **kwargs khi gọi, nhưng nếu hàm có tham số cụ thể thì chỉ khớp tên hợp lệ. Với **info thuần, khóa lạ vẫn vào dict — hãy kiểm tra dữ liệu thay vì tin tưởng.
Thứ tự tham số
Khi kết hợp, thứ tự bắt buộc:
def ham(a, b=1, *args, c=2, **kwargs):
...| Vị trí | Loại |
|---|---|
| 1 | Tham số thường |
| 2 | Tham số có mặc định |
| 3 | *args |
| 4 | Tham số chỉ theo từ khoá |
| 5 | **kwargs |
Sai thứ tự là SyntaxError ngay khi định nghĩa, nên lỗi lộ ra sớm.
Tham số chỉ theo từ khoá
Dấu * trần đánh dấu mọi tham số sau nó phải truyền theo tên:
def area(width, height, *, unit="cm"):
return f"{width * height} {unit}²"
print(area(3, 2))
print(area(3, 2, unit="m"))6 cm²
6 m²area(3, 2, "m") sẽ là TypeError: area() takes 2 positional arguments but 3 were given. Tham số chỉ theo từ khoá rất hữu ích khi thêm tuỳ chọn mới vào hàm đã có người dùng — tránh việc đối số vị trí cũ bị hiểu nhầm.
Ngược lại, dấu / đánh dấu tham số chỉ theo vị trí (Python 3.8+):
def chia(a, b, /):
return a / b
print(chia(10, 2))5.0chia(a=10, b=2) báo TypeError. Ít dùng trong code ứng dụng; chủ yếu trong thư viện chuẩn.
Thực hành
- Gọi
area(3, 2)theo vị trí và theo tên, đổi thứ tự. - Thêm mặc định
height=1.0và thử bỏ đối số thứ hai. - Tái hiện bẫy
bucket=[], rồi sửa bằngNone. - Viết
total(*nums)và gọi với 0, 3, 5 đối số. - Viết
show(**info)và gọi bằng**dict. - Đổi
unitthành tham số chỉ theo từ khoá và thử truyền vị trí để đọc lỗi.
Lỗi thường gặp
| Triệu chứng | Nguyên nhân | Cách sửa |
|---|---|---|
SyntaxError: non-default argument follows default | Mặc định đứng trước tham số thường | Đưa mặc định ra sau |
TypeError: missing required argument | Thiếu đối số | Truyền đủ hoặc thêm mặc định |
TypeError: got multiple values | Truyền cùng tham số hai lần | Kiểm tra vị trí và tên |
| List mặc định giữ dữ liệu cũ | Mutable default | Dùng None rồi tạo mới |
TypeError: takes N positional arguments | Truyền vị trí vào tham số keyword-only | Truyền theo tên |
*args là tuple, không phải list | Bản chất của *args | list(args) nếu cần sửa |
**kwargs nhận khóa lạ | Không kiểm tra dữ liệu | Lọc khóa hợp lệ trước |
Tóm tắt
- Tham số trong
def, đối số khi gọi; vị trí trước, từ khoá sau. - Mặc định đánh giá một lần — không dùng list/dict làm mặc định.
*argsgom tuple,**kwargsgom dict; mở gói bằng*/**khi gọi.*trần tạo tham số chỉ theo từ khoá;/tạo chỉ theo vị trí.- Thứ tự tham số sai báo lỗi ngay khi định nghĩa.
Dùng ← → để chuyển bài