Python – The Missing Manual

Table of contents

1. Basics

1.1 Variable replacement

Python variable names start with a lower case letter, can contain letters, underscores, words, and numbers. There are many ways to use variables inside strings. The following examples show the different ways we can do it:

v = "sushi" 
u = 10
print(v) 
>>> sushi 
print("I like " + v) 
>>> I like sushi
print ('I like', v) 
>>> I like sushi
print(f'I like {v}') 
>>> I like sushi
print("I like %s" % (v)) 
>>> I like sushi
print("I ordered %s and I paid $%f" % (v, u)) 
>>> I ordered sushi and I paid $10.000000
print("I ordered %s and I paid $%i" % (v, u)) 
>>> I ordered sushi and I paid $10

We use input() to prompt users for input from the command line:

name = input('What is your name?\n')
print(f'Hello {name}.')

1.2 String methods

'q'.isupper()
>>> False
'Q'.isupper()
>>> True
'hello'.upper()
>>> 'HELLO'
'  abc '.strip()
>>> 'abc'
'abca'.strip('ac')
>>> 'b'
'aaabcaa'.count('a')
>>> 5
'aabcaa'.count('ab')
>>> 1

If occurrences of the argument overlap, only the first counts:

'ababa'.count('aba')
>>> 1

We can use this to count words:

'this is a string with many words'.count(' ')
>>> 6 # missing last word
'this is a string with many words'.count(' ') + 1
>>> 7 # correct answer

Although not a string method, but the in relational operator is useful with strings. Note that the letters in the string have to be consecutive to return True.

'ppl' in 'apple'
>>> True

'al' in 'apple'
>>> False

2. Lists

Lists in Python can hold multiple item types. Here’s how you can create a list:

items = ["sushi", 10, "sashimi", True]

You can check whether an item is in a list by using the in operator:

print("sashimi" in items) 
>>> True

You can use the index() method to find the index of an item in the list:

items.index("sushi") 
>>> 0
items.index(10) 
>>> 1

Using a negative index will access items from the end:

items[-1] 
>>> True

You can also extract a part of a list, using slices:

items[0:2] 
>>> ["sushi", 10]
items[2:] 
>>> ["sashimi", True]

You can get the number of items contained in a list using the len() function:

len(items) 
>>> 4

len() also works with strings:

len("items") 
>>> 5

You can add items to a list by using append(), extend(), or =+:

items.append("nigiri")
items.extend(["nigiri"])
items += ["nigiri"]

They will all have the same output below:

items = ["sushi", 10, "sashimi", True, "nigiri"]

You can remove an item from a list by using the remove() method with the name of the item you want to remove:

items.remove("nigiri")

To add an item in the middle of a list, at a specific index, use the insert() method:

items.insert(1, "nigiri") # adds "nigiri" at index 1

The list will now become:

items = ['sushi', 'nigiri', 10, 'sashimi', True]

2.1. List copying

You can copy a list in Python, by using the copy() method, or the list() method, or the slice operator [:]. All will create a new list that is a copy of the original list, so you can modify the new list without affecting the original list.

Using the copy() method:

original_list = [1, 2, 3]
new_list = original_list.copy()  

Using the list() method:

original_list = [1, 2, 3]
new_list = list(original_list)

Using the slice operator [:] method:

original_list = [1, 2, 3]
new_list = original_list[:]

2.2. List sorting

You can sort a list by using the sort() method:

items.sort(key=str.lower)

You use key=str.lower to normalize the sort because uppercase is ordered before lowercase.

Note: Sorting modifies the original list.

To avoid that, you can make a copy of the list first, like this:

items_copy = items[:]

You can also use the sorted() method to return a sorted copy of the original list:

items_copy = sorted(items, key=str.lower))

2.3. List iteration

In this section we discuss for loops and while loops.

2.3.1 Iteration using for loops

In Python, we can iterate over a list using a for loop. In this example, we first create a list called my_list with five elements. Then, we use a for loop to iterate over each item in the list, and print it to the console. Using in when iterating with for loops, the loop variable takes on the value of the list item or the string character in each iteration:

my_list = [1, 2, 3, 's', 't']

for item in my_list:
    print(item)

>>> 1
>>> 2
>>> 3
>>> s
>>> t

Similarly, we can iterate using a string:

for char in "olive":
    print(char)

>>> o
>>> l
>>> i
>>> v
>>> e

We can also use the range() function to specify the number of times we iterate. When using range() the loop variable is an integer and not the value of the list item or string character. If we provide one argument to range(), we get a range from 0 to 1 less that argument:

for num in range(4):
    print(num)

>>> 0
>>> 1
>>> 2
>>> 3

If we provide 2 arguments to range(), we get a sequence from the first argument up to but not including the 2nd argument:

for num in range(2, 6):
    print(num)

>>> 2
>>> 3
>>> 4
>>> 5

We can use the range() function to count down in a for loop. And we can also use a step size while looping. To count down in a for loop the step size needs to be negative:

for num in range(6, 2, -1):
    print(num)

>>> 6
>>> 5
>>> 4
>>> 3

To count down to 0 (including 0), the 2nd argument needs to be -1:

for num in range(6, -1, -1):
    print(num)

>>> 6
>>> 5
>>> 4
>>> 3
>>> 2
>>> 1
>>> 0

We can use a range for loop to process a string from right to left:

s = 'sashimi'

for i in range(len(s) -1, -1, -1):
    print(s[i])

>>> i
>>> m
>>> i
>>> h
>>> s
>>> a
>>> s

To access and print out the index and the item in a list, you should wrap the sequence into the enumerate() function.

What enumerate does is it takes an iterable (like a list) and returns a new iterable. This new iterable consists of tuples, and each tuple contains two values:

– The first value is the index of the item (starting from 0).
– The second value is the item itself.

Basically, we are converting a one-dimensional list to a two-dimensional list and then iterating over the inner lists:

items = ['a', 'b', 'c', 'd']
for index, item in enumerate(items):
    # enumerate returns: [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]
    print(index, item)

>>> 0 a
>>> 1 b
>>> 2 c
>>> 3 d

The above example works due to a concept called ‘Tuple Unpacking’. Python allows you to unpack, or assign, the elements of a tuple (or list) into multiple variables in a single operation, provided the number of variables on the left side of the assignment matches the number of elements in the tuple (or list). This is fancy stuff. Here’s an example:

list = [[1,'a'], [2, 'b'], [3, 'c']]

for first_item, second_item in list:
    print(first_item, second_item)

>>> 1 a
>>> 2 b
>>> 3 c

Let’s look at the more traditional way of iterating over a two-dimensional list in Python using for loops. In this example, we first create a two-dimensional list called my_list with three rows and three columns. Then, we use a nested for loop to iterate over each item in the list, and print it to the console. The outer for loop iterates over each row in the list, while the inner for loop iterates over each item in the current row.

my_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

for row in my_list:
    for item in row:
        print(item)

Alternatively, you can use indexing i.e. range() to access the elements in a two-dimensional list. In this example, we use nested for loops to iterate over the list using indices. The outer loop iterates over each row in the list, while the inner loop iterates over each item in the current row using indices. We use the len() function to get the length of each row, and the range function to generate the indices for the loops.

my_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

for i in range(len(my_list)):
    for j in range(len(my_list[i])):
        print(my_list[i][j])

2.3.2 Iteration using while loops

Let’s move on to while loops. We can also use a while loop to iterate over a list.

In this example, we use a while loop to iterate over each item in the list, and print it to the console. We use a counter variable i to keep track of the index we’re currently at in the list. We use the len() function to get the length of the list, and make sure we stop iterating when we reach the end of the list.

my_list = [1, 2, 3, 4, 5]

i = 0
while i < len(my_list):
    print(my_list[i])
    i += 1

>>> 1
>>> 2
>>> 3
>>> 4
>>> 5

We can process strings using while loops:

s = 'sashimi'

i = 0

while i < len(s):
    print('We have ' + s[i])
    i = i + 1

>>> We have i
>>> We have m
>>> We have i
>>> We have h
>>> We have s
>>> We have a
>>> We have s

To process a string from right to left using a while loop:

s = 'sashimi'

i = len(s) - 1

while i >= 0:
    print('We have ' + s[i])
    i = i - 1

>>> We have i
>>> We have m
>>> We have i
>>> We have h
>>> We have s
>>> We have a
>>> We have s

In the next example, we use nested while loops to iterate over a two-dimensional list using indices. The outer while loop iterates over each row in the list, while the inner while loop iterates over each item in the current row using indices. We use the len() function to get the length of each row, and the counter variables i and j to keep track of the current indices.

my_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

i = 0
while i < len(my_list):
    j = 0
    while j < len(my_list[i]):
        print(my_list[i][j])
        j += 1
    i += 1

3. Tuples

Coming soon.


4. Dictionaries

Coming soon.


5. Sets

Coming soon.


6. Functions

Coming soon.


7. Classes

Coming soon.


8. Introspection

Introspection in Python means that you can analyze: Functions, variables and objects. This is mostly helpful for troubleshooting without using a debugger tool. In this section we will outline 4 different introspection tools commonly used in Python.

8.1. The dir() method

The dir() global function allows you to return all properties and methods of an object including the built in ones as a list. This is very useful especially when you are not sure what attributes or methods can be called on a specific object.

>>> from courses.models import Course
>>> courses = Course.objects.all()
>>> print(dir(courses[0]))

>>> ['check', 'clean', 'clean_fields', 'created', ... ]

We basically get a list of both private and public functions and attributes. Private functions and attributes are the ones that begin with an underscore.

8.2. The inspect module

Another good introspection method to know is inspect. It's a built-in python module that can also be used to get comprehensive information about a Django object. The getmembers() method return a list of tuple of all the attributes and functions of an object.

>>> from inspect import getmembers
>>> getmembers(user)

But a better way is to filter and return just the functions using the inspect.isfunction() method:

>>> from inspect import getmembers, isfunction
>>> from django.contrib.auth.models import User
>>> functions = [x[0] for x in getmembers(User) if isfunction(x[1])]
>>> print(functions)

8.3. The __dict__ attribute

You can use the __dict__ attribute of python objects which is used to store an object’s (writable) attributes. This allows you to see the readable attribute name as well as the values it contains. You use it by calling .__dict__ on the object like so: user.__dict__.

8.4. The type function

And finally, you can use the type() function to determine the type of any expression like this:

type(9.5)
>>> class 'float'