
Chào các "dev future" của anh Creyt! Hôm nay, chúng ta sẽ "khui" một khái niệm mà nhiều người hay lầm tưởng là "dễ ăn" nhưng thực chất lại là "con dao hai lưỡi": globals trong Python. Nghe tên đã thấy "toàn cầu" rồi đúng không? Cùng anh "mổ xẻ" nó nhé!
1. globals là gì mà "oách" vậy? (Giải thích Gen Z)
Thử tưởng tượng thế này: code của tụi em như một cái "chung cư" khổng lồ. Mỗi function (hàm) là một căn hộ riêng biệt, có không gian và đồ đạc riêng (biến cục bộ - local variables). Nhưng trong chung cư nào mà chẳng có cái bảng thông báo chung ở sảnh, đúng không? Ai đi qua cũng thấy, ai cũng có thể ghi lên đó. Cái bảng thông báo đó chính là globals!
Nói một cách "hàn lâm" hơn thì globals là những biến được khai báo ở phạm vi cao nhất của một module (file .py). Chúng có thể được truy cập từ bất cứ đâu trong module đó, kể cả từ bên trong các hàm. Nghe tiện lợi đúng không? "Nhà nào cũng biết, ai cũng dùng được!"
Để làm gì? Ban đầu nghe có vẻ bá đạo lắm: dùng để lưu trữ những thông tin mà cả chương trình cần dùng đến, như cấu hình hệ thống, hằng số, hay trạng thái chung của ứng dụng. Mục đích là để các phần khác nhau của code có thể "chia sẻ" thông tin dễ dàng mà không cần phải "đèo" đi đèo lại qua các tham số.
2. Code Ví Dụ Minh Họa (Chuẩn kiến thức, dễ hiểu)
Đừng lý thuyết suông, phải "thực chiến" mới thấm! Xem ví dụ này:
# Đây là biến 'thông báo chung' của cả module, ai cũng thấy
TEN_UNG_DUNG = "CreytApp"
SO_LUONG_NGUOI_DUNG = 0
def chao_mung_nguoi_dung(ten):
# Hàm này đọc biến global TEN_UNG_DUNG
print(f"Chào mừng {ten} đến với {TEN_UNG_DUNG}!")
def tang_so_luong_nguoi_dung():
# !!! CẨN THẬN CHỖ NÀY !!!
# Nếu không có 'global', Python sẽ hiểu SO_LUONG_NGUOI_DUNG là biến cục bộ mới
# và chỉ tồn tại trong hàm này mà thôi. Biến global không thay đổi.
global SO_LUONG_NGUOI_DUNG # 'Ê, tao muốn thay đổi cái biến chung ngoài kia đó nha!'
SO_LUONG_NGUOI_DUNG += 1
print(f"Tổng số người dùng hiện tại: {SO_LUONG_NGUOI_DUNG}")
# Gọi các hàm
chao_mung_nguoi_dung("Thanh")
chao_mung_nguoi_dung("Huy")
tang_so_luong_nguoi_dung()
tang_so_luong_nguoi_dung()
print(f"\nKiểm tra lại từ bên ngoài: {SO_LUONG_NGUOI_DUNG} người dùng.")
# Ví dụ về việc tạo biến cục bộ trùng tên (không dùng 'global')
def test_bien_cuc_bo_trung_ten():
SO_LUONG_NGUOI_DUNG = 999 # Đây là biến cục bộ, không ảnh hưởng đến biến global
print(f"Trong hàm (cục bộ): {SO_LUONG_NGUOI_DUNG}")
test_bien_cuc_bo_trung_ten()
print(f"Sau khi gọi hàm test (global vẫn): {SO_LUONG_NGUOI_DUNG}")
Giải thích code:
TEN_UNG_DUNGvàSO_LUONG_NGUOI_DUNGlà biếnglobalvì chúng được khai báo ở ngoài cùng của file.- Hàm
chao_mung_nguoi_dungcó thể dễ dàng đọcTEN_UNG_DUNG. - Hàm
tang_so_luong_nguoi_dungmuốn thay đổi giá trị củaSO_LUONG_NGUOI_DUNGtoàn cục, nên phải dùng từ khóaglobalđể "khai báo ý định" với Python. Nếu không cóglobal, nó sẽ tạo ra một biến cục bộ mới cùng tên. - Ví dụ cuối cùng cho thấy nếu không có
global, việc gán giá trị cho một biến trùng tên trong hàm sẽ tạo ra một biến cục bộ, không ảnh hưởng đến biến toàn cục.

3. Mẹo (Best Practices) để không "tự bắn vào chân"
globals giống như một con dao sắc: dùng đúng cách thì hiệu quả, dùng sai thì "đứt tay" lúc nào không hay. Anh Creyt có vài "bí kíp" cho tụi em:
- "Dùng ít thôi, đừng lạm dụng!" Đây là lời khuyên vàng. Việc quá nhiều biến global khiến code khó hiểu, khó debug (gỡ lỗi) và khó bảo trì. Nó giống như việc cả chung cư dùng chung một chiếc điều khiển TV vậy, ai cũng bấm loạn xạ, không biết ai đang điều khiển gì. Kết quả là "spaghetti code" (code như mớ mì gói, rối nùi).
- "Biến bất biến thì đỡ lo hơn." Nếu biến global của em là một hằng số (không thay đổi giá trị sau khi được gán lần đầu), ví dụ như
PI = 3.14159hayDEBUG_MODE = True, thì việc dùngglobalsẽ ít rủi ro hơn nhiều. Khi đó, nó giống như một quy định chung của chung cư, ai cũng biết nhưng không ai được tự ý thay đổi. - "Pass tham số thay vì dùng global." Trong hầu hết các trường hợp, việc truyền dữ liệu vào hàm dưới dạng tham số là cách tốt hơn, tường minh hơn. Code sẽ dễ đọc, dễ kiểm soát và dễ test hơn rất nhiều. "Muốn dùng đồ nhà ai, thì gõ cửa xin chứ đừng tự tiện vào lấy."
- "Tránh thay đổi biến global trong hàm." Trừ khi thực sự cần thiết, hãy hạn chế tối đa việc dùng
globalđể thay đổi giá trị của biến toàn cục bên trong một hàm. Việc này tạo ra "side effects" (tác dụng phụ) khó lường, vì một hàm nhỏ có thể làm thay đổi trạng thái của cả chương trình mà không ai ngờ tới.
4. Ứng dụng thực tế: Ai đã dùng globals?
Tuy có nhiều "tai tiếng", nhưng globals không phải là vô dụng. Chúng vẫn có chỗ đứng của mình, đặc biệt là trong các trường hợp sau:
- Cấu hình ứng dụng (Configuration Settings): Các framework web như Django, Flask thường có các file cấu hình (ví dụ
settings.pytrong Django) nơi bạn định nghĩa các biến nhưDEBUG = True,DATABASE_URL,SECRET_KEY. Mặc dù không phảiglobaltheo đúng nghĩa đen của Python (chúng là biến cấp module được import), nhưng chúng hoạt động với vai trò tương tự: cung cấp các giá trị toàn cục cho ứng dụng. - Hằng số (Constants): Như đã nói, các hằng số không thay đổi thường được định nghĩa ở cấp module để dễ dàng truy cập từ mọi nơi.
- Flags/Trạng thái đơn giản: Trong các script nhỏ, nhanh gọn, việc dùng một biến global để đánh dấu trạng thái (ví dụ
is_logged_in = False) có thể tiện lợi.
5. Thử nghiệm và Hướng dẫn nên dùng cho case nào
Khi nào nên "mạnh dạn" dùng globals?
- Hằng số: Khi bạn có các giá trị không đổi mà nhiều phần của chương trình cần. Ví dụ:
MAX_RETRIES = 5,API_KEY = "abcxyz". - Cấu hình đơn giản: Cho các script nhỏ hoặc prototype, nơi việc tạo ra một hệ thống cấu hình phức tạp là quá mức cần thiết.
- Logging/Debug flags: Một biến
DEBUG_MODE = Truecó thể được bật/tắt để thay đổi hành vi của chương trình cho mục đích gỡ lỗi.
Khi nào nên "tránh xa" globals như tránh "crush cũ"?
- Ứng dụng lớn, phức tạp: Khi code của em bắt đầu có nhiều module, nhiều class, việc quản lý trạng thái qua
globalssẽ trở thành cơn ác mộng. Thay vào đó, hãy dùng các đối tượng (objects), truyền tham số, hoặc hệ thống quản lý trạng thái (state management) rõ ràng hơn. - Biến thay đổi liên tục: Nếu biến của em thay đổi giá trị thường xuyên và nhiều hàm khác nhau cùng thay đổi nó, thì việc dùng
globalsẽ khiến việc theo dõi luồng dữ liệu trở nên cực kỳ khó khăn. - Multi-threading/Concurrency: Trong môi trường đa luồng, việc nhiều luồng cùng truy cập và thay đổi biến global có thể dẫn đến các lỗi khó phát hiện (race conditions). Lúc này cần đến các cơ chế đồng bộ hóa phức tạp hơn.
Lời kết của anh Creyt
globals không phải là "ác quỷ" trong lập trình, nhưng nó đòi hỏi sự cẩn trọng và hiểu biết sâu sắc về cách nó hoạt động. Hãy coi nó như một công cụ mạnh mẽ nhưng cần được sử dụng có trách nhiệm. Cứ dùng đi, nhưng nhớ giữ chừng mực và luôn ưu tiên sự rõ ràng, dễ bảo trì của code lên hàng đầu. Code của tụi em không phải mì gói, nên đừng làm nó rối như mì gói nhé! Chúc "dev future" học tốt!
Thuộc Series: Python
Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!