Python Tip #153 (of 365):

When you write type annotations, embrace duck typing: annotate with the most general type you can.

Don't require a list if any iterable will do. Don't require a dict if any mapping will do.

Most functions that "accept a list" actually accept any iterable.

Instead of:

def square_all(numbers: list[float]) -> list[float]: ...

Prefer:

from collections.‍abc import Iterable
def square_all(numbers: Iterable[float]) -> list[float]: ...

🧡 (1/2)

#Python #DailyPythonTip

Python Tip #152 (of 365):

Be consistent about your type annotations: skip them entirely or run a type checker.

An unchecked annotation is really just a comment, and it may be a confusingly incorrect comment. A type checker keeps your annotations honest.

Annotations can add noise to code, but they can also increase correctness.

Half-annotated code that isn't type checked adds visual noise WITHOUT adding the safety of type checking.

🧡 (1/2)

#Python #DailyPythonTip

Python Tip #151 (of 365):

For truly unpredictable randomness, use the secrets module

Python's random module relies on pseudo-randomness, meaning it generates numbers in a predictable order. If someone can guess the random "seed" (it's based on the current time) they can predict the numbers produced.

For true randomness, use Python's secrets module instead.

🧡 (1/3)

#Python #DailyPythonTip

Python Tip #150 (of 365):

When you need to pick a random item, use random.choice

You might be tempted to use random.randrange for selecting random items from a list by their index, but there's a better way!

To pick a random item any sequence, use random.choice:

>>> import random
>>> random.choice(["red", "green", "blue"])
'green'

#Python #DailyPythonTip

Python Tip #149 (of 365):

Sort by specific attributes with operator.attrgetter.

Have an iterable of dataclasses, namedtuples, or some other record-like object?

Want to sort them by a specific attribute?

Use operator.attrgetter:

from operator import attrgetter

For example, if we had an iterable of Book objects that have a title attribute, we could sort them by that:

sorted_books = sorted(books, key=attrgetter("title"))

🧡 (1/2)

#Python #DailyPythonTip

Python Tip #148 (of 365):

Sort by specific sequence items with operator.itemgetter.

Have an iterable of sequences (tuples, lists, etc.)?

You can sort them by one or more of their indexes using itemgetter from Python's operator module.

from operator import itemgetter

For example, say we have CSV rows:

rows = list(csv.reader(file))

And we want to sort these rows by their second column.

We can do this:

sorted_rows = sorted(rows, key=itemgetter(1))

🧡 (1/2)

#Python #DailyPythonTip

Python Tip #147 (of 365):

Sort by unbound method objects instead of using "lambda" 🧡

Say you're sorting mixed capitalization strings:

>>> frameworks = ["jQuery", "React", "Alpine", "htmx", "Svelte"]
>>> sorted(frameworks)
['Alpine', 'React', 'Svelte', 'htmx', 'jQuery']

You could case-normalize with a key function that calls casefold on each string:

>>> sorted(frameworks, key=lambda s: s.casefold())
['Alpine', 'htmx', 'jQuery', 'React', 'Svelte']

Or...

🧡 (1/3)

#Python #DailyPythonTip

Python Tip #146 (of 365):

Don't use sorted to find the largest/smallest item(s).

Have an iterable of items and need the largest/smallest ones?

>>> numbers = [47, 199, 123, 275, 29, 123, 18, 76, 76, 351]

Unless you need every item in sorted order, you probably don't need to sort your iterable.

You can use the max function:

>>> max(numbers)
351

To get the smallest value, you can use min:

>>> min(numbers)
18

🧡 (1/2)

#Python #DailyPythonTip

Python Tip #145 (of 365):

To sort by specific features of an iterable of objects, use a key function.

For example, we could sort strings by their lengths:

>>> colors = ["yellow", "blue", "green", "purple"]
>>> sorted(colors, key=len)
['blue', 'green', 'yellow', 'purple']

A key function can be any callable that can accept each object from the iterable and return a "key" for each.

This all works because functions are objects (recall tip 34).

🧡 (1/2)

#Python #DailyPythonTip

Python Tip #144 (of 365):

To suppress specific exceptions, use contextlib.suppress.

You could suppress an exception like:

try: ...
except ValueError: pass

But I would recommend:

from contextlib import suppress
with suppress(ValueError): ...

contextlib.suppress more clearly indicates "we're deliberately suppressing an exception" instead of "we got lazy while exception handling".

You should ALSO always ask yourself, "should I actually BE suppressing this exception?"

#Python #DailyPythonTip