Scope và Namespace trong Python
Scope (phạm vi) và Namespace (không gian tên) là hai khái niệm quan trọng giúp Python quản lý biến và tránh xung đột tên trong chương trình.
1. Namespace là gì?
Định nghĩa
Namespace là một “không gian tên” - một tập hợp các tên (identifiers) và các đối tượng mà chúng tham chiếu đến. Mỗi tên trong namespace phải là duy nhất.
Hãy tưởng tượng namespace như một cuốn từ điển:
- Key (tên biến):
age,name,calculate - Value (giá trị):
25,"John",<function>
# Namespace giống như một dictionary
# Ví dụ minh họa (không phải code thực)
# namespace = {
# 'x': 10,
# 'name': 'Python',
# 'calculate': <function object>
# }
x = 10
name = "Python"
def calculate():
passCác loại Namespace
Python có 4 loại namespace chính:
1. Built-in Namespace (Namespace tích hợp)
Chứa các tên của các hàm và biến được tích hợp sẵn trong Python (như print(), len(), int(), v.v.).
# Các hàm built-in luôn có sẵn
print(len([1, 2, 3])) # len là built-in
print(type(5)) # type là built-in
print(abs(-10)) # abs là built-in
# Xem tất cả built-in names
import builtins
print(dir(builtins))2. Global Namespace (Namespace toàn cục)
Chứa các tên được định nghĩa ở cấp độ module (file Python).
# Đây là global namespace của file này
global_var = "Tôi là biến toàn cục"
PI = 3.14159
def my_function():
pass
class MyClass:
pass
# Biến global_var, PI, my_function, MyClass đều nằm trong global namespace3. Enclosing Namespace (Namespace bao bọc)
Chứa các tên trong hàm bên ngoài (outer function) khi có nested functions.
def outer_function():
outer_var = "Tôi là biến của outer function"
def inner_function():
# inner_function có thể truy cập outer_var
# outer_var nằm trong enclosing namespace
print(outer_var)
inner_function()
outer_function() # In: Tôi là biến của outer function4. Local Namespace (Namespace cục bộ)
Chứa các tên được định nghĩa bên trong một hàm.
def my_function():
local_var = "Tôi là biến cục bộ"
x = 10
# local_var và x chỉ tồn tại trong hàm này
print(local_var)
my_function()
# print(local_var) # Lỗi: local_var không tồn tại ngoài hàm2. Scope là gì?
Định nghĩa
Scope (phạm vi) là khu vực trong code nơi một namespace có thể được truy cập trực tiếp. Scope xác định “phạm vi hoạt động” của một biến.
LEGB Rule - Quy tắc tìm kiếm biến
Python tìm kiếm biến theo thứ tự LEGB:
- L - Local: Scope cục bộ (trong hàm hiện tại)
- E - Enclosing: Scope bao bọc (hàm bên ngoài)
- G - Global: Scope toàn cục (cấp độ module)
- B - Built-in: Scope tích hợp sẵn
x = "global" # Global scope
def outer():
x = "enclosing" # Enclosing scope
def inner():
x = "local" # Local scope
print(x)
inner()
outer() # In: local
# Python tìm x theo thứ tự: Local → Enclosing → Global → Built-inMinh họa LEGB Rule
# Built-in: len() có sẵn trong Python
# Global: biến x ở cấp module
x = "global x"
def outer():
# Enclosing: biến x trong outer function
x = "enclosing x"
def inner():
# Local: biến x trong inner function
x = "local x"
print(f"1. Local x: {x}") # Tìm thấy ở Local
def inner2():
# Không có x local, tìm ở Enclosing
print(f"2. Enclosing x: {x}")
inner()
inner2()
outer()
print(f"3. Global x: {x}") # Tìm thấy ở Global
# Kết quả:
# 1. Local x: local x
# 2. Enclosing x: enclosing x
# 3. Global x: global x3. Local Scope (Phạm vi cục bộ)
Biến local
Biến được tạo bên trong hàm chỉ tồn tại trong hàm đó.
def my_function():
local_var = 100 # Biến local
print(f"Trong hàm: {local_var}")
my_function() # In: Trong hàm: 100
# print(local_var) # Lỗi: name 'local_var' is not definedTham số của hàm cũng là biến local
def greet(name): # 'name' là biến local
message = f"Hello, {name}!" # 'message' cũng là local
print(message)
greet("Alice") # In: Hello, Alice!
# print(name) # Lỗi: không tồn tại ngoài hàm
# print(message) # Lỗi: không tồn tại ngoài hàmBiến local không ảnh hưởng biến global cùng tên
x = "global"
def my_function():
x = "local" # Tạo biến local mới, không ảnh hưởng global x
print(f"Trong hàm: {x}")
my_function() # In: Trong hàm: local
print(f"Ngoài hàm: {x}") # In: Ngoài hàm: global4. Global Scope (Phạm vi toàn cục)
Biến global
Biến được tạo ở cấp độ module (ngoài tất cả các hàm).
# Biến global
global_var = "Tôi là biến toàn cục"
def function1():
print(global_var) # Đọc biến global: OK
def function2():
print(global_var) # Cũng đọc được
function1() # In: Tôi là biến toàn cục
function2() # In: Tôi là biến toàn cục
print(global_var) # In: Tôi là biến toàn cụcTừ khóa global
Để thay đổi biến global bên trong hàm, phải dùng từ khóa global.
count = 0 # Biến global
def increment():
global count # Khai báo sẽ dùng biến global
count += 1 # Thay đổi biến global
print(f"Count = {count}")
increment() # Count = 1
increment() # Count = 2
increment() # Count = 3
print(count) # 3Lỗi khi không dùng global
counter = 0
def increment():
# Không có từ khóa global
# counter += 1 # Lỗi: UnboundLocalError
# Python nghĩ counter là biến local nhưng chưa được gán giá trị
pass
# Cách đúng: dùng global
def increment_correct():
global counter
counter += 1
increment_correct()
print(counter) # 1Khi nào nên dùng global?
# ❌ KHÔNG NÊN: Lạm dụng global
score = 0
def add_score(points):
global score
score += points
def reset_score():
global score
score = 0
# ✅ NÊN: Dùng tham số và return
def add_score(current_score, points):
return current_score + points
score = 0
score = add_score(score, 10)
score = add_score(score, 5)
print(score) # 155. Enclosing Scope (Phạm vi bao bọc)
Nested Functions
Hàm bên trong có thể truy cập biến của hàm bên ngoài.
def outer():
x = "outer x"
def inner():
print(x) # Truy cập biến của outer
inner()
outer() # In: outer xTừ khóa nonlocal
Để thay đổi biến của hàm bên ngoài, dùng từ khóa nonlocal.
def outer():
count = 0
def inner():
nonlocal count # Khai báo dùng biến của outer
count += 1
print(f"Count = {count}")
inner() # Count = 1
inner() # Count = 2
print(f"Final count = {count}") # Final count = 2
outer()Lỗi khi không dùng nonlocal
def outer():
x = 10
def inner():
# x += 1 # Lỗi: UnboundLocalError
# Python nghĩ x là local nhưng chưa được gán
pass
inner()
# Cách đúng:
def outer_correct():
x = 10
def inner():
nonlocal x
x += 1
print(x)
inner() # In: 11
outer_correct()Ví dụ thực tế: Closure
def make_multiplier(n):
def multiplier(x):
return x * n # Truy cập n từ enclosing scope
return multiplier
# Tạo các hàm nhân
times_2 = make_multiplier(2)
times_3 = make_multiplier(3)
times_5 = make_multiplier(5)
print(times_2(10)) # 20
print(times_3(10)) # 30
print(times_5(10)) # 506. Built-in Scope
Namespace tích hợp sẵn
Python cung cấp sẵn nhiều hàm và biến.
# Các hàm built-in
print()
len()
type()
int()
str()
list()
dict()
# Xem tất cả built-in
import builtins
print(dir(builtins))Ghi đè built-in (KHÔNG NÊN làm)
# ❌ KHÔNG NÊN: Ghi đè built-in function
print("Before override")
print = "Now print is a string"
# print("After override") # Lỗi: 'str' object is not callable
# Khôi phục (phức tạp)
import builtins
print = builtins.print
print("Restored") # Hoạt động lại
# ❌ KHÔNG NÊN đặt tên biến trùng built-in
list = [1, 2, 3] # Ghi đè hàm list()
# my_list = list(range(5)) # Lỗi: 'list' object is not callable7. Hàm globals() và locals()
globals() - Xem global namespace
x = 10
y = 20
def my_function():
print(globals()) # Dictionary chứa tất cả biến global
my_function()
# Truy cập biến global qua globals()
print(globals()['x']) # 10
# Thêm biến global động
globals()['z'] = 30
print(z) # 30locals() - Xem local namespace
def my_function():
a = 1
b = 2
c = 3
print(locals()) # {'a': 1, 'b': 2, 'c': 3}
my_function()
# Ở global scope, locals() == globals()
x = 100
print(locals() == globals()) # True8. Ví dụ thực tế
Counter với closure
def create_counter():
count = 0
def increment():
nonlocal count
count += 1
return count
def decrement():
nonlocal count
count -= 1
return count
def get_count():
return count
return increment, decrement, get_count
# Tạo counter
inc, dec, get = create_counter()
print(inc()) # 1
print(inc()) # 2
print(inc()) # 3
print(dec()) # 2
print(get()) # 2Configuration Manager
# config.py
APP_NAME = "My Application"
VERSION = "1.0.0"
DEBUG = True
def get_config():
return {
'app_name': APP_NAME,
'version': VERSION,
'debug': DEBUG
}
def set_debug(value):
global DEBUG
DEBUG = value
# main.py
print(get_config())
set_debug(False)
print(get_config())Bank Account với encapsulation
def create_account(initial_balance):
balance = initial_balance # Private variable (enclosing scope)
def deposit(amount):
nonlocal balance
if amount > 0:
balance += amount
return f"Deposited {amount}. New balance: {balance}"
return "Invalid amount"
def withdraw(amount):
nonlocal balance
if 0 < amount <= balance:
balance -= amount
return f"Withdrew {amount}. New balance: {balance}"
return "Insufficient funds or invalid amount"
def get_balance():
return balance
return deposit, withdraw, get_balance
# Tạo tài khoản
deposit, withdraw, get_balance = create_account(1000)
print(get_balance()) # 1000
print(deposit(500)) # Deposited 500. New balance: 1500
print(withdraw(200)) # Withdrew 200. New balance: 1300
print(get_balance()) # 1300
# Không thể truy cập trực tiếp biến balance từ bên ngoài9. Bài tập thực hành
Bài 1: Phân biệt scope
x = "global"
def outer():
x = "outer"
def inner():
x = "inner"
print(f"inner x = {x}")
inner()
print(f"outer x = {x}")
outer()
print(f"global x = {x}")
# Kết quả:
# inner x = inner
# outer x = outer
# global x = globalBài 2: Tạo ID generator
def create_id_generator(start=1):
current_id = start - 1
def next_id():
nonlocal current_id
current_id += 1
return current_id
def reset():
nonlocal current_id
current_id = start - 1
return next_id, reset
# Sử dụng
next_id, reset = create_id_generator(100)
print(next_id()) # 100
print(next_id()) # 101
print(next_id()) # 102
reset()
print(next_id()) # 100Bài 3: Temperature Converter
CELSIUS_TO_FAHRENHEIT = lambda c: (c * 9/5) + 32
FAHRENHEIT_TO_CELSIUS = lambda f: (f - 32) * 5/9
def temperature_converter():
last_conversion = None
def celsius_to_fahrenheit(celsius):
nonlocal last_conversion
fahrenheit = CELSIUS_TO_FAHRENHEIT(celsius)
last_conversion = f"{celsius}°C = {fahrenheit}°F"
return fahrenheit
def fahrenheit_to_celsius(fahrenheit):
nonlocal last_conversion
celsius = FAHRENHEIT_TO_CELSIUS(fahrenheit)
last_conversion = f"{fahrenheit}°F = {celsius}°C"
return celsius
def get_last_conversion():
return last_conversion
return celsius_to_fahrenheit, fahrenheit_to_celsius, get_last_conversion
# Sử dụng
c_to_f, f_to_c, get_last = temperature_converter()
print(c_to_f(25)) # 77.0
print(get_last()) # 25°C = 77.0°F
print(f_to_c(98.6)) # 37.0
print(get_last()) # 98.6°F = 37.0°CTổng kết
-
Namespace: Không gian chứa các tên (biến, hàm, class) và giá trị của chúng
- Built-in, Global, Enclosing, Local
-
Scope: Phạm vi mà một namespace có thể được truy cập
- LEGB Rule: Local → Enclosing → Global → Built-in
-
Từ khóa quan trọng:
global: Thay đổi biến global từ trong hàmnonlocal: Thay đổi biến của hàm bên ngoài (enclosing)
-
Best Practices:
- ✅ Hạn chế dùng biến global
- ✅ Dùng tham số và return thay vì global
- ✅ Không ghi đè built-in functions/variables
- ✅ Sử dụng closure để encapsulation dữ liệu
Python