Giới thiệu về hàm trong Python

Table of Content

Hàm là một chuỗi các câu lệnh thực hiện một số tác vụ. Chúng ta sử dụng hàm để loại bỏ sự trùng lặp mã. Thay vì viết cùng một số câu lệnh hết lần này đến lần khác ở nhiều nơi trong chương trình, ta gom chúng trong một hàm và chạy các câu lệnh này bằng cách tham chiếu đến tên của hàm.

Một tiện lợi nữa là khi cần thay đổi tác vụ ta chỉ cần thay đổi mã ở trong hàm mà không phải viết lại ở tất cả những nơi cần sử dụng tác vụ này.

Định nghĩa hàm

Mã sau định nghĩa một hàm đơn giản không có tham số và không trả về bất kỳ giá trị nào.

def print_a_message():
    print("Hello, world!")

Chúng ta sử dụng từ khóa def để định nghĩa hàm. Phần tiếp theo def là tên của hàm cần định nghĩa, trong trường hợp này là print_a_message, theo sau là dấu ngoặc đơn (là nơi định nghĩa các tham số nếu có) và dấu hai chấm. Sau đó mọi thứ được thụt lề một cấp để chỉ phần thân của hàm.

Các hàm thực hiện một hành động nào đó. Vì vậy tên hàm thường là một động từ, hoặc cụm từ có chứa động từ giải thích càng đơn giản, càng chính xác những gì hàm thực hiện thì càng tốt.

Gọi hàm

Việc định nghĩa một hàm không làm cho nó thực sự chạy. Để chạy một hàm, chúng ta phải gọi nó. Để gọi hàm, chúng ta sử dụng tên của hàm, theo sau là dấu ngoặc đơn (với đối số ở giữa chúng).

>>> def print_a_message():
        print("Hello, world!")
>>> print_a_message()
Hello, world!

Chúng ta thực sự đã gọi những hàm tích hợp sẵn của Python, chẳng hạn như printlen.

>>> print("Hello")
Hello
>>> len([1, 2, 3])
3

Trong Python, hàm cũng được xem như mọi đối tượng khác. Ta có thể gán hàm như một giá trị cho một biến, sau đó gọi hàm qua biến này.

>>> def print_a_message():
        print("Hello, world!")
>>> my_function = print_a_message
>>> my_function()
Hello, world!

Vì định nghĩa một hàm không làm cho nó thực sự chạy, chúng ta có thể sử dụng một định danh bên trong một hàm ngay cả khi định danh ấy chưa được định nghĩa – miễn là nó được định nghĩa vào thời điểm chúng ta chạy hàm. Ví dụ, chúng ta có thể định nghĩa các hàm gọi lẫn nhau mà không cần bận tâm thứ tự định nghĩa chúng miễn là trước khi gọi, tất cả các hàm đều đã được định nghĩa.

def my_function():
    my_other_funcion()

def my_other_function():
    print("Hello!")

# sau các định nghĩa, ta có thể gọi hàm
my_function()

Nếu gọi hàm trước khi định nghĩa, sẽ có lỗi xuất hiện.

def my_function():
    my_other_function()

# không gọi my_function ở đây được vì my_other_function
# chưa được định nghĩa
my_function()

def my_other_function():
    print("Hello!")

Bởi vậy trong thực hành, bên nên đặt tất cả các định nghĩa hàm ở đầu chương trình.

Các tham số

Rất hiếm gặp trường hợp tác vụ mà chúng ta muốn thực hiện hoàn toàn giống nhau. Thường có những khác biệt nhỏ đối với những gì chúng ta cần làm trong các trường hợp khác nhau. Chúng ta không muốn tạo ra thêm những hàm mới cho những trường hợp khác nhau này! Thay vào đó, chúng ta muốn truyền thông tin vào hàm và sử dụng nó bên trong hàm để điều chỉnh hành vi của hàm theo nhu cầu chính xác của chúng ta. Chúng ta biểu diễn những thông tin truyền vào hàm dưới dạng các tham số của hàm.

Ví dụ, chúng ta có thể làm cho hàm print_a_message ở trên hữu ích hơn nếu ta làm cho nội dung thông báo có thể tùy chỉnh được.

>>> def print_a_message(message):
    print(message)  
>>> print_a_message("Hello, world!")
Hello, world!
>>> print_a_message("I'm Python!")
I'm Python!

Một ví dụ khác, hữu ích hơn, ta có thể truyền hai số vào hàm, hàm này tính toán và in ra tổng của hai số.

def print_sum(a, b):
    print(a + b)

ab là các tham số (parameters). Khi chúng ta gọi hàm, ta phải truyền các giá trị cho hai tham số này, nếu không sẽ gây ra lỗi.

>>> print_sum(2,3)
5
>>> print_sum()
TypeError: print_sum() missing 2 required positional arguments: 'a' and 'b'        

Trong ví dụ trên, chúng ta truyền các giá trị 23 dưới dạng các đối số cho hàm khi ta gọi nó. Khi hàm được chạy, đối số 2 sẽ được gán cho tham số a, đối số 3 sẽ được truyền cho tham số b. Sau đó bạn sử dụng biến ab để sử dụng các giá trị này bên trong hàm.

Tham số có giá trị mặc định

Bạn có thể chỉ định giá trị mặc định của một tham số. Giá trị mặc định này được dùng nếu ta không truyền đối số cho tham số. Ví dụ minh họa cách cung cấp giá trị mặc định của một tham số trong Python.

>>> def print_a_message(message='Hello!'):
    print(message)
>>> print_a_message()
Hello

Giá trị trả về của hàm

Các hàm ta đã định nghĩa ở trên không trả về bất cứ giá trị nào – chúng chỉ in ra một thông báo. Chúng ta thường muốn sử dụng một hàm để tính toán một giá trị và sau đó trả lại cho ta, để chúng ta có thể lưu trữ nó trong một biến và sử dụng nó sau này. Đầu ra được trả về của một hàm được gọi là giá trị trả về. Chúng ta có thể viết lại print_sum để nó trả về kết quả của phép cộng thay vì in nó.

def add(a, b):
    return a + b

Chúng ta sử dụng từ khóa return để định nghĩa giá trị trả về. Để truy cập giá trị này khi chúng ta gọi hàm, ta phải gán kết quả của hàm cho một biến.

>>> c = add(2, 3)
>>> c
5

Một hàm chỉ có thể trả về một đối tượng duy nhất, nhưng đối tượng đó có thể là một danh sách hoặc một tuple, vì vậy trong thực tế, bạn có thể trả về bao nhiêu giá trị từ một hàm cũng được. Nếu bạn đặt một danh sách các giá trị sau return chúng sẽ tự động được chuyển thành một tuple. Bạn có thể gán một tuple cho nhiều biến cùng một lúc, vì vậy bạn có thể giải nén một bộ giá trị do một hàm trả về thành nhiều biến.

def divide(dividen, divisor):
    quotien = dividen // divisor
    remainder = dividen % divisor
    return quotien, remainder

# cách 1
q, r = divide(35, 4)
print(q)
print(r)
print()

# cách 2
result = divide(35, 4)
q = result[0]
r = result[1]
print(q)
print(r)
print()

# danh sách cũng được hỗ trợ
c, d = [5, 6]
print(c)
print(d) 

Kết quả:

8
3

8
3

5
6

Chuyện gì xảy ra nếu ta gán một hàm không trả về giá trị cho biến?

>>> def print_message(message):
    print(message)
>>> mystery_output = print_message("Boo!")
Boo!
>>> print(mystery_output)
None

Mọi hàm thực sự luôn trả về một thứ gì đó, ngay cả khi chúng ta không định nghĩa giá trị trả về – giá trị trả về mặc định là None.

Khi return thực hiện xong, việc chạy hàm cũng hoàn thành – bất kỳ câu lệnh nào bên dưới return khi đó đều bị bỏ qua. Chúng ta có thể sử dụng điều này để kết thúc một hàm khi một điều kiện nào đó được thỏa mãn.

def divide(dividen, divisor):
    if not divisor:
        return None, None # số chia bằng không
    quotien = dividen // divisor
    remainder = dividen % divisor
    return quotien, remainder

Leave a Reply