Các hằng số được khai báo sẵn trong Python: Sự kỳ lạ đằng sau cú pháp và hành vi

25 tháng 8, 2026·4 phút đọc

Bài viết phân tích chi tiết về 6 hằng số được khai báo sẵn trong Python (True, False, None, __debug__, Ellipsis, NotImplemented), chỉ ra những khác biệt về cú pháp và hành vi khiến chúng trở thành những trường hợp đặc biệt độc đáo trong ngôn ngữ. Từ việc là token từ vựng riêng biệt đến khả năng gán đè qua builtins, tác giả hé lộ những thiết kế tưởng như 'kỳ quặc' nhưng lại phản ánh triết lý và lịch sử phát triển của Python.

Các hằng số được khai báo sẵn trong Python: Sự kỳ lạ đằng sau cú pháp và hành vi

Python sở hữu sáu hằng số được khai báo sẵn: True, False, None, debug, Ellipsis (hoặc tương đương là ...) và NotImplemented. Tuy nhiên, điều thú vị là chúng không hoạt động giống nhau, mỗi hằng số lại có những quy tắc riêng biệt về cú pháp và khả năng gán giá trị, tạo nên một mê cung khó hiểu đối với lập trình viên.

Bài viết này sẽ đi sâu vào từng hằng số, lý giải vì sao chúng lại được thiết kế khác biệt, đồng thời nhấn mạnh những trường hợp đặc biệt khiến ngay cả các lập trình viên kỳ cựu cũng phải bối rối.

True, False, và None: Không phải là định danh thông thường

Điểm đầu tiên cần nhấn mạnh: True, FalseNone là các từ khóa (keywords). Chúng không phải là định danh (identifiers), mà là các token từ vựng riêng biệt, được xử lý ngay tại bộ phân tích từ vựng (lexer) chứ không phải trong quá trình phân giải tên (name resolution) như các biến thông thường.

Hệ quả thú vị của thiết kế này là các biểu thức như x.True sẽ ngay lập tức gây ra SyntaxError. Điều này khiến nhiều lập trình viên đặt câu hỏi về lý do đằng sau quyết định này, và liệu có một rationale cụ thể nào không.

debug: Hằng số đặc biệt duy nhất không thể gán giá trị

debug là một hằng số boolean, thường có giá trị True khi chạy bình thường và False khi sử dụng tham số -O (optimized mode). Mục đích của nó tương tự như cách assert bị vô hiệu hóa trong các bản build không gỡ lỗi – bạn có thể bọc code trong if __debug__ để kiểm tra điều kiện đắt đỏ trong bản "tối ưu".

Điểm kỳ lạ là dù là một định danh bình thường, __debug__ lại là định danh duy nhất trong Python không thể gán giá trị (assignment). Thử chạy __debug__ = 67 sẽ nhận được SyntaxError: cannot assign to __debug__. Ngay cả việc gán qua thuộc tính như x.__debug__ = 67 cũng bất khả thi. Đây là một trường hợp đặc biệt thực sự.

Tuy nhiên, vì không phải là từ khóa, __debug__ vẫn có sự khác biệt: ví dụ x.__debug__ sẽ gây AttributeError (vì chỉ là truy cập thuộc tính không tồn tại) thay vì SyntaxError.

Một vòng tránh: SyntaxError không thực sự là lỗi cú pháp

Một điều thú vị khác là việc gán giá trị cho __debug__ là một trong số ít trường hợp gây SyntaxError dù code không thực sự sai cú pháp. Lập trình viên có thể tự xác nhận điều này:

assert (__debug__ := 67)

Khi chạy ở chế độ debug, lệnh assert sẽ gây lỗi, nhưng với -O, assertion không được biên dịch và không có lỗi nào xảy ra. Các trường hợp tương tự khác là sử dụng yield hoặc await ngoài hàm.

Ellipsis và NotImplemented: Hằng số giả mạo

Khác với bốn hằng số trên, EllipsisNotImplemented được tài liệu hóa trong mục "constants" nhưng thực chất chỉ là các builtin thông thường, có thể bị che phủ (shadowed) bởi biến toàn cục:

NotImplemented = 67
NotImplemented  # 67

Người dùng có thể tự do gán giá trị mới cho chúng, điều này khác hẳn với các hằng số "thực" ở trên.

Ghi đè các hằng số: Khả năng 'gần như' vô hạn

Mặc dù là token từ vựng, True, False, và None vẫn tồn tại như các builtin thông thường:

import builtins
getattr(builtins, 'True')  # True

Điều bất ngờ là setattr cũng hoạt động!

setattr(builtins, 'True', 67)
getattr(builtins, 'True')  # 67
True  # vẫn là True, không bị ảnh hưởng!

__debug__ cũng có hành vi tương tự: bạn có thể thay đổi giá trị trong builtins nhưng hằng số vẫn giữ nguyên giá trị gốc. Riêng EllipsisNotImplemented lại không như vậy – chúng hoàn toàn có thể bị ghi đè bởi lệnh gán, dù ... luôn luôn là hằng số thực.

Lời kết

Sự khác biệt trong hành vi của sáu hằng số này có thể gây hoang mang, nhưng nó phản ánh lịch sử phát triển và triết lý thiết kế của Python. Dù có vẻ "kỳ quặc" ở thời điểm hiện tại, chúng vẫn là những mảnh ghép quan trọng trong bức tranh ngôn ngữ lập trình này, nhắc nhở chúng ta rằng ngay cả những chi tiết nhỏ cũng có thể ẩn chứa vô số điều thú vị để khám phá.

Chia sẻ:FacebookX
Nội dung tổng hợp bằng AI, mang tính tham khảo. Xem bài gốc ↗