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.

· · 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.