Skip to content

🌐 14.3 Biến cục bộ và toàn cục

📖 Giới thiệu

Scope (phạm vi) của biến là một khái niệm quan trọng trong lập trình. Python có các loại biến: biến cục bộ (local), biến toàn cục (global), và biến nonlocal. Hiểu rõ scope giúp tránh lỗi và viết code dễ bảo trì.

INFO

Scope xác định nơi biến có thể được truy cập và sửa đổi

🏠 Biến cục bộ (Local Variables)

📦 Biến trong function

python
def tinh_diem_trung_binh():
    """Function với biến cục bộ"""
    # Các biến này chỉ tồn tại trong function
    diem_toan = 8.5
    diem_ly = 9.0
    diem_hoa = 7.5
    
    # Biến tính toán cục bộ
    tong_diem = diem_toan + diem_ly + diem_hoa
    diem_tb = tong_diem / 3
    
    print(f"📊 Điểm các môn: Toán={diem_toan}, Lý={diem_ly}, Hóa={diem_hoa}")
    print(f"📈 Điểm trung bình: {diem_tb:.2f}")
    
    return diem_tb

# Gọi function
ket_qua = tinh_diem_trung_binh()

# Thử truy cập biến cục bộ từ bên ngoài (sẽ lỗi)
try:
    print(diem_toan)  # NameError
except NameError as e:
    print(f"❌ Lỗi: {e}")
    print("💡 Biến 'diem_toan' chỉ tồn tại trong function")

def xu_ly_danh_sach_hoc_sinh():
    """Demo biến cục bộ với cấu trúc dữ liệu"""
    # Danh sách cục bộ
    hoc_sinh = ["An", "Bình", "Chi", "Dung"]
    so_hoc_sinh = len(hoc_sinh)
    
    # Xử lý cục bộ
    hoc_sinh_vip = []
    for hs in hoc_sinh:
        if len(hs) <= 3:  # Tên ngắn
            hoc_sinh_vip.append(hs.upper())
    
    print(f"👥 Tổng số học sinh: {so_hoc_sinh}")
    print(f"⭐ Học sinh VIP: {hoc_sinh_vip}")
    
    return hoc_sinh_vip

danh_sach_vip = xu_ly_danh_sach_hoc_sinh()
print(f"🎯 Kết quả trả về: {danh_sach_vip}")

⚡ Lifecycle của biến cục bộ

python
def demo_lifecycle():
    """Demo vòng đời của biến cục bộ"""
    print("🚀 Bắt đầu function")
    
    # Biến được tạo
    message = "Hello from function!"
    counter = 0
    
    print(f"📝 Biến message: {message}")
    
    # Vòng lặp với biến cục bộ
    for i in range(3):
        temp_var = f"Lần {i + 1}"  # Biến cục bộ trong vòng lặp
        counter += 1
        print(f"  🔄 {temp_var}, counter = {counter}")
    
    # temp_var và i vẫn tồn tại sau vòng lặp (trong Python)
    print(f"🔍 Giá trị i cuối cùng: {i}")
    print(f"🔍 temp_var cuối cùng: {temp_var}")
    
    print("🏁 Kết thúc function - các biến sẽ bị xóa")

demo_lifecycle()

# Các biến trong function đã không còn tồn tại
print("🧪 Function đã kết thúc, biến cục bộ đã bị xóa")

🌍 Biến toàn cục (Global Variables)

🌐 Khai báo và sử dụng biến global

python
# Biến toàn cục
ten_truong = "THPT Lê Quý Đôn"
nam_hoc = "2024-2025"
so_hoc_sinh_toan_truong = 1200

def in_thong_tin_truong():
    """Function đọc biến global (không cần khai báo)"""
    print(f"🏫 Trường: {ten_truong}")
    print(f"📅 Năm học: {nam_hoc}")
    print(f"👥 Tổng số học sinh: {so_hoc_sinh_toan_truong}")

def cap_nhat_so_hoc_sinh(so_moi):
    """Function sửa đổi biến global (cần từ khóa global)"""
    global so_hoc_sinh_toan_truong
    
    so_cu = so_hoc_sinh_toan_truong
    so_hoc_sinh_toan_truong = so_moi
    
    print(f"📊 Cập nhật số học sinh: {so_cu}{so_moi}")

def them_hoc_sinh_moi(so_luong):
    """Thêm học sinh mới"""
    global so_hoc_sinh_toan_truong
    so_hoc_sinh_toan_truong += so_luong
    print(f"➕ Thêm {so_luong} học sinh mới")

# Test biến global
print("🏛️ THÔNG TIN TRƯỜNG BAN ĐẦU:")
in_thong_tin_truong()

print(f"\n🔄 CẬP NHẬT DỮ LIỆU:")
cap_nhat_so_hoc_sinh(1250)
them_hoc_sinh_moi(30)

print(f"\n🏛️ THÔNG TIN SAU CẬP NHẬT:")
in_thong_tin_truong()

WARNING

Sử dụng biến global quá nhiều có thể làm code khó debug và bảo trì

🎯 Global vs Local cùng tên

python
# Biến global
diem_chuan = 15.0
thong_bao = "Thông báo toàn trường"

def kiem_tra_diem_chuan_local():
    """Function có biến local cùng tên với global"""
    # Biến local che biến global cùng tên
    diem_chuan = 18.0  # Local variable
    thong_bao = "Thông báo cục bộ"  # Local variable
    
    print(f"📊 Điểm chuẩn (local): {diem_chuan}")
    print(f"📢 {thong_bao}")

def kiem_tra_diem_chuan_global():
    """Function sử dụng biến global"""
    # Đọc biến global
    print(f"📊 Điểm chuẩn (global): {diem_chuan}")
    print(f"📢 {thong_bao}")

def cap_nhat_diem_chuan(diem_moi):
    """Function sửa biến global"""
    global diem_chuan
    diem_cu = diem_chuan
    diem_chuan = diem_moi
    print(f"🔄 Cập nhật điểm chuẩn: {diem_cu}{diem_moi}")

print("🧪 TEST GLOBAL VS LOCAL:")
print(f"Biến global ban đầu - diem_chuan: {diem_chuan}")

print(f"\n1️⃣ Function với biến local:")
kiem_tra_diem_chuan_local()

print(f"\n2️⃣ Function đọc global:")
kiem_tra_diem_chuan_global()

print(f"\n3️⃣ Function sửa global:")
cap_nhat_diem_chuan(20.0)

print(f"\n✅ Kiểm tra global sau khi sửa:")
print(f"Biến global hiện tại - diem_chuan: {diem_chuan}")

💾 Quản lý trạng thái với global

python
# Hệ thống đếm đơn giản với global
so_luot_truy_cap = 0
nguoi_dung_hien_tai = None
lich_su_hoat_dong = []

def dang_nhap(ten_nguoi_dung):
    """Đăng nhập người dùng"""
    global nguoi_dung_hien_tai, so_luot_truy_cap, lich_su_hoat_dong
    
    nguoi_dung_hien_tai = ten_nguoi_dung
    so_luot_truy_cap += 1
    lich_su_hoat_dong.append(f"Đăng nhập: {ten_nguoi_dung}")
    
    print(f"✅ {ten_nguoi_dung} đã đăng nhập (lượt thứ {so_luot_truy_cap})")

def dang_xuat():
    """Đăng xuất người dùng"""
    global nguoi_dung_hien_tai, lich_su_hoat_dong
    
    if nguoi_dung_hien_tai:
        lich_su_hoat_dong.append(f"Đăng xuất: {nguoi_dung_hien_tai}")
        print(f"👋 {nguoi_dung_hien_tai} đã đăng xuất")
        nguoi_dung_hien_tai = None
    else:
        print("⚠️ Chưa có ai đăng nhập")

def xem_trang_thai():
    """Xem trạng thái hệ thống"""
    print(f"📊 TRẠNG THÁI HỆ THỐNG:")
    print(f"  👤 Người dùng: {nguoi_dung_hien_tai or 'Chưa đăng nhập'}")
    print(f"  📈 Lượt truy cập: {so_luot_truy_cap}")
    print(f"  📋 Lịch sử ({len(lich_su_hoat_dong)} hoạt động):")
    for hoat_dong in lich_su_hoat_dong[-3:]:  # 3 hoạt động gần nhất
        print(f"    • {hoat_dong}")

# Demo hệ thống
print("🎮 DEMO HỆ THỐNG ĐĂNG NHẬP:")

xem_trang_thai()

dang_nhap("Nguyễn Văn An")
xem_trang_thai()

dang_nhap("Trần Thị Bình")  # Đổi user
xem_trang_thai()

dang_xuat()
xem_trang_thai()

🔗 Biến nonlocal (Nested Functions)

🎯 Nested functions và nonlocal

python
def tao_bo_dem():
    """Tạo function đếm với biến nonlocal"""
    count = 0  # Biến của outer function
    
    def tang_dem():
        """Inner function sửa biến của outer function"""
        nonlocal count  # Cho phép sửa biến count của outer function
        count += 1
        return count
    
    def giam_dem():
        """Inner function giảm đếm"""
        nonlocal count
        count -= 1
        return count
    
    def lay_gia_tri():
        """Inner function đọc giá trị (không cần nonlocal)"""
        return count
    
    def reset():
        """Reset counter về 0"""
        nonlocal count
        count = 0
        return count
    
    # Trả về dictionary các function
    return {
        "tang": tang_dem,
        "giam": giam_dem, 
        "gia_tri": lay_gia_tri,
        "reset": reset
    }

# Tạo bộ đếm
bo_dem = tao_bo_dem()

print("🔢 DEMO BỘ ĐẾM:")
print(f"Giá trị ban đầu: {bo_dem['gia_tri']()}")

print(f"Tăng 1: {bo_dem['tang']()}")
print(f"Tăng 1: {bo_dem['tang']()}")
print(f"Tăng 1: {bo_dem['tang']()}")

print(f"Giảm 1: {bo_dem['giam']()}")
print(f"Giá trị hiện tại: {bo_dem['gia_tri']()}")

print(f"Reset: {bo_dem['reset']()}")
print(f"Giá trị sau reset: {bo_dem['gia_tri']()}")

🏭 Factory function với nonlocal

python
def tao_may_tinh_ca_nhan():
    """Tạo máy tính cá nhân với memory"""
    memory = 0  # Bộ nhớ của máy tính
    lich_su = []  # Lịch sử tính toán
    
    def cong(x):
        nonlocal memory
        memory += x
        lich_su.append(f"+ {x} = {memory}")
        return memory
    
    def tru(x):
        nonlocal memory
        memory -= x
        lich_su.append(f"- {x} = {memory}")
        return memory
    
    def nhan(x):
        nonlocal memory
        memory *= x
        lich_su.append(f{x} = {memory}")
        return memory
    
    def chia(x):
        nonlocal memory
        if x != 0:
            memory /= x
            lich_su.append(f{x} = {memory}")
        else:
            lich_su.append("❌ Lỗi: Chia cho 0")
        return memory
    
    def clear():
        nonlocal memory
        memory = 0
        lich_su.append("🧹 Clear")
        return memory
    
    def xem_lich_su():
        return lich_su.copy()
    
    def lay_ket_qua():
        return memory
    
    return {
        "cong": cong,
        "tru": tru,
        "nhan": nhan,
        "chia": chia,
        "clear": clear,
        "lich_su": xem_lich_su,
        "ket_qua": lay_ket_qua
    }

# Tạo 2 máy tính độc lập
may_tinh_1 = tao_may_tinh_ca_nhan()
may_tinh_2 = tao_may_tinh_ca_nhan()

print("🖥️ DEMO 2 MÁY TÍNH ĐỘC LẬP:")

print(f"\n📱 Máy tính 1:")
may_tinh_1["cong"](10)
may_tinh_1["nhan"](3)
may_tinh_1["tru"](5)
print(f"Kết quả: {may_tinh_1['ket_qua']()}")

print(f"\n📱 Máy tính 2:")
may_tinh_2["cong"](100)
may_tinh_2["chia"](4)
print(f"Kết quả: {may_tinh_2['ket_qua']()}")

print(f"\n📋 Lịch sử máy tính 1:")
for step in may_tinh_1["lich_su"]():
    print(f"  {step}")

print(f"\n📋 Lịch sử máy tính 2:")
for step in may_tinh_2["lich_su"]():
    print(f"  {step}")

TIP

Nonlocal cho phép tạo closure - function "nhớ" được environment mà nó được tạo ra

📚 LEGB Rule - Thứ tự tìm kiếm biến

python
# Built-in scope (L-E-G-B)
# len, print, max, min, etc. là built-in

# Global scope
gia_tri_global = "Global Value"

def outer_function():
    """Enclosing scope"""
    gia_tri_enclosing = "Enclosing Value"
    
    def inner_function():
        """Local scope"""
        gia_tri_local = "Local Value"
        
        # Python tìm kiếm theo thứ tự: Local → Enclosing → Global → Built-in
        print(f"🔍 LEGB RULE DEMO:")
        print(f"  Local: {gia_tri_local}")
        print(f"  Enclosing: {gia_tri_enclosing}")
        print(f"  Global: {gia_tri_global}")
        print(f"  Built-in: {len('Hello')}")  # Built-in function
        
        # Test che biến
        len = "Tôi che built-in function len!"  # Local variable che built-in
        print(f"  Local len: {len}")
        
        # Để dùng built-in len, cần import builtins
        import builtins
        print(f"  Built-in len: {builtins.len('Hello')}")
    
    return inner_function

# Test LEGB
demo_func = outer_function()
demo_func()

# Demo biến cùng tên ở các scope khác nhau
ten = "Global"

def test_scope():
    ten = "Enclosing"
    
    def inner():
        ten = "Local"
        print(f"Inner function thấy: {ten}")
    
    inner()
    print(f"Enclosing function thấy: {ten}")

print(f"Global scope: {ten}")
test_scope()
print(f"Vẫn global: {ten}")

📝 Bài tập thực hành

Bài tập 1: Hệ thống quản lý điểm

Tạo hệ thống quản lý điểm sử dụng global variables:

python
# Đáp án
diem_luu_tru = {}  # Global storage

def them_diem(ten, mon, diem):
    global diem_luu_tru
    if ten not in diem_luu_tru:
        diem_luu_tru[ten] = {}
    diem_luu_tru[ten][mon] = diem
    print(f"✅ Đã thêm điểm {mon} cho {ten}: {diem}")

def xem_diem(ten):
    if ten in diem_luu_tru:
        print(f"📊 Điểm của {ten}:")
        for mon, diem in diem_luu_tru[ten].items():
            print(f"  {mon}: {diem}")
    else:
        print(f"❌ Không tìm thấy {ten}")

def tinh_diem_tb(ten):
    if ten in diem_luu_tru and diem_luu_tru[ten]:
        diem_list = list(diem_luu_tru[ten].values())
        return sum(diem_list) / len(diem_list)
    return 0

# Test
them_diem("An", "Toán", 8.5)
them_diem("An", "Lý", 9.0)
xem_diem("An")
print(f"Điểm TB: {tinh_diem_tb('An'):.2f}")

📚 Tóm tắt

Local Scope:

  • ✅ Biến trong function
  • ⚡ Tạo khi gọi function, xóa khi kết thúc
  • 🔒 Không truy cập được từ bên ngoài

Global Scope:

  • 🌍 Biến ngoài tất cả function
  • ♻️ Tồn tại suốt chương trình
  • 🔑 Cần từ khóa global để sửa đổi

Nonlocal Scope:

  • 🔗 Biến của outer function trong nested function
  • 🎯 Cần từ khóa nonlocal để sửa đổi
  • 💡 Tạo closure và factory functions

LEGB Rule:

  • 🔍 Local → Enclosing → Global → Built-in
  • 📊 Thứ tự Python tìm kiếm biến
  • ⚠️ Biến local có thể che biến ở scope cao hơn

Best Practices:

  • 🎯 Ưu tiên tham số function thay vì global
  • 📝 Sử dụng return thay vì sửa global
  • 🔒 Hạn chế global, dùng khi thật cần thiết
  • 💡 Nonlocal hữu ích cho closure và decorator

Lời khuyên

Hiểu rõ scope giúp tránh bug khó tìm và viết code dễ bảo trì. Ưu tiên function parameters và return values!

🐍 Khóa học Python căn bản bằng tiếng Việt