After writing Python for years, I've collected a bunch of small things that make my life easier. Nothing groundbreaking here, just practical stuff I use regularly. Some of these I learned the hard way, some I picked up from colleagues, some from Stack Overflow at 2am when something wasn't working.

List comprehensions

I know, everyone talks about list comprehensions. But seriously, once you get used to them, writing a for loop to build a list feels wrong. I use them all the time:

# Instead of this
results = []
for item in data:
    if item.active:
        results.append(item.name)

# Just do this
results = [item.name for item in data if item.active]

The one thing I'd say is don't go overboard. If your list comprehension is more than one line or has nested conditions that make it hard to read, just use a regular loop. Clever code is not the same as good code.

Context managers

The with statement is one of those things that seems obvious once you know about it, but I've seen plenty of code that opens files or database connections without using it. The point is simple: it guarantees cleanup happens, even if something goes wrong.

# Always do this
with open('data.csv', 'r') as f:
    content = f.read()

# Not this
f = open('data.csv', 'r')
content = f.read()
f.close()  # if something breaks before this, you have a problem

I also use context managers for database connections and for temporarily changing working directory when running scripts that expect to be in a specific path.

f-strings

If you're still using .format() or % for string formatting, switch to f-strings. They've been available since Python 3.6 and they're just better.

name = "Montevideo"
temp = 28
# This
print(f"It's {temp} degrees in {name}")

# Instead of this mess
print("It's {} degrees in {}".format(temp, name))

The one gotcha: don't put complex expressions inside f-strings. If you need more than a simple variable or attribute access, compute it first and then use the result in the f-string. Readability matters more than cleverness.

enumerate() instead of counting

I used to write i = 0 before a for loop and increment it manually. Then someone showed me enumerate() and I felt a bit silly.

for i, item in enumerate(items):
    print(f"{i}: {item}")

You can also start from a different number: enumerate(items, start=1) if you want 1-based indexing.

Virtual environments

This is not a "tip" exactly, but I keep seeing people install packages globally and then wondering why their other projects break. Use virtual environments. Always. python -m venv myenv and you're done. It takes 10 seconds and saves you hours of debugging dependency conflicts.

I also pin my requirements. pip freeze > requirements.txt is fine for development, but for production I specify exact versions. "It works on my machine" is not a deployment strategy.

defaultdict

When you're building dictionaries where values are lists or counters, defaultdict from collections saves you from writing a lot of if key not in dict boilerplate.

from collections import defaultdict

groups = defaultdict(list)
for item in data:
    groups[item.category].append(item)

No more KeyError surprises. I use this one a lot when processing data.

The standard library is bigger than you think

Before you reach for a third-party library, check if the standard library already does what you need. pathlib for file paths, dataclasses for simple data containers, logging instead of print statements, argparse for command line arguments — these are all built in and they're good.

I've removed plenty of dependencies from projects just by replacing them with standard library modules. Less dependencies means less things that can break when you upgrade Python.

That's it really. Nothing fancy, just stuff that saves me a few minutes here and there. The best Python tip I know is still the simplest: write code that you'll understand when you come back to it in six months.