Bad Practices¶
Mental Model
Every bad naming practice boils down to one mistake: choosing a name that collides with something Python already uses. Shadowing list, type, or id with your own variable hides the built-in silently and causes confusing errors later. If your editor highlights a name as a built-in, pick a different name.
Shadowing Built-ins¶
1. Common Mistakes¶
```python
Really bad!¶
print(sorted([3, 1, 2])) sorted = 1 # Shadows built-in!
Later...¶
sorted([3, 1, 2]) # TypeError!¶
```
2. Recovery¶
```python
Once shadowed¶
list = [1, 2, 3]
Recover¶
del list new_list = list(range(5)) # Works ```
3. Don't Shadow¶
```python
Never shadow:¶
list, dict, set, tuple¶
str, int, float¶
print, input¶
len, range¶
sum, min, max¶
sorted, filter, map¶
type, id¶
```
Function Shadowing¶
1. Example¶
```python def f(): return 1
f = 100 # Shadows function!
f() # TypeError!¶
```
2. Namespace Pollution¶
```python
Bad¶
def count(): return 42
count = count() # Now int!
count() # TypeError!¶
```
Misleading Names¶
1. Wrong Convention¶
```python
Bad: looks constant¶
MAX_SIZE = [1, 2, 3] # Mutable!
Better¶
max_size = [1, 2, 3] MAX_SIZE = 100 # Constant ```
2. Name vs Content¶
```python
Bad¶
count = "not a count" total = [1, 2, 3]
Better¶
label = "not a count" numbers = [1, 2, 3] ```
Single Letter Issues¶
1. Avoid Confusion¶
```python
Bad: l looks like 1¶
l = 1 # Don't use O = 0 # Don't use I = 1 # Don't use
Better¶
length = 1 offset = 0 index = 1 ```
Prevention¶
1. Check First¶
```python import keyword import builtins
def is_safe_name(name): if keyword.iskeyword(name): return False if hasattr(builtins, name): return False return name.isidentifier()
print(is_safe_name("user")) # True print(is_safe_name("list")) # False ```
2. Use Linters¶
Tools that catch shadowing:
- pylint
- flake8
- pycodestyle
Exercises¶
Exercise 1. Identify three naming problems in the following code and fix them.
python
l = [1, 2, 3]
str = "hello"
def f(x):
O = x + 1
return O
Solution to Exercise 1
```python
# Fixed version
numbers = [1, 2, 3] # 'l' looks like '1'
greeting = "hello" # 'str' shadows built-in
def increment(value): # 'f' is not descriptive
result = value + 1 # 'O' looks like '0'
return result
```
Avoid single-letter names that look like digits (l, O), shadowing built-ins (str), and non-descriptive function names (f).
Exercise 2.
Explain why using list, dict, str, type, or id as variable names is dangerous. Write a code example that breaks because of shadowing a built-in.
Solution to Exercise 2
```python
list = [1, 2, 3]
try:
new_list = list("hello")
except TypeError as e:
print(f"Error: {e}") # 'list' object is not callable
del list # Restore built-in
print(list("hello")) # ['h', 'e', 'l', 'l', 'o']
```
Shadowing built-ins makes them inaccessible in the current scope, causing confusing errors.
Exercise 3. Rewrite the following code with descriptive variable names.
python
def p(d, r, t):
return d * (1 + r) ** t
Solution to Exercise 3
```python
def compound_interest(principal, annual_rate, years):
return principal * (1 + annual_rate) ** years
print(compound_interest(1000, 0.05, 10)) # 1628.89...
```
Descriptive names make the formula self-documenting without needing comments.