6 Things Every Beginner Should Know To Write Clean Python Code

I have studied Java at my high school. When I first started writing Python in my freshman year, I used to mentally translate Java to Python. But after some good amount of open source exposure, I figured that Python is way cleaner and idiomatic than Java.

In this blog post, I discuss 6 things I wish I knew about Python as a beginner. Using these in your code would not only make your code more beautiful but also more efficient. All these tips are applicable for both Python 2 and 3.

1. Looping Over Collection and Indices

If you are coming from a C++ or a Java background, your logic for looping over collections and indices may look like –

>>> characters = ["Rick", "Maggie", "Carl", "Negan", "Daryl"]

>>> for i in range(len(characters)):
       print(i, characters[i])
(0, 'Rick')
(1, 'Maggie')
(2, 'Carl')
(3, 'Negan')
(4, 'Daryl')

But Python has a much cleaner way to do it. You can use the enumerate function. It is fast, beautiful and also saves us from tracking the indices.

>>> for i, character in enumerate(characters):
       print(i, character)
(0, 'Rick')
(1, 'Maggie')
(2, 'Carl')
(3, 'Negan')
(4, 'Daryl')

Another useful way to use enumerate is when we need a dictionary with keys as indices of the list and values as elements of the list.

>>> dict(enumerate(characters))
{0: 'Rick', 1: 'Maggie', 2: 'Carl', 3: 'Negan', 4: 'Daryl'}

2. Looping over two collections

Looping over two lists (or other collections) together is also way simpler than you might think. So, instead of –

>>> characters = ["Tyrion", "Arya", "Danerys", "John", "Jeoffery"]
>>> houses = ["Lannister", "Stark", "Targaryen", "Targaryen"]

>>> length = min(len(characters), len(houses))
>>> for i in range(length):
	print(characters[i], houses[i])

('Tyrion', 'Lannister')
('Arya', 'Stark')
('Danerys', 'Targaryen')
('John', 'Targaryen')

You can simply use the zip method –

>>> for character, house in zip(characters, houses):
	print(character, house)

('Tyrion', 'Lannister')
('Arya', 'Stark')
('Danerys', 'Targaryen')
('John', 'Targaryen')

Similar to enumerate the zip function can also be used to create dictionaries directly,

>>> dict(zip(characters, houses))
{'Arya': 'Stark', 'John': 'Targaryen', 'Danerys': 'Targaryen',
 'Tyrion': 'Lannister'}

Note – The zip function behaves differently in Python 2 and 3. In Python 2 it creates a new third list. Thus increasing memory requirement. Therefore, a better alternative to zip in Python 2 is itertools.izip. It behaves exactly as the zip method described above but is scalable as well.

In Python 3, this problem was fixed. Similar to the itertools.izip method the zip function also returns a generator, thus making it memory efficient.

3. Concatenating Strings

I see many people over complicate string concatenation and ignore the join method of strings. So instead of doing –

>>> s = ''
>>> sentence = ["I", "love", "to", "code", "in", "Python"]
>>> for word in sentence:
	s += word + " "	
>>> s
'I love to code in Python '

We can simply do –

>>> sentence = ["I", "love", "to", "code", "in", "Python"]

>>> " ".join(sentence)
'I love to code in Python'

>>> "".join(sentence)
'IlovetocodeinPython'

>>> "|".join(sentence)
'I|love|to|code|in|Python'

4. Counting Using Dictionaries

How many of us have written something similar to –

>>> memo = {}
>>> sentence = "I love to code in Python."
>>> for char in sentence:
        if char in memo:
	    memo[char] += 1
	else:
	    memo[char] = 1

Here, we needed to calculate the occurrence of each character. I had also been using the above code until I was introduced to the defaultdict collection which lets us do all this in a more concise manner.

>>> from collections import defaultdict
>>> memo = defaultdict(int)
>>> for char in sentence:
	memo[char] += 1

A Python dictionary throws a KeyError if we try to get an item with a key that is not present in the dictionary. Unlike a dictionary, when we try to access an item whose key is not already present then the defaultdict will create an item on its own. This created item depends on the function we passed while declaring the defaultdict object. Here, the object is created using int() function that will return the integer object 0.

Similarly, a defaultdict object created using the list() function would return an empty list for a key that is not already present.

>>> s = [('2017', 1), ('2018', 2), ('2017', 3), ('2019', 4), ('2019', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
        d[k].append(v)

>>> d.items()
[('2017', [1, 3]), ('2019', [4, 1]), ('2018', [2])]

5. List and Generator Comprehensions

Comprehensions is a powerful syntax to transform collections in various ways. This is perhaps my favorite feature in Python. Let’s explore this with examples.

Suppose, you have to create a list of squares of the first 10 natural numbers (1, 4, 9, …..). Without using list comprehension your code will look messy. Let me show you.

>>> elems = []
>>> for x in range(1, 11):
	elems.append(x*x)

>>> elems
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

Or how about if we only print the square of even numbers and leave out the odd numbers.

>>> elems = []
>>> for x in range(1, 11):
	if(x % 2 == 0):
	    elems.append(x*x)
>>> elems
[4, 16, 36, 64, 100]

Let’s take this one step further. Let’s print the square of even numbers and cube of odd numbers.

>>> for x in range(1, 11):
	if(x % 2 == 0):
	    elems.append(x*x)
	else:
	    elems.append(x*x*x)	
>>> elems
[1, 4, 27, 16, 125, 36, 343, 64, 729, 100]

Even if this does not seem ugly enough for you, let me show you the comprehension syntax to do it and I bet you will love it.

>>> [x*x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

>>> [x*x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100]

>>> [x*x if x % 2 == 0 else x*x*x for x in range(1, 11)]
[1, 4, 27, 16, 125, 36, 343, 64, 729, 100]

The comprehension syntax is as useful and beautiful with dictionaries as it is for lists. Let’s create a dictionary with keys as strings and values as the length of strings.

>>> {x: len(x) for x in ["Ted", "Barney", "Robin", "Marshall", "Lily"]}
{'Lily': 4, 'Marshall': 8, 'Barney': 6, 'Ted': 3, 'Robin': 5}

Comprehensions can also be used for assignment.

>>> x = 123
>>> number = "even" if x % 2 == 0 else "odd"
>>> number
'odd'

 

6. Tuple Assignment

Tuple assignments are very clean in Python unless you try to mess them up. So next time when you find something like this in your code –

>>> movies = ("The Dark Knight", "Inception", "Interstellar", "Prestige")
>>> m1 = movies[0]
>>> m2 = movies[1]
>>> m3 = movies[2]
>>> m4 = movies[3]
>>> m1, m2, m3, m4
('The Dark Knight', 'Inception', 'Interstellar', 'Prestige')

You can replace it with –

>>> m1, m2, m3, m4 = movies
>>> m1, m2, m3, m4
('The Dark Knight', 'Inception', 'Interstellar', 'Prestige')

Or something like this –

>>> x = 1
>>> y = 2
>>> tmp = x
>>> x = x + y
>>> y = tmp
>>> x, y
(3, 1)

with –

>>> x, y = 1, 2
>>> x, y = x + y, x
>>> x, y
(3, 1)

Hope you enjoyed reading this. Thank a lot. 🙂

2 thoughts on “6 Things Every Beginner Should Know To Write Clean Python Code”

  1. I think I pretty much checked on everything except for, defaultdict. Learned something new…! Also, I have a habit of writing list empty checks as:
    if foolist is not None and len(foolist) >0:
    instead of:
    if not foolist:
    the first approach to me is much for reader-friendly. Someone might think foolist is boolean in the second approach…

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s