Top 10 Ways To Write Better Python Code

17 VIEWS

· ·

The awesome thing about Python is that if you can think of something you’d like to code, there’s probably already a library for it! In fact, Python provides many tools, utilities and other resources to make any coding job easier. From dictionaries to collections to itertools to generators, there are lots of ways to write better, more concise Python code, many of which you may be under-utilizing or not even aware of.

But all of these great options mean there might be dozens of ways to write a unit of business logic. This really comes into effect when you’re reading other developers’ code. Ever feel like this?

reading another developer's code

It’s not just other people’s code, though, I sometimes feel like this when I read my own code after a couple of weeks off!

Fortunately, writing better Python code isn’t hard. As a precursor to this article, I encourage you to choose a well-accepted style guide if our goal is to write better code. Style guides help you stick to a format, making it easier to read code written by people on your team – and your own code, as well! I personally prefer “The Hitchhiker’s Guide To Python.” It’s extensive and well written.

It’s also a good idea to abide by well-known software principles like DRY (Don’t Repeat Yourself) and KISS (Keep It Simple, Stupid!). Finally, never skimp out on tests and documentation. They might be boring, but they will save you in the long run.

This article will introduce you to the top 10 ways you might not be fully taking advantage of to write better Python code, including:

  1. Lambda Function Dictionaries
  2. Dictionary Access
  3. Counter Collections
  4. Default Dictionaries
  5. Combinations and Permutations
  6. Groupby
  7. Generator Functions
  8. UUIDs
  9. Arrays
  10. Unpacking Arguments With “_” And “*”

Now, let’s get into the fun bit! It’s time to write better Python code!

How To Write Better Python Code

All of the methods outlined below make you a better Python developer, but don’t feel like you have to tackle all of them at once. You’ll get more mileage out of consistently applying some of them, rather than inconsistently applying all of them.

1 — Lambda Function Dictionaries

Did you know that dictionaries can also store Lambda functions? Lambda functions are those single-line, nameless functions, which can prove quite useful when performing minor alterations to data.

Normally, you would just store a Lambda function in a variable to be called later. For example:

square = lambda num: num * num
square(5)

Output:

25

However, if you want to group multiple common Lambdas together, they can be stored in dictionaries:

lamb = {'sum': lambda x, y: x + y, 'diff': lambda x, y: x - y}
lamb['sum'](6,5)

Output:

11

Or try:

lamb['difft'](25, 16)

Output:

9

2 — Access Dictionary Elements Elegantly

As wonderful as dictionaries are, I always fear the day my code crashes because I accessed an unavailable key. The problem most often crops up when interfacing with external APIs because in many cases, keys are only present when certain conditions are met. If you access a key that is not present an error will be thrown.

I would usually write:

s = {“name”: “swaathi”, “id”: “O24851”, “emp”: True}
n = {“name”: “nick”, “emp”: False}

if s.has_key(“id”):
print s[“id”]
else:
print “not an employee”

However, the more idiomatic way to write this is:

s.get(“id”, “not an employee”)

Output:

O24851

Or try:

n.get(“id”, “not an employee”)

Output:

not an employee

3 — Counter Collections

Python collections are a powerful data structure that can be very helpful if used properly. One of the simplest ways to make use of a collection is as a counter. In other words, use a collection to count the number of elements in a list, or the number of letters in a list of words, and so on.

For example:

import collections
A = collections.Counter([1, 1, 2, 2, 3, 3, 3, 3, 4, 5, 6, 7])
A

Output:

Counter({3: 4, 1: 2, 2: 2, 4: 1, 5: 1, 6: 1, 7: 1})

This definitely beats looping over and incrementing a counter each time! You can also query it for more information, such as the highest element occurrence:

A.most_common(1)

Output:

[(3, 4)]

Or try:

A.most_common(3)

Output:

[(3, 4), (1, 2), (2, 2)]

4 — Default dictionary

This has been my savior so many times! In our second point, we saw how to use the “get” function to read dictionary keys safely. Well, if we had used a default dictionary, that wouldn’t have even been necessary!

With default dictionaries, you can set the default data type for null values. This is helpful when you’re analyzing data and need everything to be of a particular data type. Otherwise, you’d be writing more ‘if statements’ than actual code!

import collections
t = collections.defaultdict(int)
t['a']

Output:

0

You can also change the default value to be a null string instead:

t = collections.defaultdict(str)
t['a']

Output:

“”

5 — Combinations and Permutations

The itertools module is a collection of functions that enhance processing of iterators. Itertools contain many prebuilt methods useful in data analytics or machine learning. For example, you can easily create a matrix of all possible combinations and permutations using:

import itertools
shapes = ['circle', 'triangle', 'square',]
itertools.combinations(shapes, 2)

Output:

('circle', 'triangle')
('circle', 'square')
('triangle', 'square')

You can also create permutations:

import itertools
shapes = ['circle', 'triangle', 'square',]
itertools.permutations(shapes)

6 — Groupby

Sometimes when interfacing with external APIs or parsing data, you might need to group a list of items. Traditionally, you would use multidimensional loops to achieve this, but in true Pythonic fashion, you can use a function instead. In my opinion, this is Itertools’ most useful function. For example:

from itertools import groupby

things = [("animal", "bear"), ("animal", "duck"), ("plant", "cactus"), ("vehicle", "speed boat"), ("vehicle", "school bus")]

for key, group in groupby(things, lambda x: x[0]):
for thing in group:
    print("A %s is a %s." % (thing[1], key))
print("")

Output:

A bear is an animal.
A duck is an animal.
A cactus is a plant.
A speed boat is a vehicle.
A school bus is a vehicle.

Groupby takes in a list and a function that returns the value to group by. In the above example, the Lambda function returns the first value of the set. This is used to group the list.

An important aspect of the groupby function is that you need to pass it a sorted list. It simply creates a new group when it encounters a new key. It will not retroactively update a previously created group.

7 — Generator Functions

Python generator functions are computations that are performed when called upon, rather than at invocation. Generator functions return lazy iterators which are commonly used when interfacing with I/O devices, such as reading from a file.

Generator functions utilize memory efficiently, and avoid memory leaks at the source. For example:

def my_gen():

    n = 1
    print('This is printed first')

    # Generator function contains yield statements
    yield n

    n += 1
    print('This is printed second')
    yield n

    n += 1
    print('This is printed at last')
    yield n

for item in my_gen():
print(item)

Output:

This is printed first
1
This is printed second
2
This is printed at last
3

8 — Generating UUIDs

Sometimes you just need a random string in order to tag some information. If you use a timestamp or a random function, there are chances that it will clash and generate duplicate tags.

In these cases, you should be generating a UUID instead. UUIDs are randomized 128-bit numbers, guaranteed to be unique every time you call them. In fact, there are over 2¹²² possible UUIDs that can be generated. That’s over five undecillion (or 5,000,000,000,000,000,000,000,000,000,000,000,000).

import uuid
user_id = uuid.uuid4()
user_id

Output:

UUID('7c2faedd-805a-478e-bd6a-7b26210425c7')

9 — Commonly used array functions

Here are some of my favorite array functions that I frequently use:

Range: used to create a sequence of numbers by specifying start index, end index, and step:

list(range(0,10,2))

Output:

[0, 2, 4, 6, 8]

Sum, min, max: used to sum elements in an array, or else find the min and max values:

min(array), max(array), sum(array)
print(array.min(), array.max(), array.sum())

Any and all: useful in performing quick checks, such as checking if either any or all elements meet a truth condition:

any(a % 3==0 for a in range(0,10,2))

Output:

True

Or try:

all(a % 3==0 for a in range(0,10,2))

Output:

False

Or try:

all(a % 3==0 for a in range(0,10,2))

Output:

True

10 — Unpack Arguments With _ And *

If you only need the first few elements of an array, you can use the underscore operator to extract it:

numbers = [1, 2, 3]
a, b, _ = numbers
a

Output:

1

Alternatively, if you need to extract the first few and last few elements, you can use the star operator as a catchall:

long_list = [x for x in range(100)]
a, b, *c, d, e, f = long_list
[a, b, d, e, f]

Output:

[0, 1, 97, 98, 99]

Here the *c acts as a catchall and stores any length of elements.

Summary

And there you have it, my top ten tips that will have you writing better Python code in no time!

But there’s one last thing before you go. In order to maintain the zen of this article, it is only reasonable to end the article with a meme, so here’s an easter egg for you. Go to your Python console and type in:

import antigravity

Output:

antigravity


Swaathi Kakarla is the co-founder and CTO at Skcript She enjoys talking and writing about code efficiency, performance and startups. In her free time she finds solace in yoga, bicycling and contributing to open source. Swaathi is a regular contributor at Fixate IO.


Discussion

Click on a tab to select how you'd like to leave your comment

Leave a Comment

Your email address will not be published. Required fields are marked *