Python Keywords & Identifiers -- `list` Shadowing Crash
A variable named list triggered TypeError: 'list' object is not callable in production.
- Python keywords are reserved words with fixed meaning — you cannot use them as variable names
- Identifiers are names you create — they must start with a letter or underscore, contain only letters/digits/underscores
- Python 3.12 has exactly 35 keywords; check with
keyword.kwlist - The three capitalized keywords are True, False, None — all others are lowercase
- Overwriting a built-in like
listorprintis not a keyword violation but causes silent runtime bugs
Every language has a vocabulary. English has words like 'the', 'is', and 'if' that carry fixed grammatical meaning — you can't just decide 'if' now means a type of sandwich. Python works the same way. It has a built-in vocabulary of reserved words that power every program ever written in the language, and the moment you open a Python file, those rules are already in force whether you know about them or not. Understanding them isn't optional trivia — it's the foundation everything else is built on.
The problem most beginners hit is that Python's error messages when you misuse keywords are genuinely confusing at first. You try to name a variable 'list' or 'print' and something breaks in a way that doesn't obviously point to a naming problem. Knowing the rules up front means you spend your time actually building things rather than puzzling over cryptic SyntaxError messages at 11 pm.
By the end of this article you'll know every Python keyword by category, you'll be able to write identifiers that are both legal and professional, you'll understand exactly why Python enforces these rules, and you'll be able to spot and fix the three most common beginner naming mistakes on sight. Let's build this up from zero.
What Python Keywords Actually Are — and Why You Can't Touch Them
A Python keyword is a word that is permanently reserved by the language itself. Python's interpreter reads your code word by word, and when it hits a keyword, it doesn't ask what you meant — it already knows. Keywords are the grammar of Python. They're the skeleton that holds every statement together.
Python 3 currently has 35 keywords. Every single one of them serves a specific structural purpose. 'if' starts a condition. 'for' starts a loop. 'def' starts a function. 'True' and 'False' are the only two boolean values. 'None' represents the absence of a value. None of these can be reassigned, overwritten, or used as variable names.
You can see the complete list at any time by running two lines of Python. The 'keyword' module is part of Python's standard library — it ships with Python, no installation needed — and 'keyword.kwlist' gives you the full list in alphabetical order. This is worth memorising not because an interviewer will quiz you on all 35, but because recognising them on sight stops you accidentally walking into a naming collision.
Notice that all 35 keywords are lowercase except 'True', 'False', and 'None'. That capitalisation isn't a style choice — it's part of the specification. Python is case-sensitive, so 'true' (all lowercase) is not a keyword and can technically be used as a variable name, though doing so is a terrible idea for readability.
Python Identifiers — The Naming Rules You Must Know Cold
An identifier is any name you create yourself — variable names, function names, class names, module names. You have freedom here, but Python enforces a firm set of rules. Break any one of them and you get a SyntaxError before your code even runs.
The rules are: (1) An identifier can only contain letters (a–z, A–Z), digits (0–9), and underscores (_). (2) It must not start with a digit — 'player1' is legal, '1player' is not. (3) It must not be a keyword. (4) It cannot contain spaces or special characters like @, $, %, !, or hyphens.
Python is case-sensitive. 'Score', 'score', and 'SCORE' are three completely different identifiers. This catches a lot of beginners who accidentally mix cases when referencing a variable they defined earlier.
Beyond the hard rules, the Python community follows PEP 8 — the official Python style guide. PEP 8 says: use lowercase_with_underscores for variables and functions ('player_score', not 'playerScore'), use CapitalisedWords for class names ('GamePlayer', not 'game_player'), and use ALL_CAPS_WITH_UNDERSCORES for constants ('MAX_SPEED = 300'). These aren't enforced by the interpreter, but every professional Python codebase follows them, and code reviewers will notice immediately if you don't.
Underscores carry special meaning too. A single leading underscore like '_internal_counter' signals to other developers that this is intended for internal use only. A double leading underscore like '__player_id' triggers Python's name mangling inside classes. And '__dunder__' names (double underscore on both sides) are Python's special method names like '__init__' and '__str__'.
Keywords by Category — Understanding What Each Group Actually Does
Staring at 35 keywords in alphabetical order is overwhelming. Group them by what they do and the list becomes far more manageable — and far more meaningful.
The value keywords are the simplest: 'True', 'False', and 'None'. These are Python's only built-in literal constants. You'll use all three constantly.
The control-flow keywords — 'if', 'elif', 'else', 'for', 'while', 'break', 'continue', 'pass' — control the direction your code takes. Think of these as the signposts and junctions on a road.
The function and class keywords — 'def', 'return', 'lambda', 'class', 'yield' — are how you define reusable code blocks. 'lambda' creates a tiny one-liner function. 'yield' turns a function into a generator.
The error-handling keywords — 'try', 'except', 'finally', 'raise', 'assert' — are how Python deals with things going wrong. You'll reach for these the moment your programs start handling user input or file operations.
The import keywords — 'import', 'from', 'as' — bring external code into your file. 'as' lets you rename something on import, like 'import numpy as np'.
The scope keywords — 'global', 'nonlocal' — tell Python where a variable lives. The logical operators — 'and', 'or', 'not', 'in', 'is' — build conditions. And 'with', 'del', 'async', 'await' handle context management, deletion, and asynchronous programming respectively.
The Silent Danger: Shadowing Built-in Names and Module Names
You now know that keywords like for and if are reserved — you can't use them as variable names. But there's a second, more dangerous category: built-in names like list, str, int, print, len, type, open, and input. These are NOT keywords. keyword.iskeyword('list') returns False. Python lets you assign to them without complaint.
That's the trap. The code runs. No SyntaxError. But somewhere else in your program, something that relied on list(...) or print(...) now breaks with a cryptic error.
Shadowing happens when you use a built-in name as your own identifier in a local scope. If you write list = [1, 2, 3] inside a function, then anywhere inside that function, calling will fail with list()TypeError: 'list' object is not callable. The built-in function is gone, replaced by your list.
The same applies to module names — don't name a file math.py or json.py, because when another module tries import math, Python finds your file first.
The fix is simple: use descriptive, specific names. Instead of list, use item_list or product_ids. Instead of str, use name_str or just name. Add a linting tool that flags shadowed built-in names: flake8-builtins or PyLint's builtin-attribute-shadowing rule.
Special Identifiers: Underscore Conventions and Name Mangling
Beyond the hard rules, certain identifier patterns carry special meaning in Python. Understanding them is the difference between writing code that works and writing code that other experienced Python developers can read and maintain.
_single_leading_underscore: This is a convention, not enforced by Python. When you see _helper_function, it means 'this is internal to the module or class — don't use it from outside unless you know what you're doing'. The interpreter doesn't prevent access; it's a signal to other developers.
__double_leading_underscore: This triggers name mangling inside classes. Python renames the attribute to _ClassName__attribute. It exists to avoid naming conflicts in subclasses, not to implement private access. If you define __secret in a class, subclasses won't accidentally override it.
__dunder__ (double underscore both sides): These are Python's special method names, also called 'magic methods' or 'dunder methods'. You've seen __init__ (constructor), __str__ (string representation), __repr__, __len__, __eq__, and many more. Never invent your own dunder names — those are reserved by the language for future use.
Single underscore `_` as a name: Python programmers use _ as a throwaway variable name in loops or unpacking. For example, for _ in range(10): or _, y = point. It tells anyone reading your code 'I don't need this value'.
| Aspect | Keywords | Identifiers |
|---|---|---|
| Who defines them? | Python itself — built into the language | You — the programmer decides the name |
| Can you change their meaning? | No — fixed forever, SyntaxError if misused | Yes — you define what they hold or do |
| Total count | Exactly 35 in Python 3.12 | Unlimited — as many as your program needs |
| Case sensitivity | Case matters: True ≠ true (true is NOT a keyword) | Case matters: score ≠ Score ≠ SCORE |
| Can start with a digit? | N/A — fixed names set by Python | No — '1score' is a SyntaxError |
| Can contain hyphens? | N/A | No — 'player-score' is a SyntaxError; use 'player_score' |
| PEP 8 convention | Already follow the spec — no choice | snake_case for vars/functions, PascalCase for classes, ALL_CAPS for constants |
| Checked at runtime? | No — checked at parse time (before code runs) | Partially — undefined identifiers raise NameError at runtime |
| Tool to inspect them | keyword.kwlist / keyword.iskeyword() | dir() shows all names in current scope |
Key Takeaways
- Python has exactly 35 keywords — they are owned by the language, never by you. Use 'keyword.iskeyword()' to check any word you're unsure about before using it as a name.
- Identifiers follow four hard rules: letters/digits/underscores only, can't start with a digit, can't be a keyword, no spaces or special characters. Break any one rule and Python won't even start running your code.
- Python is strictly case-sensitive in both keywords and identifiers — 'while' is a keyword, 'While' is a valid (but terrible) variable name; 'player_score' and 'Player_Score' are two completely separate variables.
- Built-ins like 'list', 'print', 'str', and 'input' are NOT keywords but shadowing them by using them as variable names causes silent, hard-to-debug runtime failures — treat them as if they were reserved.
- Underscore conventions matter:
_singlemeans 'internal use',__doubletriggers name mangling,__dunder__is for Python's special methods only.
Common Mistakes to Avoid
- Using a built-in name like 'list', 'input', 'print', or 'str' as a variable name
Symptom: Your code silently stops working or throws 'TypeError: 'list' object is not callable'. The error appears in a completely different part of the code, making it hard to trace back to the variable assignment.
Fix: Rename your variable to something descriptive like 'player_list' or 'score_list'. Add 'flake8-builtins' to your project's linter configuration to catch these automatically. - Using hyphens in variable names instead of underscores
Symptom: SyntaxError on a line like 'player-score = 100'. Python interprets the hyphen as a minus operator, so it tries to evaluate 'player minus score = 100', which makes no sense.
Fix: Always use underscores: 'player_score = 100'. If you're coming from CSS or HTML, retrain your muscle memory — Python only accepts underscores. - Assuming Python keywords are case-insensitive
Symptom: Using 'While', 'IF', or 'TRUE' expecting them to work like keywords — 'While True:' raises a SyntaxError because 'While' with a capital W is not a keyword; only 'while' (lowercase) is. The three exceptions are 'True', 'False', and 'None' which must be capitalised exactly as written.
Fix: Always type keywords in lowercase except for those three — your code editor's syntax highlighting will confirm whether you've got it right. - Using lowercase 'true', 'false', or 'none' as variable names
Symptom: These are not keywords — Python accepts them as variable names. But other developers will assume you made a typo, and your code will look amateurish. Worse, if you later try to use `True` (uppercase) in the same scope, you'll have two different values causing logical errors.
Fix: Use the correct capitalisation for boolean constants and None. If you accidentally used lowercase, rename the variable immediately —True,False,Noneare the only valid forms.
Interview Questions on This Topic
- QCan you name five Python keywords and explain what each one does?JuniorReveal
- QWhat is the difference between a keyword and a built-in in Python?Mid-levelReveal
- QWhy does Python use 'is None' rather than '== None' when checking for None values?SeniorReveal
- QWhat happens if you rename a variable to 'True' (uppercase T) in a Python program?JuniorReveal
Frequently Asked Questions
How many keywords does Python have?
Python 3.12 has exactly 35 keywords. This number has changed across Python versions — Python 3.5 added 'async' and 'await', for example. You can always get the exact count for your version by running 'import keyword; print(len(keyword.kwlist))' in your Python environment.
Is 'None' a keyword in Python?
Yes, 'None' is one of Python's 35 keywords — and it must be written with a capital N. It represents the complete absence of a value, similar to 'null' in other languages. 'none' (all lowercase) is not a keyword and could technically be used as a variable name, though doing so is a recipe for confusion.
What is the difference between a Python keyword and an identifier?
A keyword is a word with a fixed, built-in meaning that Python's interpreter recognises before your code even runs — you cannot use keywords as variable names. An identifier is a name you choose for your own variables, functions, and classes — it follows Python's naming rules but its meaning is entirely up to you. Keywords are the language's vocabulary; identifiers are your vocabulary inside that language.
Can I use 'print' as a variable name in Python?
Yes, technically — 'print' is not a keyword (check with keyword.iskeyword('print') -> False). You CAN assign print = 42 without a SyntaxError. But doing so shadows the built-in function, and any later call to print()print(...) in that scope will raise TypeError: 'int' object is not callable. Never use built-in names as identifiers.
What does a syntax error for an invalid identifier look like?
Run 1player = 5 — you'll get SyntaxError: invalid decimal literal. For a hyphen: player-score = 10 gives SyntaxError: cannot assign to operator here. Maybe you meant '==' instead of '='?. For a keyword: for = 2 gives SyntaxError: cannot assign to for. The message varies but always points to the line where the parser got confused.
That's Python Basics. Mark it forged?
6 min read · try the examples if you haven't