Quick Python Guide¶
Printing Message¶
# To print something
print("Hello World!")
Hello World!
Variables¶
# Create a variable called `a` and store value
a = 10
print(a)
10
# Create a variable called `b` and store value
b = 10.5
print(b)
10.5
# Create a variable called `name` and store value
name = "Datastics Lab"
print(name)
Datastics Lab
Reserved Keywords => Don’t use as a variable name¶
import keyword
print(keyword.kwlist)
['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']
Imports¶
# 'generic import' of math module
import math
math.sqrt(25)
5.0
# import a function
from math import sqrt
sqrt(25) # no longer have to reference the module
5.0
# import multiple functions at once
from math import cos, floor
# import all functions in a module (generally discouraged)
from csv import *
# define an alias / nickname
import datetime as dt
# import numpy as np(nickname)
import numpy as np
# show all functions in math module
print(dir(math))
['__doc__', '__name__', '__package__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'hypot', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'trunc']
Data Types¶
Determine the type of an object:
type(2)
int
type(2.0)
float
type('two')
str
type(True)
bool
type(None)
NoneType
Check if an object is of a given type:
isinstance(2.0, int)
False
isinstance(2.0, (int, float))
True
Convert an object to a given type:
float(2)
2.0
int(2.9)
2
str(2.9)
'2.9'
Zero, None
, and empty containers are converted to False
:
bool(0)
False
bool(None)
False
bool('') # empty string
False
bool([]) # empty list
False
bool({}) # empty dictionary
False
Non-empty containers and non-zeros are converted to True
:
bool(2)
True
bool('two')
True
bool([2])
True
Data Type Conversion¶
# float to integer
a = 5.25
int(a)
5
# integer to float
b = 5
float(b)
5.0
# integer to string
c = 5
str(c)
'5'
# string to integer
d = '5'
str(d)
'5'
# character to integer
s = 'a'
ord(s)
97
# integer to character
i = 97
chr(i)
'a'
3. Math¶
10 + 4
14
10 - 4
6
10 * 4
40
10 ** 4 # exponent
10000
5 % 4 # modulo - computes the remainder
1
# Python 2: returns 2 (because both types are 'int')
# Python 3: returns 2.5
10 / 4
2
10 / float(4)
2.5
Comparisons and Boolean Operations¶
Assignment statement:
x = 5
Comparisons:
x > 3
True
x >= 3
True
x != 3
True
x == 5
True
Boolean operations:
5 > 3 and 6 > 3
True
5 > 3 or 5 < 3
True
not False
True
False or not False and True # evaluation order: not, and, or
True
Conditional Statements¶
# if statement
if x > 0:
print('positive')
positive
# if/else statement
if x > 0:
print('positive')
else:
print('zero or negative')
positive
# if/elif/else statement
if x > 0:
print('positive')
elif x == 0:
print('zero')
else:
print('negative')
positive
# single-line if statement (sometimes discouraged)
if x > 0: print('positive')
positive
# single-line if/else statement (sometimes discouraged), known as a 'ternary operator'
'positive' if x > 0 else 'zero or negative'
'positive'
Lists¶
List properties: ordered, iterable, mutable, can contain multiple data types
# create an empty list (two ways)
empty_list = []
empty_list = list()
# create a list
simpsons = ['homer', 'marge', 'bart']
Examine a list:
# print element 0
simpsons[0]
'homer'
len(simpsons)
3
Modify a list (does not return the list):
# append element to end
simpsons.append('lisa')
simpsons
['homer', 'marge', 'bart', 'lisa']
# append multiple elements to end
simpsons.extend(['itchy', 'scratchy'])
simpsons
['homer', 'marge', 'bart', 'lisa', 'itchy', 'scratchy']
# insert element at index 0 (shifts everything right)
simpsons.insert(0, 'maggie')
simpsons
['maggie', 'homer', 'marge', 'bart', 'lisa', 'itchy', 'scratchy']
# search for first instance and remove it
simpsons.remove('bart')
simpsons
['maggie', 'homer', 'marge', 'lisa', 'itchy', 'scratchy']
# remove element 0 and return it
simpsons.pop(0)
'maggie'
# remove element 0 (does not return it)
del simpsons[0]
simpsons
['marge', 'lisa', 'itchy', 'scratchy']
# replace element 0
simpsons[0] = 'krusty'
simpsons
['krusty', 'lisa', 'itchy', 'scratchy']
# concatenate lists (slower than 'extend' method)
neighbors = simpsons + ['ned', 'rod', 'todd']
neighbors
['krusty', 'lisa', 'itchy', 'scratchy', 'ned', 'rod', 'todd']
Find elements in a list:
# counts the number of instances
simpsons.count('lisa')
1
# returns index of first instance
simpsons.index('itchy')
2
List slicing:
weekdays = ['mon', 'tues', 'wed', 'thurs', 'fri']
# element 0
weekdays[0]
'mon'
# elements 0 (inclusive) to 3 (exclusive)
weekdays[0:3]
['mon', 'tues', 'wed']
# starting point is implied to be 0
weekdays[:3]
['mon', 'tues', 'wed']
# elements 3 (inclusive) through the end
weekdays[3:]
['thurs', 'fri']
# last element
weekdays[-1]
'fri'
# every 2nd element (step by 2)
weekdays[::2]
['mon', 'wed', 'fri']
# backwards (step by -1)
weekdays[::-1]
['fri', 'thurs', 'wed', 'tues', 'mon']
# alternative method for returning the list backwards
list(reversed(weekdays))
['fri', 'thurs', 'wed', 'tues', 'mon']
Sort a list in place (modifies but does not return the list):
simpsons.sort()
simpsons
['itchy', 'krusty', 'lisa', 'scratchy']
# sort in reverse
simpsons.sort(reverse=True)
simpsons
['scratchy', 'lisa', 'krusty', 'itchy']
# sort by a key
simpsons.sort(key=len)
simpsons
['lisa', 'itchy', 'krusty', 'scratchy']
Return a sorted list (does not modify the original list):
sorted(simpsons)
['itchy', 'krusty', 'lisa', 'scratchy']
sorted(simpsons, reverse=True)
['scratchy', 'lisa', 'krusty', 'itchy']
sorted(simpsons, key=len)
['lisa', 'itchy', 'krusty', 'scratchy']
Insert into an already sorted list, and keep it sorted:
num = [10, 20, 40, 50]
from bisect import insort
insort(num, 30)
num
[10, 20, 30, 40, 50]
Object references and copies:
# create a second reference to the same list
same_num = num
# modifies both 'num' and 'same_num'
same_num[0] = 0
print(num)
print(same_num)
[0, 20, 30, 40, 50]
[0, 20, 30, 40, 50]
# copy a list (two ways)
new_num = num[:]
new_num = list(num)
Examine objects:
num is same_num # checks whether they are the same object
True
num is new_num
False
num == same_num # checks whether they have the same contents
True
num == new_num
True
Tuples¶
Tuple properties: ordered, iterable, immutable, can contain multiple data types
Like lists, but they don’t change size
# create a tuple directly
digits = (0, 1, 'two')
# create a tuple from a list
digits = tuple([0, 1, 'two'])
# trailing comma is required to indicate it's a tuple
zero = (0,)
Examine a tuple:
digits[2]
'two'
len(digits)
3
# counts the number of instances of that value
digits.count(0)
1
# returns the index of the first instance of that value
digits.index(1)
1
Modify a tuple:
# elements of a tuple cannot be modified (this would throw an error)
# digits[2] = 2
# concatenate tuples
digits = digits + (3, 4)
digits
(0, 1, 'two', 3, 4)
Other tuple operations:
# create a single tuple with elements repeated (also works with lists)
(3, 4) * 2
(3, 4, 3, 4)
# sort a list of tuples
tens = [(20, 60), (10, 40), (20, 30)]
sorted(tens) # sorts by first element in tuple, then second element
[(10, 40), (20, 30), (20, 60)]
# tuple unpacking
bart = ('male', 10, 'simpson') # create a tuple
(sex, age, surname) = bart # assign three values at once
print(sex)
print(age)
print(surname)
male
10
simpson
Strings¶
String properties: iterable, immutable
# convert another data type into a string
s = str(42)
s
'42'
# create a string directly
s = 'I like you'
Examine a string:
s[0]
'I'
len(s)
10
String slicing is like list slicing:
s[:6]
'I like'
s[7:]
'you'
s[-1]
'u'
Basic string methods (does not modify the original string):
s.lower()
'i like you'
s.upper()
'I LIKE YOU'
s.startswith('I')
True
s.endswith('you')
True
# checks whether every character in the string is a digit
s.isdigit()
False
# returns index of first occurrence, but doesn't support regex
s.find('like')
2
# returns -1 since not found
s.find('hate')
-1
# replaces all instances of 'like' with 'love'
s.replace('like', 'love')
'I love you'
Split a string:
# split a string into a list of substrings separated by a delimiter
s.split(' ')
['I', 'like', 'you']
# equivalent (since space is the default delimiter)
s.split()
['I', 'like', 'you']
s2 = 'a, an, the'
s2.split(',')
['a', ' an', ' the']
Join or concatenate strings:
# join a list of strings into one string using a delimiter
stooges = ['larry', 'curly', 'moe']
' '.join(stooges)
'larry curly moe'
# concatenate strings
s3 = 'The meaning of life is'
s4 = '42'
s3 + ' ' + s4
'The meaning of life is 42'
Remove whitespace from the start and end of a string:
s5 = ' ham and cheese '
s5.strip()
'ham and cheese'
String substitutions:
# old way
'raining %s and %s' % ('cats', 'dogs')
'raining cats and dogs'
# new way
'raining {} and {}'.format('cats', 'dogs')
'raining cats and dogs'
# new way (using named arguments)
'raining {arg1} and {arg2}'.format(arg1='cats', arg2='dogs')
'raining cats and dogs'
String formatting (more examples):
# use 2 decimal places
'pi is {:.2f}'.format(3.14159)
'pi is 3.14'
Normal strings versus raw strings:
# normal strings allow for escaped characters
print('first line\nsecond line')
first line
second line
# raw strings treat backslashes as literal characters
print(r'first line\nfirst line')
first line\nfirst line
Dictionaries¶
Dictionary properties: unordered, iterable, mutable, can contain multiple data types
Made of key-value pairs
Keys must be unique, and can be strings, numbers, or tuples
Values can be any type
# create an empty dictionary (two ways)
empty_dict = {}
empty_dict = dict()
# create a dictionary (two ways)
family = {'dad':'homer', 'mom':'marge', 'size':6}
family = dict(dad='homer', mom='marge', size=6)
family
{'dad': 'homer', 'mom': 'marge', 'size': 6}
# convert a list of tuples into a dictionary
list_of_tuples = [('dad', 'homer'), ('mom', 'marge'), ('size', 6)]
family = dict(list_of_tuples)
family
{'dad': 'homer', 'mom': 'marge', 'size': 6}
Examine a dictionary:
# pass a key to return its value
family['dad']
'homer'
# return the number of key-value pairs
len(family)
3
# check if key exists in dictionary
'mom' in family
True
# dictionary values are not checked
'marge' in family
False
# returns a list of keys (Python 2) or an iterable view (Python 3)
family.keys()
['dad', 'mom', 'size']
# returns a list of values (Python 2) or an iterable view (Python 3)
family.values()
['homer', 'marge', 6]
# returns a list of key-value pairs (Python 2) or an iterable view (Python 3)
family.items()
[('dad', 'homer'), ('mom', 'marge'), ('size', 6)]
Modify a dictionary (does not return the dictionary):
# add a new entry
family['cat'] = 'snowball'
family
{'cat': 'snowball', 'dad': 'homer', 'mom': 'marge', 'size': 6}
# edit an existing entry
family['cat'] = 'snowball ii'
family
{'cat': 'snowball ii', 'dad': 'homer', 'mom': 'marge', 'size': 6}
# delete an entry
del family['cat']
family
{'dad': 'homer', 'mom': 'marge', 'size': 6}
# dictionary value can be a list
family['kids'] = ['bart', 'lisa']
family
{'dad': 'homer', 'kids': ['bart', 'lisa'], 'mom': 'marge', 'size': 6}
# remove an entry and return the value
family.pop('dad')
'homer'
# add multiple entries
family.update({'baby':'maggie', 'grandpa':'abe'})
family
{'baby': 'maggie',
'grandpa': 'abe',
'kids': ['bart', 'lisa'],
'mom': 'marge',
'size': 6}
Access values more safely with get
:
family['mom']
'marge'
# equivalent to a dictionary lookup
family.get('mom')
'marge'
# this would throw an error since the key does not exist
# family['grandma']
# return None if not found
family.get('grandma')
# provide a default return value if not found
family.get('grandma', 'not found')
'not found'
Access a list element within a dictionary:
family['kids'][0]
'bart'
family['kids'].remove('lisa')
family
{'baby': 'maggie',
'grandpa': 'abe',
'kids': ['bart'],
'mom': 'marge',
'size': 6}
String substitution using a dictionary:
'youngest child is %(baby)s' % family
'youngest child is maggie'
Sets¶
Set properties: unordered, iterable, mutable, can contain multiple data types
Made of unique elements (strings, numbers, or tuples)
Like dictionaries, but with keys only (no values)
# create an empty set
empty_set = set()
# create a set directly
languages = {'python', 'r', 'java'}
# create a set from a list
snakes = set(['cobra', 'viper', 'python'])
Examine a set:
len(languages)
3
'python' in languages
True
Set operations:
# intersection
languages & snakes
{'python'}
# union
languages | snakes
{'cobra', 'java', 'python', 'r', 'viper'}
# set difference
languages - snakes
{'java', 'r'}
# set difference
snakes - languages
{'cobra', 'viper'}
Modify a set (does not return the set):
# add a new element
languages.add('sql')
languages
{'java', 'python', 'r', 'sql'}
# try to add an existing element (ignored, no error)
languages.add('r')
languages
{'java', 'python', 'r', 'sql'}
# remove an element
languages.remove('java')
languages
{'python', 'r', 'sql'}
# try to remove a non-existing element (this would throw an error)
# languages.remove('c')
# remove an element if present, but ignored otherwise
languages.discard('c')
languages
{'python', 'r', 'sql'}
# remove and return an arbitrary element
languages.pop()
'python'
# remove all elements
languages.clear()
languages
set()
# add multiple elements (can also pass a set)
languages.update(['go', 'spark'])
languages
{'go', 'spark'}
Get a sorted list of unique elements from a list:
sorted(set([9, 0, 2, 1, 0]))
[0, 1, 2, 9]
Defining Functions¶
Define a function with no arguments and no return values:
def print_text():
print('this is text')
# call the function
print_text()
this is text
Define a function with one argument and no return values:
def print_this(x):
print(x)
# call the function
print_this(3)
3
# prints 3, but doesn't assign 3 to n because the function has no return statement
n = print_this(3)
3
Define a function with one argument and one return value:
def square_this(x):
return x**2
# include an optional docstring to describe the effect of a function
def square_this(x):
"""Return the square of a number."""
return x**2
# call the function
square_this(3)
9
# assigns 9 to var, but does not print 9
var = square_this(3)
Define a function with two ‘positional arguments’ (no default values) and one ‘keyword argument’ (has a default value):
def calc(a, b, op='add'):
if op == 'add':
return a + b
elif op == 'sub':
return a - b
else:
print('valid operations are add and sub')
# call the function
calc(10, 4, op='add')
14
# unnamed arguments are inferred by position
calc(10, 4, 'add')
14
# default for 'op' is 'add'
calc(10, 4)
14
calc(10, 4, 'sub')
6
calc(10, 4, 'div')
valid operations are add and sub
Use pass
as a placeholder if you haven’t written the function body:
def stub():
pass
Return two values from a single function:
def min_max(nums):
return min(nums), max(nums)
# return values can be assigned to a single variable as a tuple
nums = [1, 2, 3]
min_max_num = min_max(nums)
min_max_num
(1, 3)
# return values can be assigned into multiple variables using tuple unpacking
min_num, max_num = min_max(nums)
print(min_num)
print(max_num)
1
3
Anonymous (Lambda) Functions¶
Primarily used to temporarily define a function for use by another function
# define a function the "usual" way
def squared(x):
return x**2
# define an identical function using lambda
squared = lambda x: x**2
Sort a list of strings by the last letter:
# without using lambda
simpsons = ['homer', 'marge', 'bart']
def last_letter(word):
return word[-1]
sorted(simpsons, key=last_letter)
['marge', 'homer', 'bart']
# using lambda
sorted(simpsons, key=lambda word: word[-1])
['marge', 'homer', 'bart']
For Loops and While Loops¶
range
returns a list of integers (Python 2) or a sequence (Python 3):
# includes the start value but excludes the stop value
range(0, 3)
[0, 1, 2]
# default start value is 0
range(3)
[0, 1, 2]
# third argument is the step value
range(0, 5, 2)
[0, 2, 4]
# Python 2 only: use xrange to create a sequence rather than a list (saves memory)
xrange(100, 100000, 5)
xrange(100, 100000, 5)
for
loops:
# not the recommended style
fruits = ['apple', 'banana', 'cherry']
for i in range(len(fruits)):
print(fruits[i].upper())
APPLE
BANANA
CHERRY
# recommended style
for fruit in fruits:
print(fruit.upper())
APPLE
BANANA
CHERRY
# iterate through two things at once (using tuple unpacking)
family = {'dad':'homer', 'mom':'marge', 'size':6}
for key, value in family.items():
print(key, value)
('dad', 'homer')
('mom', 'marge')
('size', 6)
# use enumerate if you need to access the index value within the loop
for index, fruit in enumerate(fruits):
print(index, fruit)
(0, 'apple')
(1, 'banana')
(2, 'cherry')
for
/else
loop:
for fruit in fruits:
if fruit == 'banana':
print('Found the banana!')
break # exit the loop and skip the 'else' block
else:
# this block executes ONLY if the for loop completes without hitting 'break'
print("Can't find the banana")
Found the banana!
while
loop:
count = 0
while count < 5:
print('This will print 5 times')
count += 1 # equivalent to 'count = count + 1'
This will print 5 times
This will print 5 times
This will print 5 times
This will print 5 times
This will print 5 times
Comprehensions¶
List comprehension:
# for loop to create a list of cubes
nums = [1, 2, 3, 4, 5]
cubes = []
for num in nums:
cubes.append(num**3)
cubes
[1, 8, 27, 64, 125]
# equivalent list comprehension
cubes = [num**3 for num in nums]
cubes
[1, 8, 27, 64, 125]
# for loop to create a list of cubes of even numbers
cubes_of_even = []
for num in nums:
if num % 2 == 0:
cubes_of_even.append(num**3)
cubes_of_even
[8, 64]
# equivalent list comprehension
# syntax: [expression for variable in iterable if condition]
cubes_of_even = [num**3 for num in nums if num % 2 == 0]
cubes_of_even
[8, 64]
# for loop to cube even numbers and square odd numbers
cubes_and_squares = []
for num in nums:
if num % 2 == 0:
cubes_and_squares.append(num**3)
else:
cubes_and_squares.append(num**2)
cubes_and_squares
[1, 8, 9, 64, 25]
# equivalent list comprehension (using a ternary expression)
# syntax: [true_condition if condition else false_condition for variable in iterable]
cubes_and_squares = [num**3 if num % 2 == 0 else num**2 for num in nums]
cubes_and_squares
[1, 8, 9, 64, 25]
# for loop to flatten a 2d-matrix
matrix = [[1, 2], [3, 4]]
items = []
for row in matrix:
for item in row:
items.append(item)
items
[1, 2, 3, 4]
# equivalent list comprehension
items = [item for row in matrix
for item in row]
items
[1, 2, 3, 4]
Set comprehension:
fruits = ['apple', 'banana', 'cherry']
unique_lengths = {len(fruit) for fruit in fruits}
unique_lengths
{5, 6}
Dictionary comprehension:
fruit_lengths = {fruit:len(fruit) for fruit in fruits}
fruit_lengths
{'apple': 5, 'banana': 6, 'cherry': 6}
fruit_indices = {fruit:index for index, fruit in enumerate(fruits)}
fruit_indices
{'apple': 0, 'banana': 1, 'cherry': 2}
Map and Filter¶
map
applies a function to every element of a sequence and returns a list (Python 2) or iterator (Python 3):
simpsons = ['homer', 'marge', 'bart']
map(len, simpsons)
[5, 5, 4]
# equivalent list comprehension
[len(word) for word in simpsons]
[5, 5, 4]
map(lambda word: word[-1], simpsons)
['r', 'e', 't']
# equivalent list comprehension
[word[-1] for word in simpsons]
['r', 'e', 't']
filter
returns a list (Python 2) or iterator (Python 3) containing the elements from a sequence for which a condition is True
:
nums = range(5)
filter(lambda x: x % 2 == 0, nums)
[0, 2, 4]
# equivalent list comprehension
[num for num in nums if num % 2 == 0]
[0, 2, 4]
Randomness¶
# import random module
import random
# generate random numbers
random.random()
0.37959528674478593
# generate random numbers
random.random()
0.8878439306673374
# generate random numbers from start, end
random.randint(1, 20)
5
# generate random numbers from start, end
random.randint(1, 20)
1
# generate random numbers using randrange(start, step, stop)
random.randrange(1, 20, 2)
5
# generate random numbers using randrange(start, step, stop)
random.randrange(1, 20, 2)
13
# randomly choice: random.choice([sequence])
random.choice([1, 2, 3, 4, 5, 6])
2
# randomly choice: random.choice([sequence])
random.choice([1, 2, 3, 4, 5, 6])
3
# randomly choice: random.choice([sequence])
random.choice(["H", "T"])
'T'
# randomly choice: random.choice([sequence])
random.choice(["H", "T"])
'H'
Working with Files¶
# store file in filename variable
filename = "../data/input.txt"
# open file
open(filename)
<_io.TextIOWrapper name='./data/input.txt' mode='r' encoding='UTF-8'>
# read file content using for loop
for line in open(filename):
print(line)
First Line
Second Line
Third Line
# removed special character: \n and \t
for line in open(filename):
line = line.rstrip()
print(line)
First Line
Second Line
Third Line
# split: returns a list of each line
for line in open(filename):
line = line.rstrip().split(" ")
print(line)
['First', 'Line']
['Second', 'Line']
['Third', 'Line']
# write a file
F = open("../data/output.txt", "w") # w for writing mood
F.write("Python\n")
7
# close file
F.close()
# read a file using with statement: open and close
with open(filename, "r") as F: # r means reading mood
for line in F:
line = line.rstrip()
print(line)
First Line
Second Line
Third Line
# write a custom function for reading file
def readFile(inputfile):
with open(inputfile, "r") as F:
for line in F:
line = line.rstrip()
print(line)
# read file using readFile
filename = "../data/input.txt"
readFile(filename)
First Line
Second Line
Third Line
Common Mistakes and Errors¶
# Create a list
L = [2,4,6]
# common error-1: IndexError
L[4]
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-15-41e6afda22e2> in <module>
1 # common error-1
----> 2 L[4]
IndexError: list index out of range
# check length
len(L)
3
# common error-2: AttributeError
L.add(8)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-17-dcbd7b173a8f> in <module>
1 # common error-2
----> 2 L.add(8)
AttributeError: 'list' object has no attribute 'add'
# solution
L.append(8)
L
[2, 4, 6, 8, 8]
# Create a dictionary
D = {1: "one", 2:"two"}
# keys
D.keys()
dict_keys([1, 2])
# common error-3: KeyError
D[0]
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-24-f074814482d9> in <module>
1 # indexing
----> 2 D[0]
KeyError: 0
# common error-4: TypeError
"strings" + 9
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-25-9d5edd8011ef> in <module>
1 # common error-4
----> 2 "strings" + 9
TypeError: can only concatenate str (not "int") to str
# common error-5: IndentationError
def rsum(n):
rsum = 0
for k in range(n):
rsum += k
return rsum
rsum(12)
0