None Type
None là một giá trị đặc biệt trong Python đại diện cho “không có giá trị” hoặc “giá trị rỗng”. Nó là một object duy nhất thuộc kiểu NoneType.
1. Giới thiệu về None
Phần tiêu đề “1. Giới thiệu về None”Định nghĩa
Phần tiêu đề “Định nghĩa”None là một constant đặc biệt trong Python:
- Đại diện cho sự vắng mặt của giá trị
- Là singleton - chỉ có một instance duy nhất trong Python
- Thuộc kiểu dữ liệu
NoneType
# Tạo biến với giá trị Noneresult = Noneprint(result) # Noneprint(type(result)) # <class 'NoneType'>
# None là singleton - chỉ có 1 instancea = Noneb = Noneprint(a is b) # True (cùng object trong bộ nhớ)None vs 0, False, “” (chuỗi rỗng)
Phần tiêu đề “None vs 0, False, “” (chuỗi rỗng)”# None khác với 0print(None == 0) # Falseprint(None is 0) # False
# None khác với Falseprint(None == False) # Falseprint(None is False) # False
# None khác với chuỗi rỗngprint(None == "") # Falseprint(None is "") # False
# None khác với list rỗngprint(None == []) # False
# Nhưng None là falsy valueprint(bool(None)) # False2. Khi nào sử dụng None?
Phần tiêu đề “2. Khi nào sử dụng None?”Giá trị mặc định cho tham số hàm
Phần tiêu đề “Giá trị mặc định cho tham số hàm”def greet(name=None): if name is None: print("Hello, Guest!") else: print(f"Hello, {name}!")
greet() # Hello, Guest!greet("Alice") # Hello, Alice!
# Ứng dụng thực tế: tham số tùy chọndef create_user(username, email=None, phone=None): user = {"username": username} if email is not None: user["email"] = email if phone is not None: user["phone"] = phone return user
print(create_user("john"))# {'username': 'john'}
# {'username': 'alice', 'email': '[email protected]'}
# {'username': 'bob', 'email': '[email protected]', 'phone': '123-456'}Hàm không có return statement
Phần tiêu đề “Hàm không có return statement”def print_message(msg): print(msg) # Không có return statement
result = print_message("Hello")print(result) # None
# Các hàm chỉ có return (không có giá trị) cũng trả về Nonedef early_return(x): if x < 0: return # Tương đương return None return x * 2
print(early_return(-5)) # Noneprint(early_return(5)) # 10Khởi tạo biến chưa có giá trị
Phần tiêu đề “Khởi tạo biến chưa có giá trị”# Khởi tạo biến sẽ gán sauresult = None
# Logic xử lýif some_condition: result = calculate_something()else: result = calculate_other_thing()
# Kiểm tra biến chưa được gánuser_input = None
while user_input is None: user_input = input("Nhập tên (không để trống): ").strip() if not user_input: user_input = None print("Tên không được để trống!")
print(f"Xin chào, {user_input}!")Đánh dấu không tìm thấy kết quả
Phần tiêu đề “Đánh dấu không tìm thấy kết quả”def find_user(user_id, users): """Tìm user theo ID, trả về None nếu không tìm thấy""" for user in users: if user['id'] == user_id: return user return None # Không tìm thấy
users = [ {'id': 1, 'name': 'Alice'}, {'id': 2, 'name': 'Bob'}]
user = find_user(1, users)if user is not None: print(f"Found: {user['name']}")else: print("User not found")
user = find_user(999, users)if user is None: print("User not found") # In ra dòng này3. Kiểm tra None
Phần tiêu đề “3. Kiểm tra None”Sử dụng ‘is’ và ‘is not’ (KHUYẾN KHÍCH)
Phần tiêu đề “Sử dụng ‘is’ và ‘is not’ (KHUYẾN KHÍCH)”# ✅ ĐÚNG: Dùng 'is' để kiểm tra Nonevalue = None
if value is None: print("Value is None")
if value is not None: print("Value has a value")else: print("Value is None") # In ra dòng nàyTại sao không nên dùng == với None?
Phần tiêu đề “Tại sao không nên dùng == với None?”# ❌ KHÔNG KHUYẾN KHÍCH: Dùng ==value = None
if value == None: # Hoạt động nhưng không được khuyến khích print("Value is None")
# ✅ NÊN DÙNG: isif value is None: print("Value is None")
# Lý do:# - 'is' kiểm tra identity (cùng object)# - '==' kiểm tra equality (giá trị bằng nhau)# - None là singleton, nên dùng 'is' chính xác và nhanh hơnNone trong điều kiện boolean
Phần tiêu đề “None trong điều kiện boolean”# None là falsy valuevalue = None
# Cách 1: Kiểm tra trực tiếpif not value: print("Value is None or falsy")
# Cách 2: Kiểm tra rõ ràng (TỐT HƠN)if value is None: print("Value is definitely None")
# Vấn đề khi dùng not:numbers = [] # List rỗng
# ❌ Không chính xácif not numbers: print("numbers is None") # KHÔNG ĐÚNG - numbers là [], không phải None
# ✅ Chính xácif numbers is None: print("numbers is None")else: print("numbers is not None, but may be empty") # Đúng4. None với Collections
Phần tiêu đề “4. None với Collections”None trong List
Phần tiêu đề “None trong List”# List chứa Noneitems = [1, None, 3, None, 5]print(items) # [1, None, 3, None, 5]
# Đếm số lượng Nonecount_none = items.count(None)print(count_none) # 2
# Lọc None ra khỏi listfiltered = [x for x in items if x is not None]print(filtered) # [1, 3, 5]
# Thay thế None bằng giá trị khácreplaced = [x if x is not None else 0 for x in items]print(replaced) # [1, 0, 3, 0, 5]None trong Dictionary
Phần tiêu đề “None trong Dictionary”# Dictionary với giá trị Noneuser = { 'name': 'John', 'email': None, 'phone': None}
# Lọc các key có giá trị Noneactive_fields = {k: v for k, v in user.items() if v is not None}print(active_fields) # {'name': 'John'}
# Phương thức get() trả về None nếu key không tồn tạiuser = {'name': 'Alice'}email = user.get('email')print(email) # None
# get() với giá trị mặc địnhNone vs Missing Key
Phần tiêu đề “None vs Missing Key”data = { 'a': 1, 'b': None, # 'c' không tồn tại}
# Kiểm tra key tồn tạiprint('a' in data) # Trueprint('b' in data) # True (tồn tại nhưng giá trị None)print('c' in data) # False (không tồn tại)
# Phân biệt None và missing keyif 'b' in data: if data['b'] is None: print("Key 'b' exists but value is None")
if 'c' in data: print("Key 'c' exists")else: print("Key 'c' does not exist")5. None với Functions
Phần tiêu đề “5. None với Functions”Hàm trả về None ngầm định
Phần tiêu đề “Hàm trả về None ngầm định”def no_return(): x = 5 + 5
result = no_return()print(result) # None
# Các hàm built-in cũng có thể trả về Nonenumbers = [3, 1, 2]result = numbers.sort() # sort() sắp xếp in-place, không return gìprint(result) # Noneprint(numbers) # [1, 2, 3] (đã được sắp xếp)Pattern: Optional Return Value
Phần tiêu đề “Pattern: Optional Return Value”def divide(a, b): """Chia a cho b, trả về None nếu b = 0""" if b == 0: return None return a / b
# Sử dụngresult = divide(10, 2)if result is not None: print(f"Result: {result}") # Result: 5.0
result = divide(10, 0)if result is None: print("Cannot divide by zero") # In ra dòng nàyĐối số mặc định mutable - Cẩn thận!
Phần tiêu đề “Đối số mặc định mutable - Cẩn thận!”# ❌ NGUY HIỂM: Dùng list làm giá trị mặc địnhdef add_item(item, items=[]): # KHÔNG NÊN items.append(item) return items
print(add_item(1)) # [1]print(add_item(2)) # [1, 2] - KHÔNG MONG MUỐN!print(add_item(3)) # [1, 2, 3] - KHÔNG MONG MUỐN!
# ✅ ĐÚNG: Dùng None và tạo mới bên trongdef add_item_correct(item, items=None): if items is None: items = [] items.append(item) return items
print(add_item_correct(1)) # [1]print(add_item_correct(2)) # [2] - ĐÚNG!print(add_item_correct(3)) # [3] - ĐÚNG!
# Truyền list sẵn cómy_list = [10, 20]print(add_item_correct(30, my_list)) # [10, 20, 30]6. Nullish Coalescing (Giá trị mặc định)
Phần tiêu đề “6. Nullish Coalescing (Giá trị mặc định)”Sử dụng ‘or’ operator
Phần tiêu đề “Sử dụng ‘or’ operator”# Cung cấp giá trị mặc định cho Nonename = Nonedisplay_name = name or "Guest"print(display_name) # Guest
# ⚠️ CẨN THẬN: 'or' kiểm tra falsy, không chỉ Noneage = 0display_age = age or 18print(display_age) # 18 (KHÔNG ĐÚNG - 0 cũng là falsy!)
# ✅ CHÍNH XÁC: Kiểm tra None cụ thểage = 0display_age = age if age is not None else 18print(display_age) # 0 (ĐÚNG)Pattern: Default Values
Phần tiêu đề “Pattern: Default Values”def get_config(config=None): """Trả về config hoặc giá trị mặc định""" default_config = { 'debug': False, 'timeout': 30, 'max_retries': 3 }
if config is None: return default_config
# Merge với default (override) return {**default_config, **config}
# Sử dụng mặc địnhprint(get_config())# {'debug': False, 'timeout': 30, 'max_retries': 3}
# Override một số giá trịprint(get_config({'debug': True, 'timeout': 60}))# {'debug': True, 'timeout': 60, 'max_retries': 3}7. None trong Class
Phần tiêu đề “7. None trong Class”Thuộc tính khởi tạo None
Phần tiêu đề “Thuộc tính khởi tạo None”class User: def __init__(self, username, email=None): self.username = username self.email = email self.phone = None # Sẽ set sau
def set_phone(self, phone): self.phone = phone
def get_contact_info(self): info = [self.username] if self.email is not None: info.append(f"Email: {self.email}") if self.phone is not None: info.append(f"Phone: {self.phone}") return ", ".join(info)
# Sử dụnguser1 = User("john")print(user1.get_contact_info()) # john
user2.set_phone("123-456-7890")print(user2.get_contact_info())# alice, Email: [email protected], Phone: 123-456-7890Optional Chain Pattern
Phần tiêu đề “Optional Chain Pattern”class Address: def __init__(self, street, city): self.street = street self.city = city
class Person: def __init__(self, name, address=None): self.name = name self.address = address
# Truy cập an toàn với Noneperson1 = Person("John")person2 = Person("Alice", Address("123 Main St", "NYC"))
# ❌ NGUY HIỂM: Không kiểm tra None# print(person1.address.city) # AttributeError
# ✅ AN TOÀN: Kiểm tra Noneif person1.address is not None: print(person1.address.city)else: print("No address") # In ra dòng này
# Với person2if person2.address is not None: print(person2.address.city) # NYC
# Python 3.10+: Match-casedef get_city(person): match person.address: case None: return "Unknown" case Address(city=city): return city
print(get_city(person1)) # Unknownprint(get_city(person2)) # NYC8. Best Practices
Phần tiêu đề “8. Best Practices”✅ NÊN làm
Phần tiêu đề “✅ NÊN làm”# 1. Dùng 'is None' để kiểm traif value is None: print("Value is None")
# 2. Dùng None cho tham số mặc định mutabledef create_list(items=None): if items is None: items = [] return items
# 3. Return None rõ ràng khi không tìm thấydef find_item(item_id): # ... if not found: return None return item
# 4. Sử dụng type hints (Python 3.5+)from typing import Optional
def get_user(user_id: int) -> Optional[dict]: # Có thể trả về dict hoặc None if user_exists(user_id): return {'id': user_id} return None❌ KHÔNG NÊN làm
Phần tiêu đề “❌ KHÔNG NÊN làm”# 1. Không dùng == để so sánh Noneif value == None: # KHÔNG TỐT pass
# 2. Không dùng list/dict làm default argumentdef bad_function(items=[]): # NGUY HIỂM pass
# 3. Không nhầm lẫn None với falsy valuesif not value: # CÓ THỂ SAI - value có thể là 0, [], "", False pass
# Tốt hơn:if value is None: pass9. Bài tập thực hành
Phần tiêu đề “9. Bài tập thực hành”Bài 1: Tìm kiếm an toàn
Phần tiêu đề “Bài 1: Tìm kiếm an toàn”def safe_get(data, *keys, default=None): """Lấy giá trị nested dictionary an toàn""" for key in keys: if data is None or not isinstance(data, dict): return default data = data.get(key) return data if data is not None else default
# Testuser = { 'name': 'John', 'address': { 'city': 'NYC', 'zipcode': '10001' }}
print(safe_get(user, 'name')) # Johnprint(safe_get(user, 'address', 'city')) # NYCprint(safe_get(user, 'address', 'country')) # Noneprint(safe_get(user, 'address', 'country', default='USA')) # USAprint(safe_get(user, 'phone', 'mobile')) # NoneBài 2: Filter None
Phần tiêu đề “Bài 2: Filter None”def remove_none(data): """Loại bỏ None khỏi nested structures""" if isinstance(data, dict): return {k: remove_none(v) for k, v in data.items() if v is not None} elif isinstance(data, list): return [remove_none(item) for item in data if item is not None] return data
# Testdata = { 'name': 'John', 'email': None, 'phones': ['123-456', None, '789-012'], 'address': { 'street': '123 Main', 'city': None, 'country': 'USA' }}
cleaned = remove_none(data)print(cleaned)# {'name': 'John', 'phones': ['123-456', '789-012'],# 'address': {'street': '123 Main', 'country': 'USA'}}Tổng kết
Phần tiêu đề “Tổng kết”Nonelà giá trị đặc biệt đại diện cho “không có giá trị”Nonelà singleton - chỉ có một instance duy nhất- Dùng
is Nonevàis not Noneđể kiểm tra (KHÔNG dùng==) Nonelà falsy value nhưng khác với0,False,"",[]- Sử dụng
Nonecho:- Giá trị mặc định của tham số
- Khởi tạo biến chưa có giá trị
- Đánh dấu không tìm thấy kết quả
- KHÔNG dùng mutable objects (list, dict) làm default argument - dùng
Nonethay thế - Type hint: Dùng
Optional[Type]để chỉ ra giá trị có thể là None