Hàm (function) là một khái niệm căn bản, đóng vai trò trung tâm trong lập trình Python. Hàm giúp chúng ta chia nhỏ chương trình thành các phần nhỏ hơn, dễ quản lý hơn. Bài viết này sẽ đưa bạn đi qua toàn bộ kiến thức về hàm trong Python, từ cú pháp đến cách sử dụng các loại đối số, các hàm đặc biệt, và các vấn đề liên quan khác.
Hàm trong Python là gì?
Hàm trong Python là một khối mã được tổ chức, có khả năng tái sử dụng, và được dùng để thực hiện một hành động đơn lẻ có liên quan. Hàm giúp chương trình của bạn trở nên dễ quản lý hơn, và có mức độ tái sử dụng mã cao.
Một cách tiếp cận từ trên xuống để xây dựng logic xử lý là định nghĩa các khối hàm độc lập có thể tái sử dụng. Một hàm Python có thể được gọi từ bất kỳ hàm nào khác bằng cách truyền dữ liệu cần thiết (được gọi là tham số hoặc đối số). Hàm được gọi sẽ trả kết quả trở lại môi trường gọi hàm.
Các loại hàm trong Python
Python cung cấp các loại hàm sau:
STT | Loại & mô tả |
---|---|
1 | Hàm Tích Hợp Sẵn (Built-in functions) Thư viện chuẩn của Python bao gồm một số hàm tích hợp sẵn. Một vài hàm tích hợp sẵn trong Python là print() , int() , len() , sum() ,… Các hàm này luôn sẵn có vì chúng được nạp vào bộ nhớ của máy tính ngay khi bạn khởi động trình thông dịch Python. |
2 | Hàm Định Nghĩa trong Các Module Tích Hợp Sẵn (Functions defined in built-in modules) Thư viện chuẩn cũng cung cấp một số module (các thư viện con). Mỗi module chứa một nhóm các hàm được định nghĩa. Những hàm này không sẵn dùng ngay lập tức. Bạn cần import chúng vào bộ nhớ từ các module tương ứng trước khi có thể sử dụng. |
3 | Hàm Do Người Dùng Định Nghĩa (User-defined functions) Ngoài các hàm tích hợp sẵn và các hàm trong module tích hợp sẵn, bạn cũng có thể tự tạo các hàm riêng của mình. Các hàm này được gọi là hàm do người dùng định nghĩa. |
Định nghĩa hàm trong Python
Bạn có thể tạo các hàm tùy chỉnh để cung cấp các chức năng cần thiết trong chương trình của mình. Dưới đây là các quy tắc đơn giản để định nghĩa một hàm trong Python:
- Khối mã của một hàm bắt đầu bằng từ khóa
def
, theo sau là tên hàm và dấu ngoặc đơn()
. - Các tham số đầu vào hoặc đối số cần thiết được đặt bên trong dấu ngoặc đơn này. Bạn cũng có thể định nghĩa các tham số này bên trong dấu ngoặc đơn.
- Câu lệnh đầu tiên của hàm có thể là một câu lệnh tùy chọn; chuỗi tài liệu (docstring) của hàm.
- Khối mã bên trong mỗi hàm bắt đầu bằng dấu hai chấm
:
và được thụt vào. - Câu lệnh return [
biểu_thức
] dùng để kết thúc hàm và có thể trả về một giá trị hoặc biểu thức cho nơi gọi hàm. Nếureturn
không có đối số, thì tương đương vớireturn None
.
Cú pháp định nghĩa hàm
def ten_ham(tham_so):
"chuỗi_tài_liệu_của_hàm"
khối_lệnh_của_hàm
return [biểu_thức]
Lưu ý: Đoạn code trên không phải là một đoạn chương trình để chạy, mà là cú pháp tổng quát để khai báo hàm
Giải thích code:
def ten_ham(tham_so):
: Khai báo một hàm với từ khóadef
, theo sau là tên hàmten_ham
và danh sách các tham sốtham_so
đặt trong cặp dấu ngoặc đơn()
."chuỗi_tài_liệu_của_hàm"
: Một chuỗi văn bản, đặt trong dấu nháy đôi hoặc nháy ba, để mô tả về chức năng và cách sử dụng của hàm. Chuỗi này là tùy chọn.khối_lệnh_của_hàm
: Là các câu lệnh Python nằm trong thân hàm. Chúng được thụt lề vào trong để xác định phạm vi của hàm.return [biểu_thức]
: Kết thúc hàm và trả về giá trị củabiểu_thức
(nếu có).
Theo mặc định, các tham số có hành vi theo vị trí (positional), tức là bạn cần phải truyền chúng theo đúng thứ tự đã định nghĩa. Khi hàm đã được định nghĩa xong, bạn có thể thực thi bằng cách gọi hàm đó từ một hàm khác, hoặc trực tiếp từ giao diện dòng lệnh Python.
Ví dụ về định nghĩa hàm trong Python
Ví dụ sau đây minh họa cách định nghĩa một hàm có tên là greetings()
. Dấu ngoặc đơn ()
ở đây rỗng, có nghĩa là hàm này không có tham số đầu vào. Dòng đầu tiên của hàm là docstring, và khối mã của hàm kết thúc bằng câu lệnh return
.
def greetings():
"Đây là docstring của hàm greetings"
print ("Xin chào Vietnix")
return
Khi hàm này được gọi, thông điệp “Xin chào Vietnix” sẽ được in ra màn hình.
Giải thích code:
def greetings():
: Khai báo một hàm có tên làgreetings
. Dấu ngoặc đơn rỗng()
cho thấy hàm này không nhận tham số đầu vào."Đây là docstring của hàm greetings"
: Đây là docstring (chuỗi tài liệu) của hàm, dùng để mô tả chức năng của hàm. Nó được đặt trong dấu nháy đôi hoặc nháy ba.print ("Xin chào Vietnix")
: Lệnh này in ra thông điệp “Xin chào Vietnix” khi hàm được gọi.return
: Lệnh này kết thúc hàm, ở đây không có biểu thức saureturn
nên hàm sẽ không trả về giá trị cụ thể (tương đương vớireturn None
).
Gọi hàm trong Python
Việc định nghĩa hàm chỉ cho biết tên hàm, các tham số cần thiết và cấu trúc các khối lệnh của hàm. Khi bạn đã hoàn tất việc định nghĩa hàm, bạn có thể gọi hàm bằng cách sử dụng tên hàm. Nếu hàm có tham số, bạn cần truyền các tham số đó vào trong dấu ngoặc đơn khi gọi. Nếu hàm không có tham số, dấu ngoặc đơn để trống khi gọi.
Ví dụ gọi một hàm trong Python
Dưới đây là một ví dụ để minh họa cho việc gọi hàm printme()
:
# Định nghĩa hàm
def printme(str):
"Hàm này in một chuỗi được truyền vào"
print(str)
return
# Gọi hàm
printme("Đây là lần gọi hàm đầu tiên!")
printme("Và đây là lần gọi hàm thứ hai.")
Khi đoạn code trên được thực thi, kết quả sẽ hiển thị như sau:
Đây là lần gọi hàm đầu tiên!
Và đây là lần gọi hàm thứ hai.
Giải thích code:
def printme(str):
: Dòng này định nghĩa một hàm tên làprintme
, hàm này nhận một tham số đầu vào làstr
."Hàm này in một chuỗi được truyền vào"
: Đây là docstring (chuỗi tài liệu) của hàm, mô tả ngắn gọn về chức năng của hàm.print(str)
: Câu lệnh này in giá trị của tham sốstr
ra màn hình.return
: Câu lệnh này kết thúc hàm và trả về giá trịNone
(trong trường hợp này, không có giá trị nào được trả về cụ thể).printme("Đây là lần gọi hàm đầu tiên!")
: Dòng này gọi hàmprintme
với tham số đầu vào là chuỗi"Đây là lần gọi hàm đầu tiên!"
.printme("Và đây là lần gọi hàm thứ hai.")
: Dòng này gọi lại hàmprintme
với một chuỗi khác.
Tham chiếu và giá trị
Trong các ngôn ngữ lập trình như C và C++, có hai cơ chế chính để truyền biến vào hàm, đó là truyền bằng giá trị (call by value) và truyền bằng tham chiếu (call by reference). Tuy nhiên, cách truyền biến vào hàm trong Python lại khác biệt.
Python sử dụng cơ chế truyền bằng tham chiếu. Trong Python, biến thực chất là một nhãn hoặc tham chiếu đến một đối tượng trong bộ nhớ. Do đó, cả biến được dùng làm đối số thực tế khi gọi hàm (actual argument) lẫn tham số hình thức (formal argument) đều tham chiếu đến cùng một đối tượng trong bộ nhớ. Ta có thể kiểm chứng điều này bằng cách xem id() của biến trước và sau khi truyền vào hàm.
- Truyền bằng giá trị (call by value): Khi một biến được truyền vào hàm theo cơ chế này, giá trị của đối số thực tế được sao chép sang biến đại diện cho đối số hình thức. Do đó, bất kỳ thay đổi nào đối với đối số hình thức cũng không làm thay đổi giá trị của đối số thực tế.
- Truyền bằng tham chiếu (call by reference): Với cơ chế này, một tham chiếu đến đối tượng trong bộ nhớ được truyền vào. Cả đối số hình thức và đối số thực tế (các biến trong đoạn mã gọi hàm) đều tham chiếu đến cùng một đối tượng. Vì vậy, mọi thay đổi đối với đối số hình thức đều được phản ánh ở đối số thực tế.
Ví dụ về id() của biến
Trong ví dụ dưới đây, ta sẽ kiểm tra giá trị id()
của một biến:
def testfunction(arg):
print("ID bên trong hàm:", id(arg))
var = "Xin chào"
print("ID trước khi truyền:", id(var))
testfunction(var)
Khi đoạn mã trên được thực thi, giá trị id()
của biến var
trước khi truyền vào hàm và bên trong hàm sẽ được hiển thị.
ID trước khi truyền: 140283679522768
ID bên trong hàm: 140283679522768
Giải thích code:
def testfunction(arg):
: Định nghĩa một hàmtestfunction
nhận một tham số đầu vàoarg
.print("ID bên trong hàm:", id(arg))
: In ra giá trịid()
của tham sốarg
bên trong hàm. Hàmid()
trả về địa chỉ bộ nhớ của đối tượng.var = "Xin chào"
: Gán giá trị"Xin chào"
cho biếnvar
.print("ID trước khi truyền:", id(var))
: In ra giá trịid()
của biếnvar
trước khi truyền vào hàm.testfunction(var)
: Gọi hàmtestfunction
và truyền biếnvar
vào.
Cơ chế hoạt động cũng phụ thuộc vào việc đối tượng được truyền vào có thay đổi được (mutable) hay không thay đổi được (immutable). Đối tượng số (numeric object) trong Python là bất biến. Khi một đối tượng số được truyền vào, và sau đó hàm thay đổi giá trị của đối số hình thức, thì thực tế hàm sẽ tạo một đối tượng mới trong bộ nhớ, giữ nguyên giá trị của biến ban đầu.
Ví dụ trên cho thấy rõ ràng rằng khi một biến được truyền vào hàm trong Python, biến đó thực chất là một tham chiếu đến một vùng nhớ chứa dữ liệu. Do đó, id của biến bên ngoài và trong hàm là giống nhau.
Ví dụ về đối tượng bất biến (Immutable)
Ví dụ dưới đây cho thấy cách một đối tượng bất biến (ví dụ như số nguyên) hoạt động khi được truyền vào một hàm:
def testfunction(arg):
print("ID bên trong hàm:", id(arg))
arg = arg + 1
print("Đối tượng mới sau khi tăng:", arg, id(arg))
var = 10
print("ID trước khi truyền:", id(var))
testfunction(var)
print("Giá trị sau khi gọi hàm:", var)
Kêt quả sau khi chạy đoạn code trên:
ID trước khi truyền: 140719550297160
ID bên trong hàm: 140719550297160
Đối tượng mới sau khi tăng: 11 140719550297192
Giá trị sau khi gọi hàm: 10
Giải thích code:
def testfunction(arg):
: Định nghĩa một hàm có têntestfunction
với một tham số làarg
.print("ID bên trong hàm:", id(arg))
: In ra ID của đối tượng mà tham sốarg
đang tham chiếu đến bên trong hàm.arg = arg + 1
: Tăng giá trị củaarg
lên 1 đơn vị. Điều quan trọng ở đây là việc này tạo ra một đối tượng số nguyên mới.print("Đối tượng mới sau khi tăng:", arg, id(arg))
: In ra giá trị và ID của đối tượngarg
sau khi tăng.var = 10
: Khai báo biếnvar
và gán giá trị ban đầu là 10.print("ID trước khi truyền:", id(var))
: In ID của biếnvar
trước khi truyền vào hàmtestfunction
.testfunction(var)
: Gọi hàmtestfunction
và truyền biếnvar
vào làm đối số.print("Giá trị sau khi gọi hàm:", var)
: In giá trị của biếnvar
sau khi hàmtestfunction
đã được thực thi.
Hãy cùng xem điều gì sẽ xảy ra khi truyền một đối tượng khả biến (ví dụ như danh sách – list
hoặc từ điển – dictionary
) vào một hàm. Cơ chế truyền vẫn là truyền bằng tham chiếu, bằng chứng là ID của danh sách trước và sau khi truyền không thay đổi. Tuy nhiên, nếu ta thay đổi danh sách bên trong hàm, thì sự thay đổi này cũng được phản ánh ở phạm vi bên ngoài hàm (biến toàn cục).
Ví dụ về truyền tham chiếu trong Python
Trong ví dụ dưới đây, chúng ta sẽ truyền một list
(mảng) vào một hàm, thêm một phần tử mới vào list
đó, và sau đó kiểm tra nội dung của list
gốc. Ta sẽ thấy rằng list
gốc đã bị thay đổi:
def testfunction(arg):
print ("Bên trong hàm:", arg)
print ("ID bên trong hàm:", id(arg))
arg.append(100)
var = [10, 20, 30, 40]
print ("ID trước khi truyền:", id(var))
testfunction(var)
print ("List sau khi gọi hàm:", var)
Đoạn code trên khi thực thi, sẽ cho ra kết quả như sau:
ID trước khi truyền: 140279525484544
Bên trong hàm: [10, 20, 30, 40]
ID bên trong hàm: 140279525484544
List sau khi gọi hàm: [10, 20, 30, 40, 100]
Giải thích code:
def testfunction(arg):
: Định nghĩa hàmtestfunction
nhận một tham sốarg
.print ("Bên trong hàm:", arg)
: In ra giá trị củaarg
(list) bên trong hàm.print ("ID bên trong hàm:", id(arg))
: In ra ID (địa chỉ bộ nhớ) củaarg
bên trong hàm.arg.append(100)
: Thêm giá trị100
vào cuối listarg
. Đây là nơi list gốc bị thay đổi.var = [10, 20, 30, 40]
: Tạo một list tên làvar
.print ("ID trước khi truyền:", id(var))
: In ra ID của listvar
trước khi truyền vào hàm.testfunction(var)
: Gọi hàmtestfunction
và truyềnvar
vào.print ("List sau khi gọi hàm:", var)
: In ra nội dung của listvar
sau khi hàm được thực thi.
Đối số hàm trong Python
Đối số hàm là các giá trị hoặc biến được truyền vào một hàm khi hàm đó được gọi. Cách một hàm hoạt động thường phụ thuộc vào các đối số mà nó nhận được.
Khi bạn định nghĩa một hàm, bạn cần chỉ định một danh sách các biến (được gọi là tham số hình thức) bên trong dấu ngoặc đơn ()
. Các tham số này đóng vai trò như các chỗ dành sẵn cho dữ liệu sẽ được truyền vào hàm khi nó được gọi. Khi hàm được gọi, giá trị cho mỗi tham số hình thức phải được cung cấp, và chúng được gọi là đối số thực tế.
Ví dụ về đối số hàm trong Python
Hãy thử thay đổi hàm greetings (chào hỏi)
để có thêm một đối số là name. Khi đó, chuỗi được truyền vào hàm như một đối số thực tế sẽ trở thành biến name bên trong hàm:
def greetings(name):
"Đây là docstring của hàm greetings"
print ("Xin chào {}".format(name))
return
greetings("Nam")
greetings("Lan")
greetings("Hùng")
Đoạn code này sẽ tạo ra kết quả như sau:
Xin chào Nam
Xin chào Lan
Xin chào Hùng
Giải thích code:
def greetings(name):
: Định nghĩa hàmgreetings
với một tham số hình thức làname
."Đây là docstring của hàm greetings"
: Chuỗi tài liệu (docstring) mô tả ngắn gọn về hàm.print ("Xin chào {}".format(name))
: In ra lời chào, sử dụng biếnname
được truyền vào hàm.return
: Kết thúc hàm và không trả về giá trị nào.greetings("Nam"), greetings("Lan"), greetings("Hùng")
: Các dòng này gọi hàmgreetings
với các đối số thực tế khác nhau.
Các loại đối số hàm trong Python
Dựa trên cách các đối số được khai báo khi định nghĩa một hàm Python, chúng được phân loại thành các loại sau:
- Đối số vị trí hoặc đối số bắt buộc (Positional or Required Arguments)
- Đối số từ khóa (Keyword Arguments)
- Đối số mặc định (Default Arguments)
- Đối số chỉ vị trí (Positional-only Arguments)
- Đối số chỉ từ khóa (Keyword-only arguments)
- Đối số tùy ý hoặc đối số độ dài biến đổi (Arbitrary or Variable-length Arguments)
Đối số vị trí hoặc đối số bắt buộc (Positional or Required Arguments)
Đối số bắt buộc là các đối số được truyền vào hàm theo đúng thứ tự vị trí. Số lượng đối số trong lời gọi hàm phải khớp chính xác với số lượng đối số được định nghĩa trong hàm. Nếu không, mã sẽ báo lỗi cú pháp.
Ví dụ
# Định nghĩa hàm
def printme(str):
"Hàm này in một chuỗi được truyền vào"
print(str)
return
# Gọi hàm
printme()
Khi đoạn mã trên được thực thi, nó sẽ tạo ra kết quả như sau:
Traceback (most recent call last):
File “test.py”, line 11, in <module>
printme()
TypeError: printme() takes exactly 1 argument (0 given).
Trong đoạn mã trên, chúng ta gọi hàm printme() mà không có bất kỳ tham số nào, điều này sẽ gây ra lỗi.
Giải thích code:
def printme(str):
: Định nghĩa hàmprintme
với một tham số bắt buộc làstr
.printme()
: Cố gắng gọi hàmprintme
mà không cung cấp đối số nào.TypeError: printme() takes exactly 1 argument (0 given)
: Python báo lỗi kiểu dữ liệu (TypeError
) vì hàmprintme
được định nghĩa là cần 1 đối số, nhưng lại được gọi mà không có đối số nào cả.
Đối số từ khóa (Keyword Arguments)
Đối số từ khóa (Keyword arguments) liên quan đến các lời gọi hàm. Khi bạn sử dụng đối số từ khóa trong lời gọi hàm, người gọi xác định các đối số bằng tên tham số. Điều này cho phép bạn bỏ qua các đối số hoặc đặt chúng ra khỏi thứ tự vì trình thông dịch Python có thể sử dụng các từ khóa được cung cấp để khớp các giá trị với tham số.
Ví dụ 1
Ví dụ dưới đây minh họa cách sử dụng đối số từ khóa trong Python:
# Định nghĩa hàm
def printme(str):
"Hàm này in một chuỗi được truyền vào."
print(str)
return
# Gọi hàm
printme(str = "Chuỗi của tôi")
Khi đoạn mã trên được thực thi, kết quả sẽ hiển thị như sau:
Chuỗi của tôi
Giải thích code:
def printme(str):
: Định nghĩa một hàmprintme
có một tham số đầu vào làstr
.print(str)
: Câu lệnh in giá trị của tham sốstr
ra màn hình.return
: Lệnh kết thúc hàm.printme(str = "Chuỗi của tôi")
: Dòng này gọi hàmprintme
và truyền giá trị “Chuỗi của tôi” vào cho tham sốstr
. Thay vì chỉ truyền giá trị, ta chỉ định rõstr = "Chuỗi của tôi"
để thể hiện rõ vai trò của đối số này trong hàm.
Ví dụ 2
Ví dụ sau đây sẽ làm rõ hơn về cách hoạt động của đối số từ khóa. Bạn có thể thấy rằng, thứ tự của các tham số không còn quan trọng:
# Định nghĩa hàm
def printinfo(name, age):
"Hàm này in thông tin được truyền vào."
print("Tên:", name)
print("Tuổi:", age)
return
# Gọi hàm
printinfo(age=50, name="miki")
Khi đoạn mã trên được thực thi, kết quả sẽ như sau:
Tên: miki
Tuổi: 50
Giải thích code:
def printinfo(name, age):
: Dòng này định nghĩa một hàmprintinfo
với hai tham số đầu vào làname
(tên) vàage
(tuổi).print("Tên:", name)
: Lệnh in ra màn hình dòng chữ “Tên:” và giá trị của tham sốname
.print("Tuổi:", age)
: Lệnh in ra màn hình dòng chữ “Tuổi:” và giá trị của tham sốage
.return
: Lệnh kết thúc hàm.printinfo(age=50, name="miki")
: Dòng này gọi hàmprintinfo
với việc chỉ định tên tham số tương ứng. Ta có thể thấy rằngage
được truyền vào giá trị50
vàname
được gán bằng"miki"
. Điều đặc biệt là thứ tự truyền tham số khác với thứ tự định nghĩa tham số trong hàm.
Đối số mặc định (Default Arguments)
Một đối số mặc định là một đối số được gán một giá trị mặc định trước. Nếu khi gọi hàm, bạn không truyền giá trị cho đối số này, hàm sẽ sử dụng giá trị mặc định đã được gán trước đó.
Ví dụ về đối số mặc định
Ví dụ sau đây minh họa cách sử dụng đối số mặc định. Hàm sẽ sử dụng giá trị tuổi mặc định (35) nếu giá trị này không được cung cấp khi gọi hàm:
# Định nghĩa hàm
def printinfo(name, age=35):
"Hàm này in thông tin được truyền vào."
print("Tên:", name)
print("Tuổi:", age)
return
# Gọi hàm
printinfo(age=50, name="miki")
printinfo(name="miki")
Khi đoạn mã trên được thực thi, kết quả sẽ hiển thị như sau:
Tên: miki
Tuổi: 50
Tên: miki
Tuổi: 35
Giải thích code:
def printinfo(name, age=35):
: Dòng này định nghĩa một hàmprintinfo
với hai tham số:name
vàage
. Tham sốage
có một giá trị mặc định là35
.print("Tên:", name)
: Lệnh in ra màn hình dòng chữ “Tên:” và giá trị của tham sốname
.print("Tuổi:", age)
: Lệnh in ra màn hình dòng chữ “Tuổi:” và giá trị của tham sốage
.return
: Lệnh kết thúc hàm.printinfo(age=50, name="miki")
: Dòng này gọi hàmprintinfo
, và giá trị tuổi đã được truyền vào là50
. Lúc này hàm sẽ sử dụng giá trị50
thay cho giá trị mặc định.printinfo(name="miki")
: Dòng này gọi hàmprintinfo
chỉ truyền vào tham sốname
, không truyền vào tham sốage
. Khi này hàm sẽ tự động gán giá trị35
(được định nghĩa là mặc định ở hàm) cho tham sốage
.
Đối số chỉ vị trí (Positional-only Arguments)
Những đối số mà chỉ có thể được xác định bằng vị trí của chúng trong lời gọi hàm được gọi là đối số chỉ định theo vị trí (positional-only arguments). Các đối số này được định nghĩa bằng cách đặt một dấu gạch chéo (/
) trong danh sách tham số của hàm, sau tất cả các tham số chỉ định theo vị trí. Tính năng này được giới thiệu từ phiên bản Python 3.8.
Lợi ích của việc sử dụng kiểu đối số này là nó đảm bảo rằng các hàm được gọi với đúng đối số và đúng thứ tự. Các đối số chỉ định theo vị trí phải được truyền vào hàm dưới dạng đối số vị trí, không phải đối số từ khóa.
Ví dụ
Trong ví dụ sau, chúng ta đã định nghĩa hai đối số chỉ định theo vị trí là x và y. Phương thức này phải được gọi với các đối số vị trí theo đúng thứ tự mà chúng được khai báo. Nếu không, chúng ta sẽ nhận được lỗi.
def posFun(x, y, /, z):
print(x + y + z)
print("Đánh giá đối số chỉ định theo vị trí:")
posFun(33, 22, z=11)
Sau khi chạy đoạn code trên, kết quả sẽ là:
Đánh giá đối số chỉ định theo vị trí:
66
Giải thích code:
def posFun(x, y, /, z):
: Định nghĩa hàmposFun
với ba tham số:x
,y
vàz
. Dấu/
trong danh sách tham số chỉ định rằngx
vày
là các đối số chỉ định theo vị trí.print(x + y + z)
: Hàm này tính tổng ba tham sốx
,y
,z
và in kết quả.print("Đánh giá đối số chỉ định theo vị trí:")
: In ra một thông báo cho biết ta sắp thực hiện gọi hàm có đối số chỉ định theo vị trí.posFun(33, 22, z=11)
: Gọi hàmposFun
, truyền giá trị 33 chox
, 22 choy
và truyền 11 choz
thông qua đối số từ khóa.
Đối số chỉ từ khóa (Keyword-only arguments)
Những đối số mà bắt buộc phải được chỉ định bằng tên khi gọi hàm được gọi là đối số chỉ định theo từ khóa. Để định nghĩa các đối số này, bạn cần đặt một dấu hoa thị (*
) trong danh sách tham số của hàm, ngay trước bất kỳ tham số chỉ định theo từ khóa nào. Loại đối số này chỉ có thể được truyền vào hàm dưới dạng đối số từ khóa, chứ không phải là đối số vị trí.
Ví dụ
Trong đoạn code dưới đây, ta định nghĩa một hàm với ba đối số chỉ định theo từ khóa. Để gọi hàm này, chúng ta bắt buộc phải truyền đối số từ khóa, nếu không sẽ xảy ra lỗi.
def posFun(*, num1, num2, num3):
print(num1 * num2 * num3)
print("Đánh giá các đối số chỉ định theo từ khóa: ")
posFun(num1=6, num2=8, num3=5)
Đoạn code trên khi chạy sẽ cho ra kết quả sau:
Đánh giá các đối số chỉ định theo từ khóa:
240
Giải thích code:
def posFun(*, num1, num2, num3):
: Dòng này định nghĩa hàmposFun
với ba tham số lànum1
,num2
, vànum3
. Dấu hoa thị*
trước các tham số này đánh dấu chúng là đối số chỉ định theo từ khóa.print(num1 * num2 * num3)
: Lệnh in kết quả tích của ba tham sốnum1
,num2
, vànum3
.print("Đánh giá các đối số chỉ định theo từ khóa: ")
: Lệnh in thông báo.posFun(num1=6, num2=8, num3=5)
: Dòng này gọi hàmposFun
. Để ý rằng ta bắt buộc phải truyền tham số dưới dạngnum1=6
,num2=8
, vànum3=5
. Nếu chúng ta gọiposFun(6, 8, 5)
thì Python sẽ báo lỗi.
Đối số tùy ý trong Python
Đôi khi, bạn có thể cần một hàm để xử lý nhiều đối số hơn so với số lượng bạn đã chỉ định khi định nghĩa hàm. Những đối số này được gọi là đối số có độ dài thay đổi hoặc đối số tùy ý, và đối số này không có tên trong định nghĩa hàm (không giống như các đối số bắt buộc hoặc đối số mặc định).
Cú pháp
Cú pháp của một hàm có đối số không từ khóa với độ dài thay đổi như sau:
def ten_ham([tham_so_chinh_thuc,] *tuple_doi_so_thay_doi):
"chuoi_tai_lieu_cua_ham"
phan_than_cua_ham
return [bieu_thuc]
Dấu hoa thị (*
) được đặt trước tên biến chứa giá trị của tất cả các đối số không từ khóa có độ dài thay đổi. Tuple
này sẽ trống nếu không có thêm đối số nào được chỉ định trong quá trình gọi hàm.
Ví dụ
Dưới đây là một ví dụ đơn giản về cách sử dụng đối số độ dài thay đổi trong Python:
# Định nghĩa hàm
def printinfo(arg1, *vartuple):
"Hàm này in các đối số có độ dài thay đổi"
print("Kết quả là:")
print(arg1)
for var in vartuple:
print(var)
return
# Gọi hàm
printinfo(10)
printinfo(70, 60, 50)
Khi đoạn mã trên được thực thi, kết quả sẽ hiển thị như sau:
Kết quả là:
10
Kết quả là:
70
60
50
Giải thích code:
def printinfo(arg1, *vartuple):
: Dòng này định nghĩa hàmprintinfo
với một tham số bắt buộcarg1
và một tham số tùy ý*vartuple
. Dấu*
trướcvartuple
chỉ ra rằng hàm này có thể nhận nhiều đối số không từ khóa (có độ dài thay đổi) và chúng sẽ được gom thành một tuple gọi làvartuple
.print("Kết quả là:")
: Dòng lệnh in ra thông báo “Kết quả là:”.print(arg1)
: Dòng lệnh này in giá trị của tham sốarg1
.for var in vartuple:
: Vòng lặpfor
duyệt qua từng phần tử trong tuplevartuple
.print(var)
: Trong vòng lặp, mỗi phần tửvar
trong tuple sẽ được in ra.return
: Kết thúc hàm.printinfo(10)
: Lệnh này gọi hàm với tham số đầu tiên là10
.vartuple
sẽ là tuple rỗng.printinfo(70, 60, 50)
: Lệnh này gọi hàm vớiarg1 = 70
vàvartuple = (60, 50)
.
Thứ tự các đối số của hàm Python
Một hàm có thể có các đối số thuộc bất kỳ loại nào đã được định nghĩa. Tuy nhiên, các đối số này cần được khai báo theo một thứ tự cụ thể như sau:
- Danh sách đối số bắt đầu bằng các đối số chỉ theo vị trí (positional-only arguments), tiếp theo là dấu gạch chéo (/).
- Tiếp theo là các đối số vị trí thông thường, có thể được gọi hoặc không gọi bằng đối số từ khóa.
- Sau đó, có thể có một hoặc nhiều đối số có giá trị mặc định.
- Tiếp theo là các đối số vị trí tùy ý, được biểu diễn bằng một biến có tiền tố là dấu hoa thị đơn (*), và được xem như một tuple.
- Nếu hàm có bất kỳ đối số chỉ theo từ khóa (keyword-only arguments) nào, bạn cần đặt một dấu hoa thị (*) trước tên của chúng. Một số đối số chỉ theo từ khóa có thể có giá trị mặc định.
- Cuối cùng, trong ngoặc là đối số có hai dấu hoa thị (**) để chấp nhận một số lượng tùy ý các đối số từ khóa.
Sơ đồ sau đây cho thấy thứ tự của các đối số chính thức:
Hàm Python với lệnh return
Từ khóa return
được sử dụng như câu lệnh cuối cùng trong định nghĩa hàm, báo hiệu kết thúc khối lệnh của hàm. Sau khi gặp return, chương trình sẽ quay trở lại hàm đã gọi hàm này. Mặc dù việc giảm thụt lề sau câu lệnh cuối cùng trong khối lệnh cũng ngầm định sự kết thúc của hàm, nhưng việc sử dụng return
một cách tường minh vẫn được xem là một thói quen tốt.
Ngoài việc điều khiển luồng thực thi, hàm cũng có thể trả về giá trị của một biểu thức cho hàm đã gọi nó. Giá trị được trả về có thể được lưu trữ trong một biến để xử lý tiếp.
Ví dụ
Hãy cùng định nghĩa hàm add()
để minh họa. Hàm add()
sẽ cộng hai giá trị được truyền vào và trả về tổng của chúng. Giá trị được trả về sẽ được lưu trữ trong một biến có tên là result
.
def add(x, y):
z = x + y
return z
a = 10
b = 20
result = add(a, b)
print ("a = {} b = {} a+b = {}".format(a, b, result))
Đoạn code trên khi chạy sẽ cho ra kết quả sau:
a = 10 b = 20 a+b = 30
Giải thích code:
def add(x, y):
: Dòng này định nghĩa hàmadd
có hai tham số đầu vào làx
vày
.z = x + y
: Trong hàm, biếnz
được gán bằng tổng củax
vày
.return z
: Hàm trả về giá trị của biếnz
(tổng củax
vày
) về nơi hàm được gọi.a = 10
vàb = 20
: Hai biếna
vàb
được gán giá trị lần lượt là10
và20
.result = add(a, b)
: Hàmadd
được gọi với đối sốa
vàb
, giá trị trả về được gán cho biếnresult
.print ("a = {} b = {} a+b = {}".format(a, b, result))
: Câu lệnh này in ra màn hình giá trị của các biếna
,b
vàresult
, sử dụng format string để hiển thị kết quả rõ ràng.
Hàm Anonymous trong Python
Các hàm được gọi là “Anonymous” khi hàm này không được khai báo theo cách tiêu chuẩn, sử dụng từ khóa def
. Thay vào đó, các hàm này được định nghĩa bằng cách sử dụng từ khóa lambda.
- Hàm lambda có thể nhận bất kỳ số lượng đối số nào, nhưng chỉ trả về một giá trị duy nhất dưới dạng một biểu thức. Hàm này không thể chứa các lệnh (statement) hoặc nhiều biểu thức.
- Một hàm vô danh không thể gọi trực tiếp hàm print vì lambda yêu cầu một biểu thức trả về một giá trị.
- Các hàm lambda có không gian tên cục bộ riêng và không thể truy cập các biến bên ngoài danh sách tham số và các biến trong không gian tên toàn cục.
- Mặc dù có vẻ như lambda là một phiên bản rút gọn một dòng của hàm thông thường, nhưng thực tế không tương đương với các lệnh nội tuyến (inline) trong C hoặc C++, mà mục đích của lệnh nội tuyến là bỏ qua việc cấp phát ngăn xếp hàm trong quá trình gọi để tăng hiệu suất.
Cú pháp của hàm lamba
Cú pháp của hàm lambda chỉ chứa một biểu thức duy nhất, như sau:
lambda [arg1 [,arg2,.....argn]]: biểu_thức
Ví dụ
Ví dụ dưới đây minh họa cách hàm lambda
hoạt động:
# Định nghĩa hàm lambda
sum = lambda arg1, arg2: arg1 + arg2
# Gọi hàm lambda
print ("Giá trị tổng là : ", sum(10, 20))
print ("Giá trị tổng là : ", sum(20, 20))
Khi đoạn mã trên được thực thi, kết quả sẽ là:
Giá trị tổng là : 30
Giá trị tổng là : 40
Giải thích code:
sum = lambda arg1, arg2: arg1 + arg2
: Đây là cách định nghĩa một hàm lambda có tênsum
. Hàm này nhận hai tham sốarg1
vàarg2
, và trả về tổng của chúng (arg1 + arg2
). Cấu trúc này gọn nhẹ và tương đương với việc định nghĩa hàm thông thường với từ khóadef
nhưng ngắn gọn hơn.print ("Giá trị tổng là : ", sum(10, 20))
: Gọi hàmsum
(là một hàm lambda) với hai tham số là10
và20
. Sau đó in kết quả ra màn hình.print ("Giá trị tổng là : ", sum(20, 20))
: Tương tự, dòng này gọi hàmsum
với hai tham số20
và20
, rồi in kết quả ra.
Phạm vi biến trong Python
Không phải tất cả các biến trong một chương trình đều có thể được truy cập ở mọi nơi. Điều này phụ thuộc vào vị trí bạn khai báo biến đó.
Phạm vi của một biến xác định phần nào của chương trình mà bạn có thể truy cập vào biến đó. Trong Python, có hai phạm vi biến cơ bản:
- Biến toàn cục (Global variables)
- Biến cục bộ (Local variables)
Biến toàn cục (Global) và biến cục bộ (Local)
Các biến được khai báo bên trong một hàm có phạm vi cục bộ, và các biến được khai báo bên ngoài có phạm vi toàn cục.
Điều này có nghĩa là biến cục bộ chỉ có thể được truy cập bên trong hàm mà chúng được khai báo, trong khi đó biến toàn cục có thể được truy cập ở bất cứ đâu trong chương trình và bởi tất cả các hàm. Khi bạn gọi một hàm, các biến được khai báo bên trong hàm sẽ bắt đầu có hiệu lực trong phạm vi đó.
Ví dụ
Dưới đây là một ví dụ minh họa phạm vi cục bộ và toàn cục:
total = 0 # Đây là biến toàn cục
# Định nghĩa hàm
def sum(arg1, arg2):
# Cộng hai tham số và trả về kết quả.
total = arg1 + arg2 # Đây là biến cục bộ
print("Trong hàm, biến cục bộ total:", total)
return total
# Gọi hàm sum
sum(10, 20)
print("Ngoài hàm, biến toàn cục total:", total)
Khi đoạn mã trên được thực thi, kết quả sẽ như sau:
Trong hàm, biến cục bộ total: 30
Ngoài hàm, biến toàn cục total: 0
Giải thích code:
total = 0
: Đây là khai báo biếntotal
bên ngoài hàmsum
, tức đây là biến toàn cục (global).def sum(arg1, arg2):
: Khai báo một hàmsum
có hai tham sốarg1
vàarg2
.total = arg1 + arg2
: Bên trong hàmsum
, lại có một biếntotal
được khai báo và gán giá trị. Đây là một biến cục bộ (local).print("Trong hàm, biến cục bộ total:", total)
: Lệnh này in ra giá trị của biếntotal
cục bộ bên trong hàmsum
.return total
: Lệnh này trả về giá trị của biếntotal
cục bộ.sum(10, 20)
: Gọi hàmsum
với hai đối số là 10 và 20.print("Ngoài hàm, biến toàn cục total:", total)
: Lệnh này in ra giá trị của biếntotal
toàn cục bên ngoài hàmsum
.
Lời kết
Vậy là chúng ta vừa cùng nhau khám phá chi tiết về hàm trong Python, từ khái niệm cơ bản đến cách ứng dụng hàm trong thực tế. Hy vọng rằng những kiến thức này sẽ giúp bạn viết code Python một cách hiệu quả và tối ưu hơn. Hãy tiếp tục luyện tập và đừng ngần ngại thử sức với các hàm phức tạp hơn để nâng cao kỹ năng lập trình.