Python cheatsheet#

Inspired by A Whirlwind Tour of Python and another Python Cheatsheet.

Only covers Python 3.

import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Basics#

# Print statement
print("Hello World!")  # Python 3 - No parentheses in Python 2

# Optional separator
print(1, 2, 3)  
print(1, 2, 3, sep='--')  

# Variables (dynamically typed)
mood = "happy"  # or 'happy'

print("I'm", mood)
Hello World!
1 2 3
1--2--3
I'm happy

String formatting#

# https://realpython.com/python-f-strings/
# https://cito.github.io/blog/f-strings/

name = "Garance"
age = 11

message = "My name is %s and I'm %s years old." % (name, age)  # Original language syntax
print(message)
message = "My name is {} and I'm {} years old.".format(name, age)  # Python 2.6+
print(message)
message = f"My name is {name} and I'm {age} years old."  # Python 3.6+
print(message)
My name is Garance and I'm 11 years old.
My name is Garance and I'm 11 years old.
My name is Garance and I'm 11 years old.

Numbers and arithmetic#

# Type: int
a = 4

# Type: float
b = 3.14

a, b = b, a
print(a, b)

print(13 / 2)  
print(13 // 2)  

# Exponential operator
print(3 ** 2) 
print(2 ** 3)  
3.14 4
6.5
6
9
8

Flow control#

The if/elif/else statement#

name = 'Bob'
age = 30
if name == 'Alice':
    print('Hi, Alice.')
elif age < 12:
    print('You are not Alice, kiddo.')
else:
    print('You are neither Alice nor a little kid.')
You are neither Alice nor a little kid.

The while loop#

num = 1

while num <= 10:
    print(num)
    num += 1
1
2
3
4
5
6
7
8
9
10

The for/else loop#

The optional elsestatement is only useful when a break condition can occur in the loop:

for i in [1, 2, 3, 4, 5]:
    if i == 3:
        print(i)
        break
else:
    print("No item of the list is equal to 3")
3

Data structures#

Lists#

countries = ["France", "Belgium", "India"]

print(len(countries))  
print(countries[0])  
print(countries[-1])  

# Add element at end of list
countries.append("Ecuador")

print(countries)
3
France
India
['France', 'Belgium', 'India', 'Ecuador']

List indexing and slicing#

spam = ['cat', 'bat', 'rat', 'elephant']

print(spam[1:3])  
print(spam[0:-1]) 
print(spam[:2])   
print(spam[1:])   
print(spam[:])    
print(spam[::-1]) 
['bat', 'rat']
['cat', 'bat', 'rat']
['cat', 'bat']
['bat', 'rat', 'elephant']
['cat', 'bat', 'rat', 'elephant']
['elephant', 'rat', 'bat', 'cat']

Tuples#

Contrary to lists, tuples are immutable (read-only).

eggs = ('hello', 42, 0.5)

print(eggs[0])
print(eggs[1:3])

# TypeError: a tuple is immutable
# eggs[0] = 'bonjour'
hello
(42, 0.5)

Dictionaries#

numbers = {'one':1, 'two':2, 'three':3}

numbers['ninety'] = 90
print(numbers)

for key, value in numbers.items():
    print(f'{key} => {value}')
{'one': 1, 'two': 2, 'three': 3, 'ninety': 90}
one => 1
two => 2
three => 3
ninety => 90

Sets#

A set is an unordered collection of unique items.

# Duplicate elements are automatically removed
s = {1, 2, 3, 2, 3, 4}
print(s)
{1, 2, 3, 4}

Union, intersection and difference of sets#

primes = {2, 3, 5, 7}
odds = {1, 3, 5, 7, 9}

print(primes | odds)
print(primes & odds)
print(primes - odds)
{1, 2, 3, 5, 7, 9}
{3, 5, 7}
{2}

Functions#

Function definition and function call#

def square(x):
    """ Returns the square of x """
    
    return x ** 2

# Print function docstring
help(square)

print(square(0))
print(square(3))
Help on function square in module __main__:

square(x)
    Returns the square of x

0
9

Default function parameters#

def fibonacci(n, a=0, b=1):
    """ Returns a list of the n first Fibonacci numbers"""

    l = []
    while len(l) < n:
        a, b = b, a + b
        l.append(a)
    return l

print(fibonacci(7))
[1, 1, 2, 3, 5, 8, 13]

Flexible function arguments#

def catch_all(*args, **kwargs):
    print("args =", args)
    print("kwargs = ", kwargs)
    
catch_all(1, 2, 3, a=10, b='hello')
args = (1, 2, 3)
kwargs =  {'a': 10, 'b': 'hello'}

Lambda (anonymous) functions#

add = lambda x, y: x + y

print(add(1, 2))
3

Iterators#

A unified interface#

for element in [1, 2, 3]:
    print(element)
for element in (4, 5, 6):
    print(element)
for key in {'one':1, 'two':2}:
    print(key)
for char in "baby":
    print(char)
1
2
3
4
5
6
one
two
b
a
b
y

Under the hood#

  • An iterable is a object that has an __iter__ method which returns an iterator to provide iteration support.

  • An iterator is an object with a __next__ method which returns the next iteration element.

  • A sequence is an iterable which supports access by integer position. Lists, tuples, strings and range objects are examples of sequences.

  • A mapping is an iterable which supports access via keys. Dictionaries are examples of mappings.

  • Iterators are used implicitly by many looping constructs.

The range() function#

It doesn’t return a list, but a rangeobject (which exposes an iterator).

for i in range(10):
    if i % 2 == 0:
        print(f"{i} is even")
    else:
        print(f"{i} is odd")
0 is even
1 is odd
2 is even
3 is odd
4 is even
5 is odd
6 is even
7 is odd
8 is even
9 is odd
for i in range(0, 10, 2):
    print(i)
0
2
4
6
8
for i in range(5, -1, -1):
    print(i)
5
4
3
2
1
0

The enumerate() function#

supplies = ['pens', 'staplers', 'flame-throwers', 'binders']

for i, supply in enumerate(supplies):
    print(f'Index {i} in supplies is: {supply}')
Index 0 in supplies is: pens
Index 1 in supplies is: staplers
Index 2 in supplies is: flame-throwers
Index 3 in supplies is: binders

Comprehensions#

Principle#

  • Provide a concise way to create sequences.

  • General syntax: [expr for var in iterable].

List comprehensions#

# Using explicit code
L = []
for n in range(12):
    L.append(n ** 2)
print(L)

# Using a list comprehension
[n ** 2 for n in range(12)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121]

Set and dictionary comprehensions#

# Create an uppercase set
s = {"abc", "def"}
print({e.upper() for e in s})

# Obtains modulos of 4 (elimitaing duplicates)
print({a % 4 for a in range(1000)})

# Switch keys and values
d = {'name': 'Prosper', 'age': 7}
print({v: k for k, v in d.items()})
{'ABC', 'DEF'}
{0, 1, 2, 3}
{'Prosper': 'name', 7: 'age'}

Generators#

Principle#

  • A generator defines a recipe for producing values.

  • A generator does not actually compute the values until they are needed.

  • It exposes an iterator interface. As such, it is a basic form of iterable.

  • It can only be iterated once.

Generators expressions#

They use parentheses, not square brackets like list comprehensions.

G1 = (n ** 2 for n in range(12))

print(list(G1))
print(list(G1))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121]
[]

Generator functions#

  • A function that, rather than using return to return a value once, uses yield to yield a (potentially infinite) sequence of values.

  • Useful when the generator algorithm gets complicated.

def gen():
    for n in range(12):
        yield n ** 2

G2 = gen()
print(list(G2))
print(list(G2))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121]
[]

Object-oriented programming#

Classes and objects#

class Vehicle:
    def __init__(self, number_of_wheels, type_of_tank):
        self.number_of_wheels = number_of_wheels
        self.type_of_tank = type_of_tank
        
    @property
    def number_of_wheels(self):
        return self.__number_of_wheels
    
    @number_of_wheels.setter
    def number_of_wheels(self, number):
        self.__number_of_wheels = number

    def make_noise(self):
        print('VRUUUUUUUM')
        
tesla_model_s = Vehicle(4, 'electric')
tesla_model_s.number_of_wheels = 2 # setting number of wheels to 2
print(tesla_model_s.number_of_wheels)
tesla_model_s.make_noise()
2
VRUUUUUUUM

Class and instance attributes#

class Employee:
   empCount = 0

   def __init__(self, name, salary):
      self._name = name
      self._salary = salary
      Employee.empCount += 1
   
   def count():
     return f'Total employees: {Employee.empCount}'

   def description(self):
      return f'Name: {self._name}, salary: {self._salary}'

e1 = Employee('Ben', '30')
print(e1.description())
print(Employee.count())
Name: Ben, salary: 30
Total employees: 1

Inheritance#

class Animal:
    def __init__(self, species):
        self.species = species

class Dog(Animal):
    def __init__(self, name):
        Animal.__init__(self, 'Mammal')
        self.name = name

doggo = Dog('Fang')
print(doggo.name)
print(doggo.species)
Fang
Mammal

Modules and packages#

# Importing all module content into a namespace
import math
print(math.cos(math.pi))  # -1.0

# Aliasing an import
import numpy as np
print(np.cos(np.pi))  # -1.0

# Importing specific module content into local namespace
from math import cos, pi
print(cos(pi))  # -1.0

# Importing all module content into local namespace (use with caution)
from math import *
print(sin(pi) ** 2 + cos(pi) ** 2)  # 1.0
-1.0
-1.0
-1.0
1.0