Hàm bên trong Python

Category: Python

Trong Python, một hàm bên trong một hàm khác được gọi là hàm bên trong hoặc hàm lồng nhau . Các hàm bên trong giúp tổ chức mã, cải thiện khả năng đọc và duy trì tính đóng gói . Chúng có thể truy cập các biến từ hàm bên ngoài, khiến chúng hữu ích cho việc triển khai các closuretrình trang trí hàm.

Ví dụ:

def fun1(msg): # hàm bên ngoài
    
    def fun2(): # hàm bên trong
        print(msg)
    fun2()

fun1("Hello")

Đầu ra:

Hello

Giải thích: Ở đây, fun2() được định nghĩa bên trong fun1() và nó truy cập biến msg từ phạm vi bao quanh.

Tại sao nên sử dụng hàm Inner?

Các hàm bên trong mang lại một số lợi thế:

  • Đóng gói: Giúp ẩn logic bên trong khỏi sự truy cập từ bên ngoài.

  • Tổ chức mã: Làm cho mã sạch hơn bằng cách nhóm các chức năng liên quan.

  • Truy cập vào phạm vi bao quanh: Các hàm bên trong có thể truy cập các biến của hàm bên ngoài.

  • Closures: Cho phép các hàm giữ nguyên trạng thái của hàm bao quanh chúng ngay cả sau khi thực thi.

Phạm vi của các biến trong các hàm bên trong

Các hàm bên trong có thể truy cập các biến từ hàm bao quanh (bên ngoài) của chúng, nhưng việc sửa đổi chúng đòi hỏi phải xử lý đặc biệt. Điều này tuân theo quy tắc LEGB (Cục bộ, Bao quanh, Toàn cục, Tích hợp sẵn) của Python cho phạm vi biến.

Ví dụ 1: Truy cập biến cục bộ

def fun1():  # hàm bên ngoài (outer function)
    msg = "Geeks for geeks"
    
    def fun2():  # hàm bên trong (inner function)
        print(msg)  # truy cập biến của hàm bên ngoài
    
    fun2()

fun1()

Đầu ra:

Geeks for Geeks

Giải thích: fun1() định nghĩa một biến cục bộ msg và một hàm bên trong fun2() , in ra msg . Do phạm vi từ vựng, fun2() truy cập msg từ fun1() . Gọi fun1() sẽ gọi fun2() , in ra thông báo.

Ví dụ 2: Sửa đổi các biến bằng cách sử dụng nonlocal

def fun1():  # hàm bên ngoài (outer function)
    a = 45

    def fun2():  # hàm bên trong (inner function)
        nonlocal a  # cho phép sửa giá trị của biến `a` trong fun1
        a = 54
        print(a)  # in giá trị sau khi sửa

    fun2()
    print(a)  # in lại giá trị sau khi fun2 thay đổi

fun1()

Đầu ra

54 
54

Giải thích: từ khóa nonlocal cho phép fun2() sửa đổi biến a từ fun1(). Nếu không có nonlocal, một fun2() bên trong sẽ được coi là một biến cục bộ mới thay vì sửa đổi biến trong fun1() .

Ví dụ 3: closure trong hàm bên trong

def fun1(a):  # hàm bên ngoài (outer function)

    def fun2():  # hàm bên trong (inner function)
        print(a)

    return fun2  # trả về hàm mà không gọi nó (không có dấu ngoặc)

closure_func = fun1("Hello, Closure!")  # gọi fun1 và truyền vào chuỗi
closure_func()  # hàm bên trong vẫn nhớ được giá trị 'a'

Đầu ra

Hello, Closure!

Giải thích: Ngay cả sau khi fun1() hoàn tất thực thi, hàm fun2() trả về vẫn giữ nguyên quyền truy cập vào a , thể hiện một lệnh closure.

Ứng dụng thực tế của các hàm bên trong

Các hàm bên trong hữu ích trong các tình huống thực tế để tổ chức mã, đóng gói và tái sử dụng tốt hơn. Dưới đây là một số ứng dụng thực tế:

Ví dụ 1: Đóng gói các hàm trợ giúp

def process_data(data):
    # loại bỏ khoảng trắng thừa trong danh sách

    def clean_data():
        return [item.strip() for item in data]  # Loại bỏ khoảng trắng đầu và cuối

    return clean_data()  # trả về danh sách đã được làm sạch

print(process_data(["  Python  ", "  Inner Function  "]))

Đầu ra

['Python', 'Inner Function']

Giải thích: process_data(data) xóa khoảng trắng đầu và cuối khỏi mỗi chuỗi trong danh sách đầu vào. Nó định nghĩa một hàm lồng nhau, clean_data( ) , cắt bớt khoảng trắng bằng .strip() và trả về danh sách đã được làm sạch.

Ví dụ 2: Wrapper hàm và ghi nhật ký

import logging

logging.basicConfig(level=logging.INFO)  # cấu hình mức ghi log là INFO

def logger(func):
    # ghi log chi tiết quá trình thực thi hàm

    def wrapper(*args, **kwargs):
        logging.info(f"Đang thực thi {func.__name__} với đối số {args}, {kwargs}")  # ghi log khi gọi hàm
        return func(*args, **kwargs)  # gọi hàm gốc
    return wrapper

@logger
def add(a, b):
    return a + b  # trả về tổng

print(add(3, 4))

Đầu ra:

INFO:root:Executing add with (3, 4), {}
7

Giải thích: hàm logger , args ghi lại các đối số theo vị trí và *kwargs ghi lại các đối số từ khóa, cho phép trình bao bọc xử lý bất kỳ chữ ký hàm nào.

Thực hành tốt nhất để sử dụng các hàm bên trong

Các hàm bên trong rất mạnh nhưng nên được sử dụng một cách khôn ngoan để duy trì khả năng đọc, hiệu quả và khả năng bảo trì của mã. Dưới đây là một số biện pháp thực hành tốt nhất:

  • Chỉ sử dụng các hàm bên trong khi cần thiết: Tránh lồng nhau quá mức vì nó có thể làm giảm khả năng đọc.

  • Sử dụng closure một cách khôn ngoan: Đảm bảo các biến được nắm bắt được quản lý đúng cách để ngăn ngừa các tác dụng phụ không mong muốn.

  • Ưu tiên biến không cục bộ hơn biến toàn cục: Nếu sửa đổi biến hàm bên ngoài, hãy sử dụng biến không cục bộ thay vì biến toàn cục.

  • Sử dụng các hàm bên trong trình trang trí: Đây là trường hợp sử dụng phổ biến và hiệu quả.

Published on Jun 18, 2025