5 Python Tricks They Don't Teach in Beginner Tutorials
After years of writing Python, I realized most tutorials miss the tricks that actually matter day-to-day. Walrus operator, __slots__, dataclass — these are the ones I use most.
0xNN · · 6 min read
5 Python Tricks They Don't Teach in Beginner Tutorials
After years of writing Python, I realized something: most tutorials stop at for loops, functions, and classes - then leave you to drown in production code full of edge cases.
Here are five tricks I wish I'd known from the start.
---
1. Walrus Operator := - Assignments Inside Expressions
Introduced in Python 3.8. I still see people writing longer code that could be simplified.
Without walrus:
data = fetch_data()
if data:
process(data)
With walrus:
if (data := fetch_data()):
process(data)
Small difference. But when you have a chain of checks, it shines:
if (user := get_user(id)) and (profile := user.get("profile")) and (prefs := profile.get("preferences")):
apply_settings(prefs)
Two lines gone. Code stays readable. But don't force it - if walrus makes things harder to read, skip it.
2. slots - Memory-Efficient Classes
Python classes use a dictionary (dict) to store attributes by default. Convenient? Yes. Memory-efficient? Not at all - especially when creating thousands of instances.
Before:
class User:
def init(self, name, email):
self.name = name
self.email = email
After:
class User:
slots = ("name", "email")
def init(self, name, email):
self.name = name
self.email = email
With slots, Python uses a fixed tuple instead of a dict. This cuts memory usage by 50-60% for classes with many instances. Attribute access is also faster. The tradeoff: you can't add new attributes on the fly - but that's intentional discipline.
3. functools.lru_cache - One-Line Caching
Got a function called repeatedly with the same arguments? Slap this decorator on it.
from functools import lru_cache
@lru_cache(maxsize=128)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
Without lru_cache, fibonacci(40) takes millions of calls. With it - milliseconds. Any *pure* function (output depends only on inputs) can benefit. Set maxsize=None for unlimited cache.
4. dataclass - No More Boilerplate
Before 3.7, you wrote this all the time:
class Product:
def init(self, name, price, stock):
self.name = name
self.price = price
self.stock = stock
Now:
from dataclasses import dataclass
@dataclass
class Product:
name: str
price: float
stock: int = 0
init is automatic. You also get repr, eq, and hash for free. Add frozen=True for immutability. If you know TypeScript, think of it as an interface and class in one.
5. zip + enumerate - The Forgotten Duo
Many still write manual index loops:
for i in range(len(items)):
print(i, items[i])
This is more Pythonic:
for i, item in enumerate(items):
print(i, item)
Need to combine two lists?
names = ["Alice", "Bob", "Charlie"]
scores = [85, 92, 78]
for name, score in zip(names, scores):
print(f"{name}: {score}")
Bonus: Python 3.10+ adds strict=True to zip, raising an error if lists have different lengths - good for catching silent bugs.
for name, score in zip(names, scores, strict=True):
print(f"{name}: {score}")
---
Bonus: List Comprehension vs Generator
Most people know list comprehensions:
squares = [x2 for x in range(1000)] # 1000 items in memory
But if you only need to iterate once, use a generator:
squares = (x2 for x in range(1000)) # 0 items in memory - lazy
for s in squares:
print(s)
Same syntax, different brackets: [] → (). Huge impact when processing large datasets.
---
The Point
Python looks simple on the surface, but there's a lot underneath that makes your code faster, leaner, and cleaner. You don't need to memorize everything - just know these exist, then Google when you need them.
Most important: don't use tricks just to look smart. Use them when they genuinely make your code better. When in doubt, write the clear version first. Refactor later.