Cơ Chế Hoạt Động Và Phạm Vi Của Hàm Trong Python

Tổng Quan Về Định Nghĩa Hàm

Khi xây dựng các hàm tự định nghĩa, developer cần nắm vững cấu trúc cơ bản cũng như các cơ chế nâng cao như xử lý tham số linh hoạt và closure (bao đóng).

Cơ Chế Truyền Tham Số

Trong Python, cơ chế truyền tham số thực chất là truyền tham chiếu đến đối tượng (memory address). Điều này có nghĩa là biến bên trong hàm sẽ trỏ đến cùng một vùng nhớ với biến bên ngoài nếu đó là đối tượng có thể thay đổi (mutable).

data_source = [10, 20, 30, 40]

def inspect_address(param):
    # In ra địa chỉ bộ nhớ của danh sách được truyền vào
    print(id(param))

print(id(data_source))  # Địa chỉ bộ nhớ gốc
inspect_address(data_source)

# Kết quả cho thấy cả hai đều trỏ về cùng một địa chỉ bộ nhớ

Giá Trị Trả Về Của Hàm

Hàm có thể trả về nhiều kiểu dữ liệu khác nhau, bao gồm cả chính một hàm khác. Nếu không có lệnh return, giá trị mặc định là None. Khi trả về nhiều giá trị cách nhau bởi dấu phẩy, Python thực chất đóng gói chúng vào một tuple.

def generate_handler():
    def internal_logic():
        pass
    return internal_logic

processor = generate_handler()

# Trả về nhiều giá trị tương đương với một tuple
def get_coordinates():
    return 10, 20, 30  # Tương đương return (10, 20, 30)

Thời Điểm Thực Thi Và Closure

Mã nguồn bên trong hàm chỉ được thực thi khi hàm đó được gọi. Điều này dẫn đến sự khác biệt lớn khi tạo hàm trong vòng lặp, đặc biệt liên quan đến việc đóng gói biến môi trường (closure).

Xét ví dụ sau để thấy sự khác biệt giữa việc lưu trữ định nghĩa hàm tham chiếu biến ngoài và lưu trữ kết quả của hàm factory đã đóng gói giá trị:

def global_reader():
    return current_index

def create_closure(val):
    def inner():
        return val
    return inner

store_definition = []
store_closure = []

for current_index in range(5):
    store_definition.append(global_reader)
    store_closure.append(create_closure(current_index))

# Khi thực thi:
# Các hàm trong store_definition sẽ tra cứu biến current_index lúc chạy (late binding)
# Các hàm trong store_closure đã lưu giá trị val tại thời điểm tạo hàm (early binding)
for task in store_definition:
    print(task())  # Tất cả đều ra giá trị cuối cùng của vòng lặp (4)

for task in store_closure:
    print(task())  # Ra lần lượt 0, 1, 2, 3, 4

Những Điểm Cần Ghi Nhớ

  • Thứ tự ưu tiên khi gọi hàm: Tham số vị trí (positional) trước, sau đó đến tham số tên (keyword).
  • Code trong hàm không chạy nếu không có lời gọi hàm cụ thể.
  • Mỗi lần gọi hàm, một khung nhớ mới (stack frame) được tạo để lưu trữ trạng thái riêng biệt cho lần gọi đó.
  • Quy tắc tìm kiếm biến (LEGB): Tìm trong phạm vi cục bộ trước, nếu không thấy sẽ tìm lên phạm vi bao ngoài.

Thẻ: python function-closures scope-resolution memory-management

Đăng vào ngày 30 tháng 5 lúc 21:54