This is a micropost, a quick and straight to the point article containing a self-contained tip or idea. Posts of these nature are sort of in a braindump format. If you want me to expand on the topic in depth, please send me a message.


Instead of defining your functions in this manner:

def generate_usage_report(users, start_date, end_date, limit=3):
    stats = [extract_usage_stats(user) for user in users]
    return Report.limit(limit).from(start_date).to(end_date)

… and get confused as you use them like this:

# What do these parameters even mean?

reports = generate_usage_report([john, bob, jane], today() - month(), today(), 10)

You can define them like this:

def generate_usage_report(
    *, 
    users: List[User], 
    start_date: datetime, 
    end_date: datetime, 
    limit: int=3,
) -> Report:
    stats = [extract_usage_stats(user) for user in users]
    return Report.limit(limit).from(start_date).to(end_date)

… to be used like this:

reports = generate_usage_report(
    users=[john, bob, jane], 
    start_date=today() - month(), 
    end_date=today(), 
    limit=10,
)

Pros:

  1. Every function call is intuitive at a glance.
  2. Zero ambiguity, you don’t accidentally mix the start and end date since you don’t have to pass them in order.
  3. mypy support for typehints.

Cons:

  1. More keystrokes.

Got any feedback or suggestions? Feel free to send me an email or a tweet.
Ciao!