Most Python tip collections end with “here’s how to do it in one line.” While the code gets shorter, it often becomes unreadable for the next developer.
This article filters tips by two strict criteria: making code shorter without hurting readability, and actually speeding things up as data scales. If a tip didn’t meet both, it was left out.
Solving Problems with Data Structures (5 tips)
1. Use Sets for Membership Tests
# 전: 리스트를 매번 처음부터 훑는다
valid_ids = [1, 5, 9, 12, ...] # 1만 개
for row in rows: # 10만 행
if row.id in valid_ids: ...
# 후
valid_ids = {1, 5, 9, 12, ...}
for row in rows:
if row.id in valid_ids: ...
A list’s in operator compares elements one by one, whereas a set uses hashing for O(1) lookups. The performance gap widens dramatically as the dataset grows. This is the single most impactful tip in this article.
2. Use Dictionaries for Matching Pairs — Nested loops used to match elements across two lists can usually be replaced with a single dictionary lookup.
# 전
for order in orders:
for user in users:
if user.id == order.user_id: ...
# 후
user_by_id = {u.id: u for u in users}
for order in orders:
user = user_by_id.get(order.user_id)
3. Count Elements with Counter
from collections import Counter
counts = Counter(words)
counts.most_common(10)
4. Handle Missing Keys with defaultdict
from collections import defaultdict
groups = defaultdict(list)
for item in items:
groups[item.category].append(item) # 키 존재 확인 불필요
5. Use dataclass for Data-Only Classes
from dataclasses import dataclass
@dataclass
class User:
id: int
name: str
email: str = ""
This automatically generates __init__, __repr__, and __eq__.
Reducing Loops (5 tips)
6. Comprehensions — Turn the “create-and-append” pattern into a single line.
names = [u.name for u in users if u.active]
7. enumerate — Avoid manual counter variables when you need index tracking.
for i, line in enumerate(lines, start=1): ...
8. zip — Iterate over multiple lists in parallel.
for name, score in zip(names, scores): ...
9. any / all — Condense conditional loops into a single line. Plus, they short-circuit immediately once the condition is met.
if any(u.is_admin for u in users): ...
10. dict.get and setdefault — Eliminate conditional branching for key existence checks.
Let’s also draw a clear line on where readability degrades. If a comprehension has multiple conditions or nested loops, a standard loop is much better. Shorter isn’t always better; code is good when it can be understood in a single glance.
Files, Paths, and Strings (5 tips)
11. pathlib — Stop manipulating paths as raw strings.
from pathlib import Path
p = Path("data") / "2026" / "log.txt"
p.write_text("hello", encoding="utf-8")
12. Always Explicitly Specify Encoding — Most encoding issues stem from omitting this. Since default encodings vary by operating system, code that works perfectly on your local machine might break on the server.
open("f.csv", encoding="utf-8") # 항상 붙인다
open("f.csv", encoding="utf-8-sig") # 엑셀이 만든 CSV의 BOM 처리
13. with Statements — Always open files this way. It guarantees they close properly even if an exception occurs.
14. f-strings — You can also format values directly inside them.
f"{value:,.2f}" # 1,234.57
f"{name:<10}" # 왼쪽 정렬
f"{obj=}" # obj=<값> (디버깅용)
15. Use join for String Concatenation
# 전: 반복마다 새 문자열이 만들어진다
s = ""
for x in items: s += str(x)
# 후
s = "".join(str(x) for x in items)
Optimizations That Actually Speed Things Up (5 tips)
16. Save Memory with Generators — Use them when you don’t need to load everything into memory at once.
# 전: 파일 전체를 메모리에
lines = open("big.log", encoding="utf-8").readlines()
# 후: 한 줄씩 흘려보낸다
with open("big.log", encoding="utf-8") as f:
for line in f: ...
17. Hoist Calculations Out of Loops — Move expressions that evaluate to the same value outside the loop.
# 전
for x in items:
if x in set(valid): # 매 반복마다 집합을 새로 만든다
...
# 후
valid_set = set(valid)
for x in items:
if x in valid_set: ...
18. Prioritize Built-in Functions and the Standard Library — Functions like sum, max, sorted, and modules like itertools are implemented in C, making them significantly faster than writing equivalent loops in pure Python.
19. functools.lru_cache — Use this for pure functions that are repeatedly called with the same arguments.
from functools import lru_cache
@lru_cache(maxsize=None)
def expensive(n): ...
20. Measure Before You Optimize — This is the final and most important tip.
import cProfile
cProfile.run("main()")
The parts you assume are slow are usually different from the parts that actually are. Running a profiler once is worth more than ten optimization tips.
Optimizations to Avoid
- One-liners that sacrifice readability. Nested comprehensions, excessive lambdas, and nested ternary operators might be short, but they are costly to maintain.
- Premature optimization. Most execution time is spent in a tiny fraction of the codebase. Tuning everything without measuring is a waste of time.
- Writing CPU-heavy tasks in pure Python. Leave heavy numerical computations to libraries like NumPy. Pure Python loops simply cannot compete with optimized C extensions.
Frequently Asked Questions
Which Python version is this based on?
Most tips in this article can be used as-is in Python 3.8 or higher. dataclass was introduced in 3.7, and the f-string f"{obj=}" syntax was added in 3.8. For new projects, using the latest supported stable version is highly recommended for both performance and security benefits.
Does it really make a noticeable speed difference?
It depends on the tip. Switching data structures is an algorithmic improvement where the performance gap widens as data grows, while string join or hoisting calculations out of loops scales with the iteration count. Other tips primarily focus on improving readability. To see how much of a difference they make in your specific codebase, measure it yourself using timeit or cProfile.
Can beginners start using these right away?
We recommend a step-by-step approach. First, get comfortable with data structures (Tips 1–5) and files/encoding (Tips 11–15). They will immediately help you prevent bugs. It’s better to move on to comprehensions and generators after you are fully comfortable with basic loops. Using them without understanding how they work under the hood can make debugging difficult.

Leave a Reply