Python Crash Course

The purpose of this article is to help you refresh your knowledge of all the basic Python keywords, data structures, and fundamentals. I wrote it for the intermediate Python programmer who wants to reach the next level of programming expertise.

However, the way of achieving an expert-level is often through studying the basics. For example, computer science professors usually have an extremely profound knowledge of the basics in their field. This enables them to argue from “first principles” rather than from the state-of-the-art—it’s easier for them to identify research gaps because they know about the ground rules in their field rather than being blinded by the latest technology and state-of-the-art. If you want to reach the next level in coding, take your time and study the basics carefully. This chapter provides you with the most important Python basics which serve as a foundation for more advanced topics in this book.

  1. Python Keywords
  2. Python Basic Data Structures
  3. Python Container Data Structures
  4. Membership Operator
  5. List and Set Comprehension
  6. Summary

Click the image to register and download all Python cheat sheets.

Python Keywords

Like any other programming language, Python has many keywords with special meaning. For instance, Python 3.7 comes with 33 special keywords:

'''
False
class
finally 
is 
return
None
continue
for
lambda
try
True
def
from 	
nonlocal 	
while
and 	
del 	
global 	
not 	
with
as 	
elif 	
if 	
or 	
yield
assert 	
else 	
import 	
pass 	 
break 	
except 	
in 	
raise
'''

Exercise: Quickly glance over the list of keywords and try to explain their meaning.

In the following, you will study the most important Python keywords with short examples.

Keywords: False, True

These keywords represent the only two data values from the Boolean data type. In Python, Boolean and integer data types are closely related: the Boolean data type internally uses integer values (per default, the Boolean value False is represented by integer 0 and the Boolean value True is represented by integer 1).  The following code snippet gives you an example of these two Boolean keywords.

x = 1 > 2
print(x)
# False

y = 2 > 1
print(y)
# True

After evaluating the given expressions, variable name x refers to the Boolean value False and variable y refers to the Boolean value True.

Keywords: and, or, not

These keywords represent basic logical operators.

  • Keyword and: The expression x and y evaluates to True if value x is True and value y is True. If one of those is False, the overall expression becomes False, too.
  • Keyword or: The expression x or y evaluates to True if value x is True or value y is True (or both values are True). If one of those is True, the overall expression becomes True, too.
  • Keyword not: The expression not x evaluates to True if value x is False.

Consider the following Python code example:

x, y = True, False

print((x or y) == True)
# True

print((x and y) == False)
# True

print((not y) == True)
# True 

By using these three operations—and, or, and not—you can express all logical expressions you’ll ever need.

Keywords: if, else, elif

Algorithms are often compared to cooking recipes. Imagine a cooking recipe which consists only of a sequential list of commands: fill water into a pot, add the salt, add the rice, get rid of the water, and serve the rice. Strictly speaking, without a conditional execution, the sequence of commands would take only a few seconds to execute and the rice would not be ready for sure. For example, you would fill in water, salt, and rice and immediately get rid of the water without waiting for the water to be hot and the rice to be soft.

We need to respond in a different way to different circumstances: we need to remove the water from the pot only if the rice is soft, and we need to put in the rice if the water is hot. It’s almost impossible to write programs in a way that anticipate what happens in the real world in a deterministic manner. Instead, we need to write programs that respond differently if different conditions are met. This is precisely why we need conditional execution with the keywords if, else, and elif.

x = int(input("your value: "))
if x > 3:
    print("Big")
elif x == 3:
    print("Medium")
else:
    print("Small")

The code snippet first takes the user input, converts it into an integer, and stores it in the variable x. It then tests the variable value whether it is larger than, equal to, or smaller than the value 3. In other words, the code responds to real-world input that is unpredictable in a differentiated manner.

Keywords: for, while

Computers are extremely fast—they execute billions of instructions per second. Now imagine a world without a way of executing the same code snippet multiple times (with modified input). A program that runs only for a day would have to consists of trillions of lines of code (otherwise it would quickly run out of code to be executed). And the code would look like a mess because it would be highly redundant and not readable.

To allow for repeated execution of similar code snippets, Python (like any other major programming language) allows for two types of loops: for loops and while loops. This way, you can easily write a program consisting only of two lines of code that executes forever. It’s hard to do this without loops–the only alternative is recursion.

# For loop declaration
for i in [0, 1, 2]:
   print(i)

'''
0
1
2
'''

# While loop - same semantics
j = 0
while j < 3:
   print(j)
   j = j + 1

'''
0
1
2
'''

Both loop variants achieve the same thing: they print the integers 0, 1, and 2 to the shell. The loops accomplish this in two different ways. The for loop repeatedly executes the loop body by declaring a loop variable i that iteratively takes on all values in the list [0, 1, 2]. The while loop executes the loop body as long as a certain condition is met—in our case j < 3.

Keyword: break

There are two fundamental ways of terminating a loop: (i) define a loop condition that evaluates to False, or (ii) use the keyword break at the exact position in the loop body. The following code snippet shows an example of the latter.

while True:
   break # no infinite loop

print("hello world")
# hello world

We create a while loop with a loop condition that will always evaluate to True. For example, this is common practice when developing webservers that repeat forever the following procedure: wait for a new web request and serve the request. However, in some cases, you still want to terminate the loop prematurely. In the webserver example, you would stop serving files for security reasons when your server detects that it is under attack. In these cases, you can use the keyword break to immediately stop the loop and execute the code that follows. In the example, the code executes print(“hello world”) after the loop ends prematurely.

Keyword: continue

The break statement is not the only statement that allows you to modify the execution flow of Python loops. It is also possible to force the Python interpreter to skip certain areas in the loop while not ending it prematurely. In the previously considered web server example, you may just want to skip malicious web requests instead of halting the server completely. This can be achieved using the continue statement that finishes the current loop iteration and brings the execution flow back to the loop condition.

while True:
  continue
  print("43") # dead code 

The code executes forever without executing the print statement once. The reason is that the continue statement finishes the current loop iteration. The effect of using the continue statement in this way is that there exists dead code that will never be executed.  That’s why the continue statement (as well as the break statement) is commonly used under a certain condition by using a conditional if-else environment.

Keyword: in

This keyword checks whether a certain element exists in a given sequence or container type.

print(42 in [2, 39, 42]) 
# True

print("21" in {"2", "39", "42"}) 
# False

The code snippet shows that the keyword in can be used to u test membership of an integer value 42 in a list of integer values or to v test membership of a string value “21” in a set of strings.

Keyword: is

Beginners in Python are often confused about the exact meaning of the keyword is. However, if you take the time to properly understand it now, you won’t belong to this group for long. The keyword simply checks whether both variables refer to the same object in memory.

y = x = 3

print(x is y)
# True

print([3] is [3])
# False

If you create two lists—even if they contain the same elements—they still refer to two different list objects in memory. Modifying one list object does not affect the other list object. We say that lists are mutable because they can be modified after creation. Therefore, if you check whether one list refers to the same object in memory, the result is False. However, integer values are immutable so there is no risk of one variable changing the object which will then accidentally change all other variables. The reason is that you cannot change the integer object 3—trying it will only create a new integer object and leave the old one unmodified.

Keyword: return

The keyword return terminates the execution of a function and passes the flow of execution to the caller of the function. An optional value after the return keyword specifies the function result.

def appreciate(x, percentage):
   return x + x * percentage / 100


print(appreciate(10000, 5))
# 10500.0

We create a function appreciate() that calculates how much a given investment appreciates at a given percentage of return. To this end, we use the keyword return to specify the result of the function as the sum of the original investment and the nominal return in one unit of time. The return value of the function appreciate() is of type float.

Keyword: None

The keyword None is a Python constant with the meaning “the absence of a value”. Other programming languages such as Java use the value null instead. But the term null often confuses beginners assuming it’s equal to the integer value 0. Instead, Python uses the keyword None to indicate that it’s a different value than any numerical value for zero, an empty list, or an empty string. An interesting fact is that the value None is of its own data type.

def f():
   x = 2


print(f() is None)
# True

print("" == None)
# False

print(0 == None)
# False

The code snippet shows several examples of the None data value (and what it is not). If you don’t define a return value for a function, the default return value is None. However, the value None is different from the empty string or the numerical zero value.

Keyword: lambda

The keyword lambda is used to define lambda functions in Python. Lambda functions are anonymous functions that are not defined in the namespace (roughly speaking: they have no names). The syntax is:

lambda <arguments> : <return expression>

The lambda function can have one or multiple arguments (comma-separated). After the colon (:), you define the return expression that may (or may not) use the defined argument. It can be any expression or even another function.

Lambda functions are very important in Python. You’ll see them a lot in practical code projects: for example to make code shorter and more concise, or to create arguments of various Python functions (such as map() or reduce()).

print((lambda x: x + 3)(3))
# 6

Consider the code. First, we create a lambda function that takes value x and returns the result of the expression x + 3. The result is a function object that can be called like any other function. Because of its semantics, we denote this function as incrementor function. Second, when calling this incrementor function with the argument x=3, the result is the integer value 6.

Python Basic Data Structures

At this point, you’ve learned about the Python keywords which I view as the bare minimum every Python coder must know. However, writing code is more than using keywords correctly. Source code operates on data. But data can be represented in various ways—a thorough understanding of data structures is one of the most fundamental skills you can acquire as a programmer. It will help you in every single of your future endeavors—no matter whether you create machine learning projects, work on large codebases, set up and manage websites, or write algorithms. Data structures are fundamental to those areas.

The Boolean Data Type

A variable of type Boolean can only take two values—either True or False. You have already studied both keywords above.

## 1. Boolean Operations
x, y = True, False

print(x and not y)
# True

print(not x and y or x)
# True

## 2. If condition evaluates to False
if None or 0 or 0.0 or '' or [] or {} or set():
    print("Dead code") # Not reached

The code snippet shows two important points: First, Boolean operators are ordered by priority—the operator not has the highest priority, followed by the operator and, followed by the operator or. Second, the following values are evaluated to the Boolean value False: the keyword None, the integer value 0, the float value 0.0, empty strings, or empty container types.

Numerical Data Types

The two most important numerical data types are integer and float. An integer is a positive or negative number without floating point (for example 3). A float is a positive or negative number with floating point precision (for example 3.14159265359). Python offers a wide variety of built-in numerical operations, as well as functionality to convert between those numerical data types. Study the examples carefully to master these highly important numerical operations.

## Arithmetic Operations
x, y = 3, 2
print(x + y) # = 5
print(x - y) # = 1
print(x * y) # = 6
print(x / y) # = 1.5
print(x // y) # = 1
print(x % y) # = 1
print(-x) # = -3
print(abs(-x)) # = 3
print(int(3.9)) # = 3
print(float(3)) # = 3.0
print(x ** y) # = 9

Most of the operators are self-explaining. Note that the // operator performs integer division. The result is an integer value that is rounded toward the smaller integer number (for example 3 // 2 == 1).

The String Data Type

Python strings are sequences of characters. Strings are immutable so they cannot be changed, once created. There are five main ways to create strings:

  • Single quotes: ‘Yes’.
  • Double quotes: “Yes”.
  • Triple quotes (for multi-line string): ”’Yes”” or “””Yes”””.
  • The string method: str(5) == ‘5’ is True.
  • Concatenation: ‘Py’ + ‘thon’ becomes ‘Python’.

While there are other ways, these are the five most commonly used.

Oftentimes, you want to explicitly use whitespace characters in strings. These are the most important ones: the newline character ‘\n’, the space character ‘\s’, and the tab character ‘\t’.

The following code snippet shows the most important string methods.

## Most Important String Methods
y = "    This is lazy\t\n   "

print(y.strip())
# Remove Whitespace: 'This is lazy'

print("DrDre".lower())
# Lowercase: 'drdre'

print("attention".upper())
# Uppercase: 'ATTENTION'

print("smartphone".startswith("smart"))
# True

print("smartphone".endswith("phone"))
# True

print("another".find("other"))
# Match index: 2

print("cheat".replace("ch", "m"))
# meat

print(','.join(["F", "B", "I"]))
# F,B,I

print(len("Rumpelstiltskin"))
# String length: 15

print("ear" in "earth")
# Contains: True

This non-exclusive list of string methods shows that the string data type is very powerful in Python and you can solve many common string problems with built-in Python functionality. If in doubt about how to achieve a certain result regarding string problems, consult the online reference listing all built-in string methods.

Python Container Data Structures

In the last section, you’ve learned about the basic Python data types. But Python also ships with so-called container data types that handle complex operations efficiently while being easy to use.

List

The list is a container data type that stores a sequence of elements. Unlike strings, lists are mutable. This means that you can modify them at runtime. The use of the list data type is best described with a series of examples:

l = [1, 2, 2]
print(len(l))
# 3

This code snippet shows how to create a list and how to populate it with three integer elements. You can also see that some elements may arise multiple times in a single list. The len() function returns the number of elements in a list.

Adding Elements

There are three common ways of adding elements to a list: append, insert, or list concatenation.

# 1. Append
l = [1, 2, 2]
l.append(4)
print(l)
# [1, 2, 2, 4]

# 2. Insert
l = [1, 2, 4]
l.insert(2,2)
print(l)
# [1, 2, 2, 4]

# 3. List Concatenation
print([1, 2, 2] + [4])
# [1, 2, 2, 4]

All operations generate the same list [1, 2, 2, 4] but the append operation is the fastest because it neither has to traverse the list to insert an element at the correct position (such as insert), nor create a new list out of two sublists (such as list concatenation). Note that a fourth method is extend() which allows you to append multiple elements to the given list in an efficient manner.

Removing Elements

Removing an element x from a list can be easily achieved using the list method list.remove(x):

l = [1, 2, 2, 4]
l.remove(1)
print(l)
# [2, 2, 4]

Note that the method operates on the list object itself—no new list is created.

Reversing Lists

You can reverse the order of the list elements using the method list.reverse().

l = [1, 2, 2, 4]
l.reverse()
print(l)
# [4, 2, 2, 1]

Much like the method to remove an element from a list, reversing the list modifies the original list object and does not merely create a new list object.

Sorting Lists

You can sort the list elements using the method list.sort().

l = [2, 1, 4, 2]
l.sort()
print(l)
# [1, 2, 2, 4]

Again, sorting the list modifies the original list object. The resulting list is sorted in an ascending manner. You can also specify a key function and pass it as the parameter key to the sort() method to customize the sorting behavior. This way, you can also sort lists of custom objects (for example, sort a list of customer objects regarding their age). The key function simply transforms one list element into an element that is sortable (such as an integer, float, or string element).

Indexing List Elements

You can determine the index of a specified list element x using the method list.index(x).

print([2, 2, 4].index(2))
# 0

print([2, 2, 4].index(2,1))
# 1

The method index(x) finds the first occurrence of the element x in the list and returns its index.

Stack

The stack data structure is a natural way of storing data items. Much like an unstructured person handles their paperwork: first in, first out. Every new paper is placed at the top of a stack of papers. When working through the stack, they remove the topmost paper from the stack. As a result, the paper at the bottom never sees the daylight. While this application does not seem to be a favorable way of using the stack data structure, the stack is still an extremely important fundamental data structure in computer science used in operating system management, algorithms, syntax parsing, and backtracking.

Python lists can be used intuitively as stacks via the two list operations append() and pop():

stack = [3]
stack.append(42) # [3, 42]
stack.pop() # 42 (stack: [3])
stack.pop() # 3 (stack: [])

Due to the efficiency of the list implementation, there is usually no need to import external stack libraries.

Set

The set data structure is one of the basic collection data types in Python and many other programming languages. There are even popular languages for distributed computing that focus almost exclusively on set operations (like MapReduce or Apache Spark) as programming primitives. So what is a set exactly?

Definition: A set is an unordered collection of unique elements.

Let’s break this definition into its main pieces.

(1) Collection: A set is a collection of elements like a list or a tuple. The collection consists of either primitive elements (e.g. integers, floats, strings), or complex elements (e.g. objects, tuples). However, all data types must be hashable (a hash value of an object does never change and is used to compare the object to other objects). Let’s have a look at an example.

hero = "Harry"
guide = "Dumbledore"
enemy = "Lord V."
print(hash(hero))
# 6175908009919104006

print(hash(guide))
# -5197671124693729851

## Can we create a set of strings?
characters = {hero, guide, enemy}
print(characters)
# {'Lord V.', 'Dumbledore', 'Harry'}

## Can we create a set of lists?
team_1 = [hero, guide]
team_2 = [enemy]
teams = {team_1, team_2}
# TypeError: unhashable type: 'list'

As you can see, we can create a set of strings because strings are hashable. But we cannot create a set of lists because lists are unhashable. The reason is that lists are mutable: you can change a list by appending or removing elements. If you change the list data type, the hash value changes (it is calculated based on the content of the list). This violates the above definition (the hash value does not change). As mutable data types are not hashable, you cannot use them in sets.

(2) Unordered: Unlike lists, sets are unordered because there is no fixed order of the elements. In other words, regardless of the order in which you put stuff into the set, you can never be sure in which order the set stores these elements. Here is an example:

characters = {hero, guide, enemy}
print(characters)
# {'Lord V.', 'Dumbledore', 'Harry'}

You put in the hero first, but my interpreter prints the enemy first (the Python interpreter is on the dark side, obviously). Note that your interpreter may print yet another order of the set elements.

(3) Unique: All elements in the set are unique. Each pair of values (x,y) in the set produces a different pair of hash values (hash(x)!=hash(y)). Hence, every two elements x and y in the set are different—as a result, we cannot create an army of Harry Potter clones to fight Lord V:

clone_army = {hero, hero, hero, hero, hero, enemy}
print(clone_army)
# {'Lord V.', 'Harry'}

No matter how often you put the same value into the same set, the set stores only one instance of this value. Note that an extension of the normal set data structure is the multiset data structure that can store multiple instances of the same value. However, it is seldom used in practice, so I don’t introduce it here.

Dictionary

The dictionary is a useful data structure for storing (key, value) pairs.

calories = {'apple' : 52, 'banana' : 89, 'choco' : 546}

You can read and write elements by specifying the key within brackets.

print(calories['apple'] < calories['choco'])
# True

calories['cappu'] = 74

print(calories['banana'] < calories['cappu'])
# False

Use the keys() and values() functions to access all keys and values of the dictionary.

print('apple' in calories.keys())
# True

print(52 in calories.values())
# True

Access the (key, value) pairs of a dictionary with the items() method.

for k, v in calories.items():
    print(k) if v > 500 else None
# 'choco'

This way, it’s easy to iterate over all keys and all values in a dictionary without accessing those individually.

Membership

Check with the keyword in whether the set, list, or dictionary contains an element. Note that set containment is faster than list containment.

basket = {'apple', 'eggs', 'banana', 'orange'}

print('eggs' in basket)
# True

print('mushroom' in basket)
# False

List and Set Comprehension

List comprehension is a popular Python feature that helps you to create lists. The simple formula is [ expression + context ].

Expression: What to do with each list element?

Context: What list elements to select? The context consists of an arbitrary number of for and if statements.

For example, the list comprehension statement [x for x in range(3)] creates the list [0, 1, 2]. Another example is the following:

# (name, $-income)
customers = [("John", 240000),
             ("Alice", 120000),
             ("Ann", 1100000),
             ("Zach", 44000)]

# your high-value customers earning >$1M
whales = [x for x,y in customers if y>1000000]
print(whales)
# ['Ann']

Set comprehension is like list comprehension but creates a set rather than a list.

Summary

This article gave you a concise Python crash course to refresh your basic Python education. You studied the most important Python keywords and how to use them in code examples. As a result, you learned how to control the program execution flow using if-elif-else statements, as well as the while and the for loop. Moreover, you revisited the basic data types in Python—Boolean, integer, float, and string—and which built-in operations and functions are commonly used in practice. Most code snippets in practice and non-trivial algorithms are built around more powerful container types such as lists, stacks, sets, and dictionaries. By studying the given examples, you learned how to add, remove, insert, and reorder elements. Finally, you learned about membership operators and list comprehension: an efficient and powerful built-in method to create lists programmatically in Python.


I wrote this 5000word article for my upcoming book “Python One-Liners” with the San Francisco-based publisher NoStarch. Until the book launches (end of 2019), consider buying my other books to level up your skill level!

Coffee Break Python

Leave a Comment