Python is praised for its readability, but that doesn't mean every Python code is clean. Over years of code review, I've identified patterns that separate messy scripts from maintainable systems. Here are seven actionable habits to level up your Python.
π§Ή 1. Embrace Explicit Over Implicit
Python's dynamic typing is powerful, but it can lead to confusion. Use type hints to document your codeβthey're free documentation.
Bad:
def process(data):
return [x * 2 for x in data]
Good:
def process(data: list[float]) -> list[float]:
return [x * 2 for x in data]
Type hints don't enforce types at runtime, but tools like mypy catch bugs early. Your future self (and teammates) will thank you.
π 2. Context Managers for Resource Safety
Forgetting to close files or locks is a classic bug. Use with statements to guarantee cleanup.
Avoid:
f = open('file.txt', 'r')
data = f.read()
f.close()
Preferred:
with open('file.txt', 'r') as f:
data = f.read()
Even better, use contextlib.contextmanager for your own objects.
π¦ 3. Write Functions, Not Scripts
Long scripts are hard to test. Break logic into single-purpose functions with clear inputs/outputs.
Anti-pattern:
data = []
with open('input.csv') as f:
for line in f:
data.append(line.strip())
processed = [process(row) for row in data]
with open('output.csv', 'w') as f:
for row in processed:
f.write(row + '\n')
Refactored:
def read_csv(path: str) -> list[str]:
with open(path) as f:
return [line.strip() for line in f]
def write_csv(path: str, rows: list[str]):
with open(path, 'w') as f:
f.writelines([row + '\n' for row in rows])
def main():
data = read_csv('input.csv')
processed = [process(row) for row in data]
write_csv('output.csv', processed)
π§ͺ 4. Use f-strings, Not % or .format()
f-strings are faster, cleaner, and harder to mess up.
Old ways:
name = "Alice"
print("Hello, %s" % name)
print("Hello, {}".format(name))
Modern:
print(f"Hello, {name}")
You can even evaluate expressions inside {}.
π 5. Leverage Comprehensions and Generators
List comprehensions are more Pythonic and often faster than manual loops. For large data, use generator expressions.
Loop:
squares = []
for i in range(10):
squares.append(i * i)
Comprehension:
squares = [i * i for i in range(10)]
Generator for memory efficiency:
squares_gen = (i * i for i in range(10))
π§© 6. Stick to the Standard Library First
Before installing a new package, check if Python's built-in modules can do the job. itertools, collections, functools, pathlib, and datetime are gold mines.
Example with pathlib:
from pathlib import Path
p = Path('data/output.txt')
p.parent.mkdir(parents=True, exist_ok=True)
p.write_text('Hello')
No more os.path.join spaghetti.
π§ 7. Think About Performance Early
Premature optimization is the root of all evil, but basic awareness helps. Use timeit to profile small snippets.
import timeit
# Compare list concatenation vs extend
print(timeit.timeit('a + b', globals={'a': [1]*1000, 'b': [2]*1000}))
print(timeit.timeit('a.extend(b)', globals={'a': [1]*1000, 'b': [2]*1000}))
Also, prefer join for strings:
# Good
result = ''.join(list_of_strings)
π Your Turn!
These habits will make your Python cleaner, safer, and faster. Which one will you adopt today? Drop a comment with your favorite Python trickβI read every reply. And if you found this helpful, share it with a friend who's still using for i in range(len(list)). Happy coding!
π§ Want free AI tools? Check out AI Toolbox β text improver, translator, code generator, and more. No signup needed.
Top comments (0)