A list is a collection of arbitrary objects, similar to arrays in other programming languages. A list is defined by enclosing a comma-separated sequence of objects in square brackets []
>>> squares = [1, 4, 9, 16, 25] # list of numbers
>>> names = ['harry', 'ron', 'hermione', 'ginny'] # list of strings
>>> variety = [3, 'slytherin', 2.718, True, [9, 8, 7]] # list of varying data typesThe len function returns the length of a list
>>> horcruxes = ["diary", "ring", "cup", "locket", "diadem", "snake", "boy"]
>>> len(horcruxes) # returns the number of elements in the list
7To understand accessing elements of a list, it is very important to understand the concept of slicing.
>>> my_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> # 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
... # -10,-9,-8,-7,-6,-5,-4,-3,-2,-1In python, you can use both +ve and -ve indices to access elements
>>> my_list[0] # 1st element from the front
0
>>> my_list[5] # 6th element from the front
5
>>> my_list[9] # 10th element from the front
9
>>> my_list[-1] # 1st element from the back
9
>>> my_list[-5] # 5th element from the back
5
>>> my_list[-10] # 10th element from the back
0To get a range of elements, we use the following syntax:
list[start:end:step]- start - Starting position of
range, defaults to 0 - end - Ending position of
range, non-inclusive, defaults to length oflist - step - Step size, defaults to 1
>>> my_list[0:5] # 1st element from the front till the 5th element from the front
[0, 1, 2, 3, 4]
>>> my_list[3:8] # 4th element from the front till the 8th element from the front
[3, 4, 5, 6, 7]
>>> my_list[0:-5] # 1st element from the front till the 6th element from the back
[0, 1, 2, 3, 4]
>>> my_list[-7:-2] # 7th element from the back till the 3rd element from the back
[3, 4, 5, 6, 7]Since end is non-inclusive, how do you slice the entire list?
>>> my_list[1:9] # Does not work
[1, 2, 3, 4, 5, 6, 7, 8]
>>> my_list[1:10] # Bad
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> my_list[1:len(my_list)] # Okay
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> my_list[1:] # Good
[1, 2, 3, 4, 5, 6, 7, 8, 9]This also works for the beginning
>>> my_list[0:-1] # Okay
[0, 1, 2, 3, 4, 5, 6, 7, 8]
>>> my_list[:-1] # Good
[0, 1, 2, 3, 4, 5, 6, 7, 8]You can also drop both start and end to slice the entire list
>>> my_list[:] # The entire range
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]The step parameter skips values
>>> my_list[2:9:2] # pick every 2nd element
[2, 4, 6, 8]The value of step can also be -ve which will run in reverse
>>> my_list[8:1:-1] # pick every 1st element in reverse
[8, 7, 6, 5, 4, 3, 2]
>>> my_list[8:1:-2] # pick every 2nd element in reverse
[8, 6, 4, 2]Using step you can reverse the entire list
>>> my_list[::-1] # get the entire list and pick every 1st element in reverse
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]Now that you have an understanding of list, let's now see some built-in operators
The in and not in operators
>>> gryffindor = ["harry", "ron", "hermione"]
>>> "harry" in gryffindor # checks if "harry" is in gryffindor
True
>>> "draco" not in gryffindor # checks if "draco" is not in gryffindor
TrueYou can concatenate two list objects by using the + operator
>>> slytherin = ["draco", "tom", "snape", "vincent", "gregory"]
>>> ravenclaw = ["luna", "cho", "padma"]
>>> hufflepuff = ["cedric", "tonks"]
>>> hogwarts = gryffindor + slytherin + ravenclaw + hufflepuff
>>> hogwarts
['harry', 'ron', 'hermione', 'draco', 'tom', 'snape', 'vincent', 'gregory', 'luna', 'cho', 'padma', 'cedric', 'tonks']You can repeat a list by using the * operator
>>> [0, 1, 2] * 3 # repeats list [0, 1, 2] 3 times and concatenates
[0, 1, 2, 0, 1, 2, 0, 1, 2]You can also use mathematical functions
>>> my_list
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> min(my_list) # returns the minimum or smallest element in the list
0
>>> max(my_list) # returns the maximum or largest element in the list
9
>>> sum(my_list) # returns the sum of elements in the list
45Keep in mind that a list can also be nested
>>> l = [[0, 1, 2], ['quaffle', 'bludger', 'bludger', 'snitch']] # l comprises of 2 nested lists
>>> l[0][2] # l[0] = [0, 1, 2]
2
>>> l[1][:2] # l[1] = ['quaffle', 'bludger', 'bludger', 'snitch']
['quaffle', 'bludger']
>>> l[0][::-1]
[2, 1, 0]One fundamental concept of list is that it is mutable. This means you can change values in a list, elements can be added, deleted, shifted and moved around at will.
A mutable object can be modified after it is created. In contrast, an immutable object is one whose state cannot be modified after it is created.
We will use the following example
>>> spells = ["riddikulus", "obliviate", "sectumsempra", "avada kedavara", "alohomora", "lumos", "expelliarmus","wingardium leviosa", "accio", "expecto patronum"]To modify a single value
>>> spells[0] = 'stupefy' # modify element at position 1
>>> spells
['stupefy', 'obliviate', 'sectumsempra', 'avada kedavara', 'alohomora', 'lumos', 'expelliarmus', 'wingardium leviosa', 'accio', 'expecto patronum']Or modify a range of values
>>> spells[:3] = ['crucio', 'imperio', 'incendio'] # modify all elements in range(0, 3)
>>> spells
['crucio', 'imperio', 'incendio', 'avada kedavara', 'alohomora', 'lumos', 'expelliarmus', 'wingardium leviosa', 'accio', 'expecto patronum']You can append elements at end of a list
>>> spells.append('reducto')
>>> spells
['crucio', 'imperio', 'incendio', 'avada kedavara', 'alohomora', 'lumos', 'expelliarmus', 'wingardium leviosa', 'accio', 'expecto patronum', 'reducto']Or insert at a specific index
>>> spells.insert(2, "silencio")
>>> spells
['crucio', 'imperio', 'silencio', 'incendio', 'avada kedavara', 'alohomora', 'lumos', 'expelliarmus', 'wingardium leviosa', 'accio', 'expecto patronum', 'reducto']
>>> spells.insert(-1, "reparo") # negative indices also work
>>> spells
['crucio', 'imperio', 'silencio', 'incendio', 'avada kedavara', 'alohomora', 'lumos', 'expelliarmus', 'wingardium leviosa', 'accio', 'expecto patronum', 'reparo', 'reducto']To delete a single value
>>> del spells[2]
>>> spells
['crucio', 'imperio', 'incendio', 'avada kedavara', 'alohomora', 'lumos', 'expelliarmus', 'wingardium leviosa', 'accio', 'expecto patronum', 'reparo', 'reducto']
>>> del spells[-2]
>>> spells
['crucio', 'imperio', 'incendio', 'avada kedavara', 'alohomora', 'lumos', 'expelliarmus', 'wingardium leviosa', 'accio', 'expecto patronum', 'reducto']Or delete a range of values
>>> del spells[:3]
>>> spells
['avada kedavara', 'alohomora', 'lumos', 'expelliarmus', 'wingardium leviosa', 'accio', 'expecto patronum', 'reducto']One neat property of a list is unpacking
>>> student = ['Neville', 29, 1980] # list packing
>>> name, age, year = student # list unpacking
>>> print(name, age, year) # prints as space separated values by default
Neville 29 1980However, if we try to unpack more/less values than expected, python throws an error
>>> student = ['Neville', 29, 1980]
>>> name, age, year, id_no = student # trying to unpack 4 values from a list of 3 values
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: not enough values to unpack (expected 4, got 3)You can convert an str object or a string to a list using type casting
>>> list("python") # breaks the string into a list of characters
['p', 'y', 't', 'h', 'o', 'n']Type casting or type coercion refers to converting one data type into another.
We can use type casting to better understand the range function
>>> list(range(5)) # returns a list of elements from 0 to 4
[0, 1, 2, 3, 4]
>>> list(range(1, 10, 2)) # returns a list of odd elements from 1 to 9
[1, 3, 5, 7, 9]To iterate over a list
>>> animals = ['hippogriff', 'phoenix', 'unicorn', 'centaur']
>>> for animal in animals: # loops through a sequence of elements
... print(animal)
...
hippogriff
phoenix
unicorn
centaurTo empty a list
>>> animals = ['hippogriff', 'phoenix', 'unicorn', 'centaur']
>>> animals.clear() # delete all elements in list
>>> animals
[]A tuple is identical to a list in all respects, except for the following properties:
- A
tupleis defined using parenthesis()instead of square brackets[]as in alist - A
tupleis immutable
Why use a tuple over list?
- Faster execution
- Data remains constant
>>> my_tuple = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
>>> my_tuple[5]
5
>>> my_tuple[-3]
7
>>> my_tuple[:5]
(0, 1, 2, 3, 4)
>>> my_tuple[1:]
(1, 2, 3, 4, 5, 6, 7, 8, 9)
>>> my_tuple[2:9:2]
(2, 4, 6, 8)
>>> my_tuple[::-1]
(9, 8, 7, 6, 5, 4, 3, 2, 1, 0)Since they are immutable, you cannot change their values
>>> my_tuple[0] = 10 # error
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignmentTo iterate over a tuple
>>> levels = ('prefect', 'head', 'caretaker', 'professor', 'headmaster')
>>> for level in levels: # loops through a sequence of elements
... print(level)
...
prefect
head
caretaker
professor
headmasterWe can now try to see enumerate function
>>> tuple(enumerate(levels)) # adds a counter for each value as a tuple of (counter, value)
((0, 'prefect'), (1, 'head'), (2, 'caretaker'), (3, 'professor'), (4, 'headmaster'))The default starting value for the counter is 0 in enumerate. However, you can specify a different starting value
>>> tuple(enumerate(levels, 100)) # starts the counter from 100
((100, 'prefect'), (101, 'head'), (102, 'caretaker'), (103, 'professor'), (104, 'headmaster'))Using tuple unpacking we can loop through with enumerate
>>> levels = ('prefect', 'head', 'caretaker', 'professor', 'headmaster')
>>> for index, level in enumerate(levels): # loop through a sequence of elements with tuple unpacking
... print(index, level)
...
0 prefect
1 head
2 caretaker
3 professor
4 headmasterA dictionary is a collection of key-value pairs. The key is a unique identifier that is mapped to a value, almost like a real-world dictionary where each word is a key and the definition is the value. You can define a dictionary using curly braces {}, a colon : separates each key from its value
>>> student = {'name': 'Harry', 'age': 14, 'courses': ['Charms', 'Defence Against the Dark Arts', 'Potions', 'Herbology']} # dictWe access values of a dict similar to a list but instead of specifying the position (which doesn't make much sense in a dictionary), we specify the key
>>> student['name'] # accessing the key 'name'
'Harry'
>>> student['age'] # accessing the key 'age'
14
>>> student['courses'] # accessing the key 'courses'
['Charms', 'Defence Against the Dark Arts', 'Potions', 'Herbology']If the key, does not exist it will throw an error, a better way is to use the get method
>>> student['idno'] # error
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'idno'
>>> print(student.get('idno')) # returns None if key does not exist
NoneAdding an entry is as easy as assigning a new key and a value
>>> student['idno'] = 'the-boy-who-lived' # updates the value if key exists else creates a new key with value
>>> student
{'name': 'Harry', 'age': 25, 'courses': ['Charms', 'Defence Against the Dark Arts', 'Potions', 'Herbology'], 'idno': 'the-boy-who-lived'}To delete an entry
>>> del student['idno'] # delete key-value pair with key 'idno'
>>> student
{'name': 'Harry', 'age': 25, 'courses': ['Charms', 'Defence Against the Dark Arts', 'Potions', 'Herbology']}We can have a variety of keys and values just like in a list or tuple as long as the keys are of immutable data type
>>> variety = {13: 'prime', 'constants': [3.14, 2.718, 1.618], (1 + 4.2j): True} # dict of varying data typesLet's now look at some built-in methods. We'll use the following example
>>> letters = {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e'}Some common methods
>>> letters.items() # returns the key-value pairs of dict
dict_items([(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd'), (4, 'e')])
>>> letters.keys() # returns the keys of dict
dict_keys([0, 1, 2, 3, 4])
>>> letters.values() # returns the values of dict
dict_values(['a', 'b', 'c', 'd', 'e'])Using the items method and tuple unpacking, we can loop through a dict
>>> letters = {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e'}
>>> for key, value in letters.items(): # loop through a sequence of elements with tuple unpacking
... print(key, value)
...
0 a
1 b
2 c
3 d
4 eTo merge a dictionary using another dictionary
>>> letters.update({5: 'f', 6: 'g', 7: 'h'}) # updates the value if key present else creates a new one
>>> letters
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h'}To empty a dict
>>> letters.clear() # delete all key-value pairs in dict
>>> letters
{}A set is an unordered collection with no duplicate elements. A set itself may be modified, but the elements of a set must be immutable.
There are two ways to create a set
>>> weasleys = {"ron", "fred", "george", "fred", "ginny", "ron"} # Using {}
>>> weasleys # duplicate elements automatically removed
{'george', 'ron', 'fred', 'ginny'}
>>> weasleys = set(["ron", "fred", "george", "fred", "ginny", "ron"]) # Using the set function
>>> weasleys # duplicate elements automatically removed
{'george', 'ron', 'fred', 'ginny'}Elements in a set can be of varying data types as long as they are immutable
>>> variety = {"python", 5, ("breakfast", "lunch", "dinner"), 2.718} # set of varying data types
>>> variety
{('breakfast', 'lunch', 'dinner'), 2.718, 5, 'python'}
>>> s = {[1, 2, 3]} # error: lists aren't mutable
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'You can modify a set
>>> weasleys = {'george', 'ron', 'ginny', 'fred'}
>>> weasleys.add('percy') # adds an element to the set
>>> weasleys
{'fred', 'george', 'percy', 'ron', 'ginny'}
>>> weasleys.remove('fred') # removes an element from the set. accidental spoilers!
>>> weasleys
{'george', 'percy', 'ron', 'ginny'}Be careful when you remove elements, a better way is to use discard
>>> weasleys.remove('harry') # removes an element if it exists else raises an error
Traceback (most recent call last): # error: element not in set
File "<stdin>", line 1, in <module>
KeyError: 'harry'
>>> weasleys.discard('harry') # removes an element if it exists else does nothingTo iterate over a set
>>> weasleys = {'fred', 'george', 'percy', 'ron', 'ginny'}
>>> for fruit in weasleys: # loops through a sequence of elements
... print(fruit)
...
fred
george
percy
ron
ginnyTo empty a set
>>> weasleys.clear() # delete all elements in set
>>> weasleys
set()You can use operators on set. We'll use the following example
>>> odds = {1, 3, 5, 7, 9} # set of odd numbers
>>> evens = {0, 2, 4, 6, 8} # set of even numbers
>>> ints = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} # set of integers
>>> primes = {2, 3, 5, 7} # set of primesThe in and not in operators can be used to test if elements are in a set
>>> 5 in odds # check if element is present in set
True
>>> 2 not in odds # check if element is not present in set
TrueLet's now take a look at mathematical operations on a set. Find the union of two or more sets
>>> odds.union(evens) # returns the set of elements in either a or b
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
>>> odds & ints
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}Find the intersection of two or more sets
>>> odds.intersection(evens) # returns the set of elements common to both a and b
set()
>>> evens & primes
{2}Get the difference of two or more sets
>>> ints.difference(odds) # returns the set of elements in a but not in b
{0, 2, 4, 6, 8}
>>> ints - evens
{1, 3, 5, 7, 9}Get the symmetric_difference of two or more sets
>>> primes.symmetric_difference(odds) # returns the set of elements in either a or b but not both
{1, 2, 9}
>>> primes ^ evens
{0, 3, 4, 5, 6, 7, 8}Just like a
listhas an immutable data type calledtuple, asetalso has an immutable data type calledfrozenset.
Functions allow you to write a piece of code to carry out a specified task. Functions help break your code into smaller chunks. As your program grows larger, functions make it more organized and manageable. Futhermore, they allow you to avoid repetition and make code reusable.
There are 3 types of functions:
- Built-in functions
- User-defined functions
- Anonymous functions
You have already seen a few built-in functions. The len, min, max and sum are a few examples. We'll mainly be focusing on user-defined functions.
Functions have the following syntax
def function_name(parameter(s)):
"""docstring"""
statement(s)
[return object]Below are the steps in defining a function:
- Use the keyword
defto define the function followed by the name of the function. - Add parameter(s) to the function, this is optional.
- A colon
:marks the end of function header. - Optional documentation string to decribe what the function does.
- Statement(s) making up the function body, must be indented.
- An optional
returnstatement toreturna value from the function.
Let's now create some functions!
def greet():
... """This function greets by printing 'Hello, Everyone!'"""
... print("Hello, Everyone!")To call a function, simply type the function name with appropriate parameters
>>> greet()
Hello, World!Let's add a name parameter to our function
>>> def greet(name):
... """Greets the person whose name is passed as a parameter"""
... print("Hello, " + name + "!")Now we call it by passing a name as an argument, if we don't we get an error
>>> greet("Voldemort")
Hello, Voldemort!
>>> greet() # error: no name passed
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: greet() missing 1 required positional argument: 'name'To solve this we can use default arguments
>>> def greet(name='Everyone'):
... """Greets the person whose name is passed as a parameter, default='Everyone'"""
... print("Hello, " + name + "!")
...
>>> greet() # no argument passed, uses default value
Hello, Everyone!
>>> greet("Dumbledore") # argument passed, uses argument value
Hello, Dumbledore!You can have multiple arguments
>>> def greet(msg, name="Everyone"):
... """Greets the person whose name is passed as a parameter, default='Everyone' with a message"""
... print("Hello, " + name + "! " + msg)Keep the ordering of arguments when calling the function
>>> greet("The boy who lived come to die? :P", "Harry") # name passed, uses argument value
Hello, Harry! The boy who lived come to die? :P
>>> greet("Hope you like our session!") # no name passed, uses default value
Hello, Everyone! Hope you like our session!When having multiple arguments, default arguments must be followed after required arguments
>>> def greet(name="Everyone", msg): # error: default argument before required argument
... print("Hello, " + name + "! " + msg)
...
File "<stdin>", line 1
SyntaxError: non-default argument follows default argumentYou can return values from a function. Let's define a basic exponent function
>>> def exponent(a, b):
... """Returns a to the power b"""
... return a ** b
...
>>> exponent(5, 3) # returns 5 to the power 3
125When we call a function with values, the values get assigned to the arguments according to their position. However, python allows functions to be called using keyword arguments
>>> exponent(2, 3) # called using positional arguments
8
>>> exponent(3, 2) # switching the position matters
9
>>> exponent(a=2, b=3) # called using keyword arguments
8
>>> exponent(b=3, a=2) # switching the position does not matter
8When using both positional and keyword arguments, make sure keyword arguments follow positional arguments, else python throws you an error
>>> # Goal: a = 5 and b = 3
... exponent(5, b=3) # a = 5 and b = 3
125
>>> exponent(b=3, 5) # error: keyword arguments must follow positional arguments
File "<stdin>", line 1
SyntaxError: positional argument follows keyword argumentAlso, make sure you are using the right keyword names
>>> exponent(5, c=3) # error: what is c?
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: exponent() got an unexpected keyword argument 'c'You might still get an error when mixing positional and keyword arguments
>>> # Goal: a = 3 and b = 5
... exponent(5, a=3) # error: a = 5 or a = 3?
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: exponent() got multiple values for argument 'a'The last type of arguments you can have are arbitrary arguments. We use them when we do not know in advance the number of arguments that will be passed into a function. We use an asterisk * before the parameter name to denote this argument
>>> def add(*numbers):
... """Returns the sum of all numbers"""
... return sum(numbers)
...
>>> add(10, 20, 30)
60
>>> add(1, 2, 3, 4, 5)
15Bear in mind, functions immediately exit when they come across a return statement
>>> def add(*numbers):
... """Returns the sum of all numbers"""
... return sum(numbers)
... print("This never gets executed")
...
>>> add(9, 4)
13We covered:










