Tham số (parameter) của hàm trong Python

Đây là bài 15/54 bài của series môn học Ngôn ngữ lập trình Python

Ở bài này, chúng ta sẽ tìm hiểu về tham số (parameter) của hàm trong Python. Khi gọi một hàm, chúng ta cần truyền các đối số (argument) cho hàm. Để phân biệt tham số và đối số cũng như làm cơ sở học tốt bài này, các bạn có thể đọc bài Khái niệm tham số và đối số trong C++.

1. Định nghĩa hàm với các tham số

Khi một hàm (function) được định nghĩa, các tham số cũng được xác định bên trong dấu ngoặc đơn của hàm. Một hàm có thể có số lượng tham số bất kỳ. Mỗi tham số được phân tách bằng dấu phẩy ,.

def hello(name, msg):
    """Say hello to a person with message"""
    print("Hello ", name, ", ", msg, sep='')

hello("John", "Welcome to Gochocit.com!")
Kết quả
Hello John, Welcome to Gochocit.com!

Hàm hello(name, msg) có 2 tham số. Khi gọi hàm, nếu chúng ta chỉ truyền 1 đối số hoặc không truyền đối số nào sẽ gây ra lỗi.

def hello(name, msg):
    """Say hello to a person with message"""
    print("Hello ", name, ", ", msg, sep='')

#TypeError: hello() missing 1 required positional argument: 'msg'
hello("John")
#TypeError: hello() missing 2 required positional arguments: 'name' and 'msg'
hello()

2. Đối số mặc định của hàm trong Python

Khi định nghĩa hàm, chúng ta có thể cung cấp giá trị mặc định cho các tham số bằng cách sử dụng toán tử gán ‘=’. Chúng ta gọi là đối số mặc định (default argument). Ví dụ:

def hello(name, msg="Welcome to Gochocit.com!"):
    """Say hello to a person with message"""
    """If the msg is not provided, it defaults to "Welcome to Gochocit.com!"
    """
    print("Hello ", name, ", ", msg, sep='')

#Not provided any value for default argument
hello("John")
#Provided a value for default argument
hello("John", "How are you?")
Kết quả
Hello John, Welcome to Gochocit.com!
Hello John, How are you?

Trong ví dụ trên, tham số name không có giá trị mặc định nên bắt buộc phải truyền đối số khi gọi hàm. Còn tham số msg đã có giá trị mặc định là “Welcome to Gochocit.com!”. Nên khi gọi hàm có thể truyền đối số hoặc không đều được.

Lưu ý: Tất cả các tham số của hàm đều có thể có giá trị mặc định. Nhưng có trường hợp, một vài tham số có giá trị mặc định còn một vài tham số khác không có giá trị mặc định. Lúc này, tất cả tham số có giá trị mặc định đều phải được đặt bên phải các tham số không có giá trị mặc định. Nếu quy tắc này không được tuân thủ sẽ gây ra lỗi. Ví dụ:

#SyntaxError: non-default argument follows default argument
def hello(msg="Welcome to Gochocit.com!", name):
    """Say hello to a person with message"""
    """If the msg is not provided, it defaults to "Welcome to Gochocit.com!"
    """
    print("Hello ", name, ", ", msg, sep='')

Tham số msg có giá trị mặc định nằm trước (nằm bên trái) của tham số name không có giá trị mặc định sẽ gây ra lỗi SysntaxError.

3. Gọi hàm với tên của tham số

Khi chúng ta gọi một hàm, các giá trị truyền vào hàm sẽ tương ứng với các tham số theo thứ tự từ trái qua phải. Có một ý tưởng là cho phép gọi hàm bằng việc chỉ định tên tham số với các giá trị. Việc này có lợi là chúng ta không cần nhớ thứ tự của các tham số. Chúng ta gọi là keyword argument. Ví dụ:

def hello(name, msg):
    """Say hello to a person with message"""
    print("Hello ", name, ", ", msg, sep='')

# 2 keyword arguments
hello(name = "John", msg = "How are you?")
# 2 keyword arguments (out of order)
hello(msg = "How are you?", name = "John") 
#1 positional, 1 keyword argument
hello("John", msg = "How are you?")
Kết quả
Hello John, How are you?
Hello John, How are you?
Hello John, How are you?

Chúng ta có thể vừa sử dụng tên tham số vừa sử dụng thứ tự tham số khi gọi hàm. Nhưng sử dụng tên tham số phải luôn ở sau thứ tự tham số. Ví dụ:

def hello(name, msg):
    """Say hello to a person with message"""
    print("Hello ", name, ", ", msg, sep='')

#SyntaxError: positional argument follows keyword argument
hello(name = "John", "How are you?")  

Khi gọi hàm mà sử dụng tên tham số trước thứ tự tham số sẽ gây ra lỗi SyntaxError.

4. Gọi hàm với số lượng đối số tùy ý trong Python

Trong một số trường hợp, chúng ta không biết trước số lượng đối số truyền vào một hàm khi gọi hàm. Python cho phép truyền số lượng đối số khác cho mỗi lần gọi hàm bằng cách sử dụng các dấu hoa thị * (asterisk). Có 2 cách sử dụng dấu hoa thị * trong trường hợp này là:

    • *args (Non-Keyword Arguments)
    • **kwargs (Keyword Arguments)

Sử dụng *args (Non-Keyword Arguments)

Sử dụng một dấu hoa thị * trước tên tham số để sử dụng Non-Keyword Arguments. Tên tham số tuân thủ theo quy tắc đặt tên định danh (identifier).

def hello(*names):
    """Say hello to all person in names"""
    for name in names:
        print("Hello", name)

hello("John", "James", "Mary", "Robert", "Jennifer")
Kết quả
Hello John
Hello James
Hello Mary 
Hello Robert
Hello Jennifer

Nguyên tắc hoạt động của Non-Keyword Arguments là các đối số được đưa vào trong một tuple. Chúng ta sử dụng for để duyệt qua từng phần tử trong tuple này.

Sử dụng **kwargs (Keyword Arguments)

Sử dụng hai dấu hoa thị ** trước tên tham số để sử dụng Keyword Arguments. Các đối số được truyền vào hàm đều có một tên định danh (identifier) đại diện.

def hello(**notices):
    """Send notices to all person"""
    for key, value in notices.items():
        print("%s, %s" % (key, value))

hello(John="How are you?", James="Welcome to Gochocit.com!", Mary="Nice to meet you!")
Kết quả
John, How are you?
James, Welcome to Gochocit.com!
Mary, Nice to meet you!

5. Truyền đối số cho hàm trong Python là tham trị hay tham chiếu?

Nếu các bạn đã đọc bài Biến (variable)Bộ nhớ biến trong Python, thì các bạn sẽ biết tất cả biến trong Python đều tham chiếu đến một object nào đó. Khi gọi hàm, chúng ta truyền một biến cho hàm. Lúc này, một tham chiếu mới đến đối tượng (object) của biến đó sẽ được tạo ra. Ví dụ, chúng ta có một hàm và gọi hàm như sau:

def myFunction(val):
    if(val>0):
        print("val =", val, "is greater than 0")
    val = 9.1
    print("val =", val)
x = 5
myFunction(x)
print("x = ", x)
Kết quả
val = 5 is greater than 0
val = 9.1
x =  5

Trong ví dụ trên, cơ chế truyền đối số cho hàm myFunction(val) xảy ra như sau:

1) Khi gán x = 5 thì x tham chiếu đến một đối tượng của lớp int lưu trữ giá trị 5.

2) Chúng ta gọi hàm myFunction(x) với biến x là đối số được truyền vào cho hàm.

3) Sau đó, một biến val được tạo ra. Biến val này cũng sẽ tham chiếu đến đối tượng của lớp int lưu trữ giá trị 5 mà biến x tham chiếu đến. Tức là 2 biến xval cùng tham chiếu đến một object 5.

4) Nhưng sau đó, gán val = 9.1 thì lúc này val sẽ tham chiếu đến một đối tượng của lớp float lưu trữ giá trị 9.1. Tức là val bỏ tham chiếu đến object 5. Lúc này chỉ còn x tham chiếu đến object 5.

5) Sau khi hàm kết thúc, biến valobject 9.1 cũng bị xóa. Và biến x thì vẫn tham chiếu đến object 5 mà không bị thay đổi khi ra khỏi hàm.

Biến x và val tham chiếu đến cùng object 5
Biến x và val tham chiếu đến cùng object 5
Khi gán val = 9.1, biến x và val tham chiếu khác object
Khi gán val = 9.1, biến x và val tham chiếu khác object

Ví dụ truyền đối số là list cho hàm trong Python

#x is a new reference to same list lst
def myFunction(x):
    x[0] = 99
    x[2] = 999
 
lst = [10, 11, 12, 13, 14, 15]
myFunction(lst)
print(lst)
Kết quả
[99, 11, 999, 13, 14, 15]

Trong ví dụ trên, lstx cùng tham chiếu đến cùng object lưu trữ một danh sách (list). Khi x thay đổi các phần tử trong object này thì truy xuất bởi lst cũng sẽ được kết quả thay đổi theo.

Nhưng nếu gán x bằng một danh sách (list) khác thì xlst sẽ tham chiếu khác object. Ví dụ:

def myFunction(x):
    # A new object is assigned to x.
    x = [20, 30, 40]

lst = [10, 11, 12, 13, 14, 15]
myFunction(lst)
print(lst)
Kết quả
[10, 11, 12, 13, 14, 15]

Khi gán x = [20, 30, 40] thì x đã tham chiếu đến một object list khác. Do đó, xlst bây giờ không liên quan gì đến nhau.

Ví dụ truyền đối số là integer cho hàm trong Python

def myFunction(val):
    # A new object is assigned to x.
    val = 20
    print("val = ", val)

x = 10
myFunction(x)
print("x = ", x)
Kết quả
val =  20
x =  10

Khi gán val = 20 thì val đã tham chiếu đến một object int khác. Do đó, xval bây giờ không liên quan gì đến nhau.

Tóm lại, rõ ràng khi truyền đối số cho hàm trong Python là truyền tham chiếu. Nhưng điểm đặc biệt của Python là khi gán giá trị cho một biến với toán tử gán = thì liên kết tham chiếu cũ sẽ bị phá bỏ. Các bạn lưu ý điểm này khi truyền đối số cho hàm trong Python nhé!

5/5 - (1 bình chọn)
Bài trước và bài sau trong môn học<< Hàm (function) và cách xây dựng hàm trong PythonPhân biệt các biến global, local và nonlocal trong Python >>
Chia sẻ trên mạng xã hội:

Trả lời

Lưu ý:

1) Vui lòng bình luận bằng tiếng Việt có dấu.

2) Khuyến khích sử dụng tên thật và địa chỉ email chính xác.

3) Mọi bình luận trái quy định sẽ bị xóa bỏ.