0% found this document useful (0 votes)
26 views63 pages

PCAP(python)

The document outlines the syllabus for two Python courses, Python Essentials 1 and 2, covering foundational programming concepts, data types, control structures, functions, and object-oriented programming. Each course includes modules on specific topics, culminating in summary tests and a final test for certification eligibility. Key takeaways include built-in functions, literals, operations, expressions, variables, loops, and bitwise operators.

Uploaded by

vasih462
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
0% found this document useful (0 votes)
26 views63 pages

PCAP(python)

The document outlines the syllabus for two Python courses, Python Essentials 1 and 2, covering foundational programming concepts, data types, control structures, functions, and object-oriented programming. Each course includes modules on specific topics, culminating in summary tests and a final test for certification eligibility. Key takeaways include built-in functions, literals, operations, expressions, variables, loops, and bitwise operators.

Uploaded by

vasih462
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 63

Course syllabus: Python Essentials 1 PE1

PE1 Module 1  Introduction to Python and Computer Programming

Python as a modern, universal and growing programming language;


Python versions and language development;
Brief review of tools and environments needed to start programming in Python.

PE1 Module 2  Data Types, Variables, Basic Input-Output Operations, Basic Operators

How to write and run the very first Python program;


Python literals;
Python operators and expressions;
Variables – naming and using;
Basic input/output operations in Python.

PE1 Module 3  Boolean Values, Conditional Execution, Loops, Lists and List Processing,
Logical and Bitwise Operations

Boolean data type;


Relational operators in Python;
Decision-making in Python: if, if-else, if-elif-else;
Repeating code execution using loops: while and for;
Logic and bit-wise operations in Python;
Lists in Python: constructing, indexing, slicing and content manipulation;
How to sort a list using a bubble-sort algorithm;
Multidimensional lists and their applications.

PE1 Module 4  Functions, Tuples, Dictionaries, and Data Processing

Code structuring and the concept of functions;


Function invocation and returning a result from a function;
Name scopes and variable shadowing;
Tuples – purpose, constructing and using;
Dictionaries – purpose, constructing and using.

Python Essentials 1  Summary Test

PE1 Modules 1-4.

Course syllabus: Python Essentials 2 PE2

PE2 Module 1  Modules, Packages and PIP

What is module and why do we need it?


Importing and using modules;
Review of selected useful Python modules;
What is a package and how it differs from a module?
Constructing and using packages;
PIP – Swiss army knife for package maintenance.

PE2 Module 2  Exceptions, Strings, String and List Methods


Characters, strings and coding standards;
Strings vs. lists – similarities and differences;
Lists methods;
String methods;
Python's way of handling runtime errors;
Controlling the flow of errors using try and except;
The hierarchy of exceptions.

PE2 Module 3  Object-Oriented Programming in Python (OOP

Basic concepts of object-oriented programming;


From procedural to object approach – motivations and benefits;
Classes, objects, properties and methods;
Inheritance and polymorphism;
Exception as an object.

PE2 Module 4  Miscellaneous

Generators, iterators and closures;


Working with file-system, directory tree and files;
Selected Python Standard Library modules (os, datetime, time, and calendar).

Python Essentials 2  Summary Test

PE2 Modules 1-4.

Python Essentials - Final Test

PE1 Modules 1-4;


PE2 Modules 1-4;
score 70% or more to be eligible for a 50% discount voucher (PCAP - Certified
Associate in Python Programming certification exam).
Key takeaways (Built-in functions)
print()
1. The print() function is a built-in function. It prints/outputs a specified message to the
screen/consol window.

2. Built-in functions, contrary to user-defined functions, are always available and don't
have to be imported. Python 3.8 comes with 69 built-in functions. You can find their full
list provided in alphabetical order in the Python Standard Library.

3. To call a function (this process is known as function invocation or function call), you
need to use the function name followed by parentheses. You can pass arguments into a
function by placing them inside the parentheses. You must separate arguments with a
comma, e.g., print("Hello,", "world!") . An "empty" print() function outputs an
empty line to the screen.

4. Python strings are delimited with quotes, e.g., "I am a string" (double quotes), or 'I
am a string, too' (single quotes).

5. Computer programs are collections of instructions. An instruction is a command to


perform a specific task when executed, e.g., to print a certain message to the screen.

6. In Python strings the backslash ( \ ) is a special character which announces that the
next character has a different meaning, e.g., \n (the newline character) starts a new
output line.

7. Positional arguments are the ones whose meaning is dictated by their position, e.g.,
the second argument is outputted after the first, the third is outputted after the second,
etc.

8. Keyword arguments are the ones whose meaning is not dictated by their location, but
by a special word (keyword) used to identify them.

9. The end and sep parameters can be used for formatting the output of the print()
function. The sep parameter specifies the separator between the outputted arguments
(e.g., print("H", "E", "L", "L", "O", sep="-") , whereas the end parameter specifies
what to print at the end of the print statement.

Literals
1. Literals are notations for representing some fixed values in code. Python has various
types of literals - for example, a literal can be a number (numeric literals, e.g., 123 ), or a
string (string literals, e.g., "I am a literal.").

2. The binary system is a system of numbers that employs 2 as the base. Therefore, a
binary number is made up of 0s and 1s only, e.g., 1010 is 10 in decimal.

Octal and hexadecimal numeration systems, similarly, employ 8 and 16 as their bases
respectively. The hexadecimal system uses the decimal numbers and six extra letters.

3. Integers (or simply ints) are one of the numerical types supported by Python. They are
numbers written without a fractional component, e.g., 256 , or -1 (negative integers).
4. Floating-point numbers (or simply floats) are another one of the numerical types
supported by Python. They are numbers that contain (or are able to contain) a fractional
component, e.g., 1.27 .

5. To encode an apostrophe or a quote inside a string you can either use the escape
character, e.g., 'I\'m happy.' , or open and close the string using an opposite set of
symbols to the ones you wish to encode, e.g., "I'm happy." to encode an apostrophe,
and 'He said "Python", not "typhoon"' to encode a (double) quote.

6. Boolean values are the two constant objects True and False used to represent truth
values (in numeric contexts 1 is True , while 0 is False .

EXTRA

There is one more, special literal that is used in Python: the None literal. This literal is a
so-called NoneType object, and it is used to represent the absence of a value. We'll tell
you more about it soon.

Operations and Expressions


1. An expression is a combination of values (or variables, operators, calls to functions -
you will learn about them soon) which evaluates to a value, e.g., 1 + 2 .

2. Operators are special symbols or keywords which are able to operate on the values
and perform (mathematical) operations, e.g., the * operator multiplies two values: x *
y.

3. Arithmetic operators in Python: + (addition), - (subtraction), * (multiplication), /


(classic division - always returns a float), % (modulus - divides left operand by right
operand and returns the remainder of the operation, e.g., 5 % 2 = 1 ), ** (exponentiation
- left operand raised to the power of right operand, e.g., 2 ** 3 = 2 * 2 * 2 = 8 ), //
(floor/integer division - returns a number resulting from division, but rounded down to the
nearest whole number, e.g., 3 // 2.0 = 1.0 )

4. A unary operator is an operator with only one operand, e.g., -1 , or +3 .

5. A binary operator is an operator with two operands, e.g., 4 + 5 , or 12 % 5 .

6. Some operators act before others - the hierarchy of priorities:

unary + and - have the highest priority


then: ** , then: * , / , and % , and then the lowest priority: binary + and - .

7. Subexpressions in parentheses are always calculated first, e.g., 15 - 1 * (5 * (1 +


2)) = 0 .

8. The exponentiation operator uses right-sided binding, e.g., 2 ** 2 ** 3 = 256 .

Variables
1. A variable is a named location reserved to store values in the memory. A variable is
created or initialized automatically when you assign a value to it for the first time. 2.1.4.1

2. Each variable must have a unique name - an identifier. A legal identifier name must be
a non-empty sequence of characters, must begin with the underscore( _ ), or a letter, and
it cannot be a Python keyword. The first character may be followed by underscores,
letters, and digits. Identifiers in Python are case-sensitive. 2.1.4.1
3. Python is a dynamically-typed language, which means you don't need to declare
variables in it. 2.1.4.3 To assign values to variables, you can use a simple assignment
operator in the form of the equal ( = ) sign, i.e., var = 1 .

4. You can also use compound assignment operators (shortcut operators) to modify
values assigned to variables, e.g., var += 1 , or var /= 5 * 2 . 2.1.4.8

5. You can assign new values to already existing variables using the assignment operator
or one of the compound operators, e.g.: 2.1.4.5

var = 2
print(var)
var = 3
print(var)
var += 1
print(var)

6. You can combine text and variables using the + operator, and use the print()
function to output strings and variables, e.g.: 2.1.4.4

var = "007"
print("Agent " + var)
Key takeaways (Loops, conditional
statements)
1. There are two types of loops in Python: while and for :

the while loop executes a statement or a set of statements as long as a specified


boolean condition is true, e.g.:

# Example 1

while True:
print("Stuck in an infinite loop.")

# Example 2
counter = 5
while counter > 2:
print(counter)
counter -= 1

the for loop executes a set of statements many times; it's used to iterate over a
sequence (e.g., a list, a dictionary, a tuple, or a set - you will learn about them soon)
or other objects that are iterable (e.g., strings). You can use the for loop to iterate
over a sequence of numbers using the built-in range function. Look at the examples
below:

# Example 1
word = "Python"
for letter in word:
print(letter, end="*")
# Example 2
for i in range(1, 10):
if i % 2 == 0:
print(i)

2. You can use the break and continue statements to change the flow of a loop:

You use break to exit a loop, e.g.:

text = "OpenEDG Python Institute"


for letter in text:
if letter == "P":
break
print(letter, end="")
You use continue to skip the current iteration, and continue with the next iteration,
e.g.:

text = "pyxpyxpyx"
for letter in text:
if letter == "x":
continue
print(letter, end="")

3. The while and for loops can also have an else clause in Python. The else clause
executes after the loop finishes its execution as long as it has not been terminated by
break , e.g.:

n = 0
while n != 3:
print(n)
n += 1

else:
print(n, "else")
print()

for i in range(0, 3):


print(i)

else:
print(i, "else")

4. The range() function generates a sequence of numbers. It accepts integers and


returns range objects. The syntax of range() looks as follows: range(start, stop,
step) , where:

start is an optional parameter specifying the starting number of the sequence (0


by default)
stop is an optional parameter specifying the end of the sequence generated (it is
not included),
and step is an optional parameter specifying the difference between the numbers
in the sequence (1 by default.)

Example code:

for i in range(3):
print(i, end=" ") # Outputs: 0 1 2

for i in range(6, 1, -2):


print(i, end=" ") # Outputs: 6, 4, 2
Key takeaways: continued
Exercise 1

Create a for loop that counts from 0 to 10, and prints odd numbers to the screen. Use
the skeleton below:

for i in range(1, 11): # Line of code. # Line of code.`

#Sample solution:

for i in range(0, 11):


if i % 2 != 0:
print(i)

Exercise 2

Create a while loop that counts from 0 to 10, and prints odd numbers to the screen. Use
the skeleton below:

x = 1 while x < 11: # Line of code.

#Sample solution:

x = 1
while x < 11:
if x % 2 != 0:
print(x)
x += 1

Exercise 3

Create a program with a for loop and a break statement. The program should iterate
over characters in an email address, exit the loop when it reaches the @ symbol, and
print the part before @ on one line. Use the skeleton below:

for ch in "john.smith@pythoninstitute.org":
if ch == "@":
# Line of code.
# Line of code.`

**Sample solution**:

for ch in "john.smith@pythoninstitute.org":
if ch == "@":
break
print(ch, end="")
Exercise 4

Create a program with a for loop and a continue statement. The program should iterate
over a string of digits, replace each 0 with x , and print the modified string to the screen.
Use the skeleton below:

for digit in "0165031806510":


if digit == "0":
# Line of code.
# Line of code.
# Line of code.`

Sample solution:

for digit in "0165031806510":


if digit == "0":
continue
print(digit, end="")

Exercise 5
What is the output of the following code?

n = 3
while n > 0:
print(n + 1)
n -= 1
else:
print(n)

The output of the following code is:

4 3 2 0

Exercise 6
What is the output of the following code?

n = range(4)
for num in n:
print(num - 1)
else:
print(num)

The output of the following code is:

-1 0 1 2 3

Exercise 7

What is the output of the following code?


for i in range(0, 6, 3):
print(i)

Key takeaways (Bitwise operator)


1. Python supports the following logical operators:

and → if both operands are true, the condition is true, e.g., (True and True) is
True ,
or → if any of the operands are true, the condition is true, e.g., (True or False) is
True ,
not → returns false if the result is true, and returns true if the result is false, e.g.,
not True is False .

2. You can use bitwise operators to manipulate single bits of data. The following sample
data:

x = 15 , which is 0000 1111 in binary,


y = 16 , which is 0001 0000 in binary.

will be used to illustrate the meaning of bitwise operators in Python. Analyze the
examples below:

& does a bitwise and, e.g., x & y = 0 , which is 0000 0000 in binary,
| does a bitwise or, e.g., x | y = 31 , which is 0001 1111 in binary,
˜ does a bitwise not, e.g., ˜ x = 240 *, which is 1111 0000 in binary,
^ does a bitwise xor, e.g., x ^ y = 31 , which is 0001 1111 in binary,
>> does a bitwise right shift, e.g., y >> 1 = 8 , which is 0000 1000 in binary,
<< does a bitwise left shift, e.g., y << 3 = , which is 1000 0000 in binary,
* -16 (decimal from signed 2's complement) -- read more about the Two's
complement operation.

Exercise 1
What is the output of the following snippet?

x = 1
y = 0
z = ((x == y) and (x == y)) or not(x == y)
print(not(z))

False

Exercise 2
What is the output of the following snippet?

x = 4
y = 1
a = x & y
b = x | y
c = ~x # tricky!
d = x ^ 5
e = x >> 2
f = x << 2
print(a, b, c, d, e, f)

The output of the following code is:

0 5 -5 1 1 16

Key takeaways (List processing)


1. The list is a type of data in Python used to store multiple objects. It is an ordered and
mutable collection of comma-separated items between square brackets, e.g.:

my_list = [1, None, True, "I am a string", 256, 0]

2. Lists can be indexed and updated, e.g.:

my_list = [1, None, True, 'I am a string', 256, 0]


print(my_list[3]) # outputs: I am a string
print(my_list[-1]) # outputs: 0
my_list[1] = '?'
print(my_list) # outputs: [1, '?', True, 'I am a string', 256, 0]
my_list.insert(0, "first")
my_list.append("last")
print(my_list) # outputs: ['first', 1, '?', True, 'I am a string', 256, 0, 'last']

3. Lists can be nested, e.g.:

my_list = [1, 'a', ["list", 64, [0, 1], False]]

You will learn more about nesting in module 3.1.7  for the time being, we just want you to
be aware that something like this is possible, too.

4. List elements and lists can be deleted, e.g.:

my_list = [1, 2, 3, 4]
del my_list[2]
print(my_list) # outputs: [1, 2, 4]
del my_list # deletes the whole list

Again, you will learn more about this in module 3.1.6  don't worry. For the time being just
try to experiment with the above code and check how changing it affects the output.

5. Lists can be iterated through using the for loop, e.g.:

my_list = ["white", "purple", "blue", "yellow", "green"]


for color in my_list:
print(color)
6. The len() function may be used to check the list's length, e.g.:

my_list = ["white", "purple", "blue", "yellow", "green"]


print(len(my_list)) # outputs 5
del my_list[2]
print(len(my_list)) # outputs 4

7. A typical function invocation looks as follows: result = function(arg) , while a typical


method invocation looks like this: result = data.method(arg) .

Exercise 1

What is the output of the following snippet?

lst = [1, 2, 3, 4, 5]
lst.insert(1, 6)
del lst[0]
lst.append(1)
print(lst)

The output of the following code is:

[6, 2, 3, 4, 5, 1]

Exercise 2

What is the output of the following snippet?

lst = [1, 2, 3, 4, 5]
lst_2 = []
add = 0
for number in lst:
add += number
lst_2.append(add)
print(lst_2)

[1, 3, 6, 10, 15]

Exercise 3

What happens when you run the following snippet?

lst = []
del lst
print(lst)

The output of the following code is:

NameError: name 'lst' is not defined

Exercise 4
What is the output of the following snippet?

lst = [1, [2, 3], 4]


print(lst[1])
print(len(lst))`

[2, 3]
3

Key takeaways (list methods)


1. You can use the sort() method to sort elements of a list, e.g.:

lst = [5, 3, 1, 2, 4]
print(lst)
lst.sort()
print(lst) # outputs: [1, 2, 3, 4, 5]

2. There is also a list method called reverse() , which you can use to reverse the list, e.g.:

lst = [5, 3, 1, 2, 4]
print(lst)
lst.reverse()
print(lst) # outputs: [4, 2, 1, 3, 5]

Exercise 1

What is the output of the following snippet?

lst = ["D", "F", "A", "Z"]


lst.sort()
print(lst)

The output of the following code is:

['A', 'D', 'F', 'Z']

Exercise 2

What is the output of the following snippet?

a = 3
b = 1
c = 2
lst = [a, c, b]
lst.sort()
print(lst)

Exercise 3

What is the output of the following snippet?

a = "A"
b = "B"
c = "C"
d = " "
lst = [a, b, c, d]
lst.reverse()
print(lst)

Key takeaways (list slicing)


1. If you have a list l1 , then the following assignment: l2 = l1 does not make a copy of
the l1 list, but makes the variables l1 and l2 point to one and the same list in
memory. For example:

vehicles_one = ['car', 'bicycle', 'motor']


print(vehicles_one) # outputs: ['car', 'bicycle', 'motor']
vehicles_two = vehicles_one
del vehicles_one[0] # deletes 'car'
print(vehicles_two) # outputs: ['bicycle', 'motor']

2. If you want to copy a list or part of the list, you can do it by performing slicing:

colors = ['red', 'green', 'orange']


copy_whole_colors = colors[:] # copy the entire list
copy_part_colors = colors[0:2] # copy part of the list

3. You can use negative indices to perform slices, too. For example:

sample_list = ["A", "B", "C", "D", "E"]


new_list = sample_list[2:-1]
print(new_list) # outputs: ['C', 'D']

4. The start and end parameters are optional when performing a slice:
list[start:end] ,

e.g.:
my_list = [1, 2, 3, 4, 5]
slice_one = my_list[2: ]
slice_two = my_list[ :2]
slice_three = my_list[-2: ]
print(slice_one) # outputs: [3, 4, 5]
print(slice_two) # outputs: [1, 2]
print(slice_three) # outputs: [4, 5]

5. You can delete slices using the del instruction:

my_list = [1, 2, 3, 4, 5]
del my_list[0:2]
print(my_list) # outputs: [3, 4, 5]
del my_list[:]
print(my_list) # deletes the list content, outputs: []

6. You can test if some items exist in a list or not using the keywords in and not in ,
e.g.:

my_list = ["A", "B", 1, 2]


print("A" in my_list) # outputs: True
print("C" not in my_list) # outputs: True
print(2 not in my_list) # outputs: False

Exercise 1

What is the output of the following snippet?

list_1 = ["A", "B", "C"]


list_2 = list_1
list_3 = list_2
del list_1[0]
del list_2[0]
print(list_3)`

Exercise 2

What is the output of the following snippet?

list_1 = ["A", "B", "C"]


list_2 = list_1 l
ist_3 = list_2
del list_1[0]
del list_2[0]
print(list_3)
The output of the following code is:

['B', 'C']

Exercise 3

What is the output of the following snippet?

list_1 = ["A", "B", "C"]


list_2 = list_1
list_3 = list_2
del list_1[0]
del list_2[:]
print(list_3)

The output of the following code is:

[]

Exercise 4

What is the output of the following snippet?

list_1 = ["A", "B", "C"]


list_2 = list_1[:]
list_3 = list_2[:]
del list_1[0]
del list_2[0]
print(list_3)

The output of the following code is:

['A', 'B', 'C']

Exercise 5

Insert in or not in instead of ??? so that the code outputs the expected result.

my_list = [1, 2, "in", True, "ABC"]


print(1 ??? my_list) # outputs True
print("A" ??? my_list) # outputs True
print(3 ??? my_list) # outputs True
print(False ??? my_list) # outputs False

my_list = [1, 2, "in", True, "ABC"]


print(1 in my_list) # outputs True
print("A" not in my_list) # outputs True
print(3 not in my_list) # outputs True
print(False in my_list) # outputs False
Key takeaways (list comprehension)
1. List comprehension allows you to create new lists from existing ones in a concise and
elegant way. The syntax of a list comprehension looks as follows:

`[expression for element in list if conditional]`

which is actually an equivalent of the following code:

for element in list: if conditional: expression

Here's an example of a list comprehension - the code creates a five-element list filled
with with the first five natural numbers raised to the power of 3

cubed = [num ** 3 for num in range(5)]

print(cubed) # outputs: [0, 1, 8, 27, 64]

2. You can use nested lists in Python to create matrices (i.e., two-dimensional lists). For
example:
# A four-column/four-row table - a two dimensional array (4x4)

table = [[":(", ":)", ":(", ":)"],


[":)", ":(", ":)", ":)"],
[":(", ":)", ":)", ":("],
[":)", ":)", ":)", ":("]]
print(table)
print(table[0][0]) # outputs: ':('
print(table[0][3]) # outputs: ':)'

3. You can nest as many lists in lists as you want, and therefore create n-dimensional lists,
e.g., three-, four- or even sixty-four-dimensional arrays. For example:

# Cube - a three-dimensional array (3x3x3)


cube = [[[':(', 'x', 'x'],
[':)', 'x', 'x'],
[':(', 'x', 'x']],
[[':)', 'x', 'x'],
[':(', 'x', 'x']]
[':)', 'x', 'x']],
[[':(', 'x', 'x'],
[':)', 'x', 'x'],
[':)', 'x', 'x']]]
print(cube)
print(cube[0][0][0]) # outputs: ':('
print(cube[2][2][0]) # outputs: ':)'
Key takeaways (Functions)
1. You can pass information to functions by using parameters. Your functions can have as
many parameters as you need.

An example of a one-parameter function:

def hi(name):
print("Hi,", name)
hi("Greg")

An example of a two-parameter function:

def hi_all(name_1, name_2):


print("Hi,", name_2)
print("Hi,", name_1)
hi_all("Sebastian", "Konrad")

An example of a three-parameter function:

def address(street, city, postal_code):


print("Your address is:", street, "St.,", city, postal_code)
s = input("Street: ")
p_c = input("Postal Code: ")
c = input("City: ")
address(s, c, p_c)

2. You can pass arguments to a function using the following techniques:

positional argument passing in which the order of arguments passed matters (Ex.
1,
keyword (named) argument passing in which the order of arguments passed
doesn't matter (Ex. 2,
a mix of positional and keyword argument passing (Ex. 3.

# Ex. 1
def subtra(a, b):
print(a - b)
subtra(5, 2) # outputs: 3
subtra(2, 5) # outputs: -3

# Ex. 2
def subtra(a, b):
print(a - b)
subtra(a=5, b=2) # outputs: 3
subtra(b=2, a=5) # outputs: 3

# Ex. 3
def subtra(a, b):
print(a - b)
subtra(5, b=2) # outputs: 3
subtra(5, 2) # outputs: 3

It's important to remember that positional arguments mustn't follow keyword arguments.
That's why if you try to run the following snippet:

def subtra(a, b):


print(a - b)
subtra(5, b=2) # outputs: 3
subtra(a=5, 2) # Syntax Error

Python will not let you do it by signalling a SyntaxError .

3. You can use the keyword argument passing technique to pre-define a value for a given
argument:

def name(first_name, last_name="Smith"):


print(first_name, last_name)
name("Andy") # outputs: Andy Smith
name("Betty", "Johnson")
# outputs: Betty Johnson (the keyword argument replaced by "Johnson")

Exercise 1

What is the output of the following snippet?

def intro(a="James Bond", b="Bond"):


print("My name is", b + ".", a + ".")

intro()

The output of the following code is:

My name is Bond. James Bond.

Exercise 2

What is the output of the following snippet?


def intro(a="James Bond", b="Bond"):
print("My name is", b + ".", a + ".")

intro(b="Sean Connery")
My name is Sean Connery. James Bond.

Exercise 3

What is the output of the following snippet?

def intro(a, b="Bond"):


print("My name is", b + ".", a + ".")
intro("Susan")

Exercise 4

What is the output of the following snippet?

def add_numbers(a, b=2, c):


print(a + b + c)
add_numbers(a=1, c=3)

SyntaxError - a non-default argument ( c ) follows a default argument ( b=2 )

Key takeaways
1. You can use the return keyword to tell a function to return some value. The return
statement exits the function, e.g.:

def multiply(a, b):


return a * b

print(multiply(3, 4)) # outputs: 12

def multiply(a, b):


return

print(multiply(3, 4)) # outputs: None

2. The result of a function can be easily assigned to a variable, e.g.:

def wishes():
return "Happy Birthday!"
w = wishes()
print(w) # outputs: Happy Birthday!

Look at the difference in output in the following two examples:

# Example 1

def wishes():
print("My Wishes")

return "Happy Birthday"

wishes() # outputs: My Wishes

# Example 2

def wishes():
print("My Wishes")
return "Happy Birthday"

print(wishes())

# outputs: My Wishes
# Happy Birthday

3. You can use a list as a function's argument, e.g.:

def hi_everybody(my_list):
for name in my_list:
print("Hi,", name)

hi_everybody(["Adam", "John", "Lucy"])

4. A list can be a function result, too, e.g.:

def create_list(n):
my_list = []
for i in range(n):
my_list.append(i)
return my_list

print(create_list(5))

Exercise 1
What is the output of the following snippet?

def hi():
return

print("Hi!")
hi()

the function will return an implicit None value

Exercise 2

What is the output of the following snippet?

def is_int(data):
if type(data) == int:
return True
elif type(data) == float:
return False
print(is_int(5))
print(is_int(5.0))
print(is_int("5"))

The output of the following code is:

True
False
None

Exercise 3

What is the output of the following snippet?

def even_num_lst(ran):
lst = []
for num in range(ran):
if num % 2 == 0:
lst.append(num)
return lst

print(even_num_lst(11))

The output of the following code is:

[0, 2, 4, 6, 8, 10]

Exercise 4

What is the output of the following snippet?


def list_updater(lst):
upd_list = []
for elem in lst:
elem **= 2
upd_list.append(elem)
return upd_list

foo = [1, 2, 3, 4, 5]
print(list_updater(foo))

The output of the following code is:

[1, 4, 9, 16, 25]

Key takeaways (Related to functions)


1. A variable that exists outside a function has a scope inside the function body (Example
1 unless the function defines a variable of the same name (Example 2, and Example 3,
e.g.:

Example 1

var = 2
def mult_by_var(x):
return x * var

print(mult_by_var(7))
# outputs: 14

Example 2

def mult(x):
var = 5
return x * var

print(mult(7))
# outputs: 35

Example 3

def mult(x):
var = 7
return x * var

var = 3
print(mult(7))
# outputs: 49
2. A variable that exists inside a function has a scope inside the function body (Example
4, e.g.:

Example 4

def adding(x):
var = 7
return x + var

print(adding(4))
# outputs: 11
print(var)
# NameError

3. You can use the global keyword followed by a variable name to make the variable's
scope global, e.g.:

var = 2
print(var) # outputs: 2
def return_var():
global var
var = 5
return var

print(return_var()) # outputs: 5
print(var) # outputs: 5

Exercise 1

What will happen when you try to run the following code?

def message():
alt = 1

print("Hello, World!")
print(alt)

The NameError exception will be thrown ( NameError: name 'alt' is not defined )

Exercise 2

What is the output of the following snippet?

a = 1
def fun():
a = 2
print(a)
fun()
print(a)

The output of the following code is:

2 1

Exercise 3

What is the output of the following snippet?

a = 1
def fun():
global a
a = 2
print(a)
fun()
a = 3
print(a)

The output of the following code is:

2 3

Exercise 4

What is the output of the following snippet?

a = 1
def fun():
global a
a = 2
print(a)
a = 3
fun()
print(a)

The output of the following code is:

2 2

Key takeaways (Recursion)


1. A function can call other functions or even itself. When a function calls itself, this
situation is known as recursion, and the function which calls itself and contains a
specified termination condition (i.e., the base case - a condition which doesn't tell the
function to make any further calls to that function) is called a recursive function.

2. You can use recursive functions in Python to write clean, elegant code, and divide it
into smaller, organized chunks. On the other hand, you need to be very careful as it
might be easy to make a mistake and create a function which never terminates. You also
need to remember that recursive calls consume a lot of memory, and therefore may
sometimes be inefficient.

When using recursion, you need to take all its advantages and disadvantages into
consideration.

The factorial function is a classic example of how the concept of recursion can be put in
practice:

# Recursive implementation of the factorial function.


def factorial(n):
if n == 1: # The base case (termination condition.)
return 1
else:
return n * factorial(n - 1)

print(factorial(4))
# 4 * 3 * 2 * 1 = 24

Exercise 1

What will happen when you attempt to run the following snippet and why?

def factorial(n):
return n * factorial(n - 1)

print(factorial(4))

The factorial function has no termination condition (no base case) so Python will raise an
exception ( RecursionError: maximum recursion depth exceeded )

Exercise 2

What is the output of the following snippet?

def fun(a):
if a > 30:
return 3
else:
return a + fun(a + 3)

print(fun(25))

The output of the following code is:

56

Key takeaways: tuples


1. Tuples are ordered and unchangeable (immutable) collections of data. They can be
thought of as immutable lists. They are written in round brackets:

my_tuple = (1, 2, True, "a string", (3, 4), [5, 6], None)

print(my_tuple)

my_list = [1, 2, True, "a string", (3, 4), [5, 6], None]

print(my_list)

Each tuple element may be of a different type (i.e., integers, strings, booleans, etc.). What
is more, tuples can contain other tuples or lists (and the other way round).

2. You can create an empty tuple like this:

empty_tuple = ()
print(type(empty_tuple)) # outputs: <class 'tuple'>`

3. A one-element tuple may be created as follows:

one_elem_tuple_1 = ("one", ) # Brackets and a comma.

one_elem_tuple_2 = "one", # No brackets, just a comma.

If you remove the comma, you will tell Python to create a variable, not a tuple:

my_tuple_1 = 1

print(type(my_tuple_1)) # outputs: <class 'tuple'>

my_tuple_2 = 1 # This is not a tuple.

print(type(my_tuple_2)) # outputs: <class 'int'>

4. You can access tuple elements by indexing them:

my_tuple = (1, 2.0, "string", [3, 4], (5, ), True)

print(my_tuple[3]) # outputs: [3, 4]


5. Tuples are immutable, which means you cannot change their elements (you cannot
append tuples, or modify, or remove tuple elements). The following snippet will cause an
exception:

my_tuple = (1, 2.0, "string", [3, 4], (5, ), True)


my_tuple[2] = "guitar" # The TypeError exception will be raised.

However, you can delete a tuple as a whole:

my_tuple = 1, 2, 3,
del my_tuple():
print(my_tuple) # NameError: name 'my_tuple' is not defined`

6. You can loop through a tuple elements (Example 1, check if a specific element is
(not)present in a tuple (Example 2, use the len() function to check how many elements
there are in a tuple (Example 3, or even join/multiply tuples (Example 4

# Example 1
tuple_1 = (1, 2, 3)
for elem in tuple_1:
print(elem)

# Example 2

tuple_2 = (1, 2, 3, 4)
print(5 in tuple_2)
print(5 not in tuple_2)

# Example 3

tuple_3 = (1, 2, 3, 5)
print(len(tuple_3))

# Example 4

tuple_4 = tuple_1 + tuple_2


tuple_5 = tuple_3 * 2
print(tuple_4)
print(tuple_5)

EXTRA

You can also create a tuple using a Python built-in function called tuple() . This is
particularly useful when you want to convert a certain iterable (e.g., a list, range, string,
etc.) to a tuple:
my_tuple = tuple((1, 2, "string"))
print(my_tuple)
my_list = [2, 4, 6]
print(my_list) # outputs: [2, 4, 6]
print(type(my_list)) # outputs: <class 'list'>
tup = tuple(my_list)
print(tup) # outputs: (2, 4, 6)
print(type(tup)) # outputs: <class 'tuple'>

By the same fashion, when you want to convert an iterable to a list, you can use a Python
built-in function called list() :

tup = 1, 2, 3,
my_list = list(tup)
print(type(my_list)) # outputs: <class 'list'>

Key takeaways: dictionaries


1. Dictionaries are unordered*, changeable (mutable), and indexed collections of data.
(*In Python 3.6x dictionaries have become ordered by default.

Each dictionary is a set of key: value pairs. You can create it by using the following
syntax:

my_dictionary = {

key1: value1,

key2: value2,

key3: value3,

2. If you want to access a dictionary item, you can do so by making a reference to its key
inside a pair of square brackets (ex. 1 or by using the get() method (ex. 2

pol_eng_dictionary = {

"kwiat": "flower",

"woda": "water",
"gleba": "soil"

item_1 = pol_eng_dictionary["gleba"] # ex. 1


print(item_1) # outputs: soil
item_2 = pol_eng_dictionary.get("woda")
print(item_2) # outputs: water

3. If you want to change the value associated with a specific key, you can do so by
referring to the item's key name in the following way:

pol_eng_dictionary = {

"zamek": "castle",

"woda": "water",

"gleba": "soil"

pol_eng_dictionary["zamek"] = "lock"
item = pol_eng_dictionary["zamek"]
print(item) # outputs: lock

4. To add or remove a key (and the associated value), use the following syntax:

phonebook = {} # an empty dictionary


phonebook["Adam"] = 3456783958 # create/add a key-value pair
print(phonebook) # outputs: {'Adam': 3456783958}
del phonebook["Adam"]
print(phonebook) # outputs: {}

You can also insert an item to a dictionary by using the update() method, and remove
the last element by using the popitem() method, e.g.:

pol_eng_dictionary = {"kwiat": "flower"}

pol_eng_dictionary.update({"gleba": "soil"})

print(pol_eng_dictionary) # outputs: {'kwiat': 'flower', 'gleba': 'soil'}

pol_eng_dictionary.popitem()
print(pol_eng_dictionary) # outputs: {'kwiat': 'flower'}

5. You can use the for loop to loop through a dictionary, e.g.:

pol_eng_dictionary = {

"zamek": "castle",

"woda": "water",

"gleba": "soil"

for item in pol_eng_dictionary:


print(item)

# outputs: zamek
# woda
# gleba

6. If you want to loop through a dictionary's keys and values, you can use the items()
method, e.g.:

pol_eng_dictionary = {

"zamek": "castle",

"woda": "water",

"gleba": "soil"

for key, value in pol_eng_dictionary.items():


print("Pol/Eng ->", key, ":", value)

7. To check if a given key exists in a dictionary, you can use the in keyword:

pol_eng_dictionary = {

"zamek": "castle",
"woda": "water",

"gleba": "soil"

if "zamek" in pol_eng_dictionary:
print("Yes")
else:
print("No")

8. You can use the del keyword to remove a specific item, or delete a dictionary. To
remove all the dictionary's items, you need to use the clear() method:

pol_eng_dictionary = {

"zamek": "castle",

"woda": "water",

"gleba": "soil"

print(len(pol_eng_dictionary)) # outputs: 3
del pol_eng_dictionary["zamek"] # remove an item
print(len(pol_eng_dictionary)) # outputs: 2
pol_eng_dictionary.clear() # removes all the items
print(len(pol_eng_dictionary)) # outputs: 0
del pol_eng_dictionary # removes the dictionary

9. To copy a dictionary, use the copy() method:

pol_eng_dictionary = {

"zamek": "castle",

"woda": "water",

"gleba": "soil"

copy_dictionary = pol_eng_dictionary.copy()
Key takeaways: tuples and dictionaries
Exercise 1

What happens when you attempt to run the following snippet?

my_tup = (1, 2, 3)
print(my_tup[2])

The program will print 3 to the screen.

Exercise 2

What is the output of the following snippet?

tup = 1, 2, 3
a, b, c = tup
print(a * b * c)

The program will print 6 to the screen. The tup tuple elements have been "unpacked" in
the a , b , and c variables.

Exercise 3

Complete the code to correctly use the count() method to find the number of duplicates
of 2 in the following tuple.

tup = 1, 2, 3, 2, 4, 5, 6, 2, 7, 2, 8, 9
duplicates = # Write your code here.
print(duplicates) #
outputs: 4

tup = 1, 2, 3, 2, 4, 5, 6, 2, 7, 2, 8, 9
duplicates = tup.count(2)
print(duplicates) # outputs: 4

Exercise 4

Write a program that will "glue" the two dictionaries ( d1 and d2 ) together and create a
new one ( d3 ).

d1 = {'Adam Smith': 'A', 'Judy Paxton': 'B+'}


d2 = {'Mary Louis': 'A', 'Patrick White': 'C'}
d3 = {}
for item in (d1, d2):
# Write your code here.
print(d3)

Sample solution:

d1 = {'Adam Smith': 'A', 'Judy Paxton': 'B+'}


d2 = {'Mary Louis': 'A', 'Patrick White': 'C'}
d3 = {}
for item in (d1, d2):
d3.update(item)

print(d3)

Exercise 5

Write a program that will convert the my_list list to a tuple.

my_list = ["car", "Ford", "flower", "Tulip"]


t = # Write your code here.
print(t)

Sample solution:

my_list = ["car", "Ford", "flower", "Tulip"]


t = tuple(my_list)
print(t)

Exercise 6

Write a program that will convert the colors tuple to a dictionary.

colors = (("green", "#008000"), ("blue", "#0000FF")) # Write your code here. print

Sample solution:

colors = (("green", "#008000"), ("blue", "#0000FF"))


colors_dictionary = dict(colors)
print(colors_dictionary)

Exercise 7

What will happen when you run the following code?


my_dictionary = {"A": 1, "B": 2}
copy_my_dictionary = my_dictionary.copy()
my_dictionary.clear()
print(copy_my_dictionary)

The program will print {'A': 1, 'B': 2} to the screen.

Exercise 8

What is the output of the following program?

colors = {
"white": (255, 255, 255),
"grey": (128, 128, 128),
"red": (255, 0, 0),
"green": (0, 128, 0)
}

for col, rgb in colors.items():


print(col, ":", rgb)

python white : (255, 255, 255) grey : (128, 128, 128) red : (255, 0, 0) green :
(0, 128, 0)
Key takeaways (Python modules)
A lazy programmer is a programmer who looks for existing solutions and analyzes the
available code before they start to develop their own software from scratch.

1. If you want to import a module as a whole, you can do it using the import module_name
statement. You are allowed to import more than one module at once using a comma-
separated list. For example:

import mod1
import mod2, mod3, mod4

although the latter form is not recommended due to stylistic reasons, and it's better and
prettier to express the same intention in more a verbose and explicit form, such as:

import mod2
import mod3
import mod4

2. If a module is imported in the above manner and you want to access any of its entities,
you need to prefix the entity's name using dot notation. For example:

import my_module
result = my_module.my_function(my_module.my_data)

The snippet makes use of two entities coming from the my_module module: a function
named my_function() and a variable named my_data . Both names must be prefixed by
my_module. None of the imported entity names conflicts with the identical names existing
in your code's namespace.

3. You are allowed not only to import a module as a whole, but to import only individual
entities from it. In this case, the imported entities must not be prefixed when used. For
example:

from module import my_function, my_data


result = my_function(my_data)

The above way - despite its attractiveness - is not recommended because of the danger
of causing conflicts with names derived from importing the code's namespace.

4. The most general form of the above statement allows you to import all entities offered
by a module:
from my_module import *
result = my_function(my_data)

Note: this import's variant is not recommended due to the same reasons as previously
(the threat of a naming conflict is even more dangerous here).

5. You can change the name of the imported entity "on the fly" by using the as phrase of
the import . For example:

from module import my_function as fun, my_data as dat


result = fun(dat)

Exercise 1

You want to invoke the function make_money() contained in the module named mint . Your
code begins with the following line:

import mint

What is the proper form of the function's invocation?

mint.make_money()

Exercise 2

You want to invoke the function make_money() contained in the module named mint . Your
code begins with the following line:

from mint import make_money

What is the proper form of the function's invocation?

make_money()

Exercise 3

You've written a function named make_money on your own. You need to import a function
of the same name from the mint module and don't want to rename any of your previously
defined names. Which variant of the import statement may help you with the issue?

# sample solution from mint import make_money as make_more_money

Exercise 4

What form of the make_money function invocation is valid if your code starts with the
following line?

from mint import *


make_money()

Key takeaways (built-in Modules)


1. A function named dir() can show you a list of the entities contained inside an
imported module. For example:
import os dir(os)
prints out the list of all the os module's facilities you can use in your code.

2. The math module couples more than 50 symbols (functions and constants) that
perform mathematical operations (like sine() , pow() , factorial() ) or providing
important values (like π and the Euler symbol e).

3. The random module groups more than 60 entities designed to help you use pseudo-
random numbers. Don't forget the prefix "random", as there is no such thing as a real
random number when it comes to generating them using the computer's algorithms.

4. The platform module contains about 70 functions which let you dive into the
underlaying layers of the OS and hardware. Using them allows you to get to know more
about the environment in which your code is executed.

5. Python Module Index (https://docs.python.org/3/py-modindex.html is a community-


driven directory of modules available in the Python universe. If you want to find a module
fitting your needs, start your search there.

Exercise 1

What is the expected value of the result variable after the following code is executed?

import math
result = math.e == math.exp(1)

The output of the following code is:

True

Exercise 2

Complete the sentence) Setting the generator's seed with the same value each time your
program is run guarantees that...

... the pseudo-random values emitted from the random module will be exactly the same.

Exercise 3

Which of the platform module's functions will you use to determine the name of the CPU
running inside your computer?

The processor() function

Exercise 4

What is the expected output of the following snippet?

import platform
print(len(platform.python_version_tuple()))

The output of the following code is:

3
Key takeaways (How to create a module)
Notes

1. While a module is designed to couple together some related entities (functions,


variables, constants, etc.), a package is a container which enables the coupling of several
related modules under one common name. Such a container can be distributed as-is (as a
batch of files deployed in a directory sub-tree) or it can be packed inside a zip file.

2. During the very first import of the actual module, Python translates its source code into
the semi-compiled format stored inside the pyc files, and deploys these files into the
__pycache__ directory located in the module's home directory.

3. If you want to instruct your module's user that a particular entity should be treated as
private (i.e. not to be explicitly used outside the module) you can mark its name with
either the _ or __ prefix. Don't forget that this is only a recommendation, not an order.

4\. The names _shabang_, _shebang_, _hasbang_, _poundbang_, and _hashpling_


describe the digraph written as `#!`, used to instruct Unix-like OSs how the
Python source file should be launched. This convention has no effect under MS
Windows.

5. If you want convince Python that it should take into account a non-standard package's
directory, its name needs to be inserted/appended into/to the import directory list stored
in the path variable contained in the sys module.

6. A Python file named __init__.py is implicitly run when a package containing it is


subject to import, and is used to initialize a package and/or its sub-packages (if any). The
file may be empty, but must not be absent.

Exercise 1

You want to prevent your module's user from running your code as an ordinary script.
How will you achieve such an effect?

import sys
if __name__ == "__main__":
print "Don't do that!" sys.exit()`

Exercise 2

Some additional and necessary packages are stored inside the


D:\Python\Project\Modules directory. Write a code ensuring that the directory is
traversed by Python in order to find all requested modules.

import sys # note the double backslashes!


sys.path.append("D:\\Python\\Project\\Modules")

Exercise 3

The directory mentioned in the previous exercise contains a sub-tree of the following
structure:

abc |__ def |__ mymodule.py


Assuming that D:\Python\Project\Modules has been successfully appended to the
sys.path list, write an import directive letting you use all the mymodule entities.

import abc.def.mymodule

Key takeaways (Python pip)


1. A repository (or repo for short) designed to collect and share free Python code exists
and works under the name Python Package Index (PyPI) although it's also likely that you
come across a very niche name The Cheese Shop. The Shop's website is available at
https://pypi.org/.

2. To make use of The Cheese Shop the specialized tool has been created and its name is
pip (pip installs packages while pip stands for... ok, don't mind). As pip may not be
deployed as a part of standard Python installation, it is possible that you will need to
install it manually. Pip is a console tool.

3. To check pip's version one the following commands should be issued:

pip --version
or
pip3 --version

Check yourself which of these works for you in your OS' environment.

4. List of main pip activities looks as follows:

pip help _operation_ - shows brief pip's description;


pip list - shows list of currently installed packages;
pip show _package_name_ - shows package_name info including package's
dependencies;
pip search _anystring_ - searches through PyPI directories in order to find
packages which name contains anystring;
pip install _name_ - installs name system-wide (expect problems when you don't
have administrative rights);
pip install --user _name_ - install name for you only; no other your platform's user
will be able to use it;
pip install -U _name_ - updates previously installed package;
pip uninstall _name_ - uninstalls previously installed package;

Exercise 1

Where does the name "The Cheese Shop" come from?

It's a reference to an old Monty Python's sketch of the same name.

Exercise 2

Why should I ensure which one of pip and pip3 works for me?

When Python 2 and Python 3 coexist in your OS, it's likely that pip identifies the instance
of pip working with Python 2 packages only.

Exercise 3

How can I determine if my pip works with either Python 2 or Python 3?


pip --version will tell you that.

Exercise 4

Unfortunately, I don't have administrative right. What should I do to install a package


system-wide?

You have to ask your sysadmin - don't try to hack your OS!
Key takeaways (ASCII
1. Computers store characters as numbers. There is more than one possible way of
encoding characters, but only some of them gained worldwide popularity and are
commonly used in IT these are ASCII (used mainly to encode the Latin alphabet and
some of its derivates) and UNICODE (able to encode virtually all alphabets being used by
humans).

2. A number corresponding to a particular character is called a codepoint.

3. UNICODE uses different ways of encoding when it comes to storing the characters
using files or computer memory: two of them are UCS4 and UTF8 (the latter is the most
common as it wastes less memory space).

Exercise 1

What is BOM?

BOM Byte Order Mark) is a special combination of bits announcing encoding used by a
file's content (eg. UCS4 or UTFB.

Exercise 2

Is Python 3 _I18N_ed?

Yes, it's completely internationalized - we can use UNICODE characters inside our code,
read them from input and send to output.

Key takeaways (String basics)


1. Python strings are immutable sequences and can be indexed, sliced, and iterated like
any other sequence, as well as being subject to the in and not in operators. There are
two kinds of strings in Python:

one-line strings, which cannot cross line boundaries – we denote them using either
apostrophes ( 'string' ) or quotes ( "string" )

multi-line strings, which occupy more than one line of source code, delimited by
trigraphs:

''' string '''

or

""" string """

2. The length of a string is determined by the len() function. The escape character ( \ )
is not counted. For example:

print(len("\n\n"))

outputs 2 .
3. Strings can be concatenated using the + operator, and replicated using the *
operator. For example:

asterisk = '*'
plus = "+"
decoration = (asterisk + plus) * 4 + asterisk
print(decoration)

outputs *+*+*+*+* .

4. The pair of functions chr() and ord() can be used to create a character using its
codepoint, and to determine a codepoint corresponding to a character. Both of the
following expressions are always true:

chr(ord(character)) == character
ord(chr(codepoint)) == codepoint

5. Some other functions that can be applied to strings are:

list() – create a list consisting of all the string's characters;


max() – finds the character with the maximal codepoint;
min() – finds the character with the minimal codepoint.

6. The method named index() finds the index of a given substring inside the string.

Exercise 1

What is the length of the following string assuming there is no whitespaces between the
quotes?

""" """

Exercise 2

What is the expected output of the following code?

s = 'yesteryears'
the_list = list(s)
print(the_list[3:6])

The output of the following code:

['t', 'e', 'r']

Exercise 3

What is the expected output of the following code?


for ch in "abc":
print(chr(ord(ch) + 1), end='')

bcd

Prev

Key takeaways (String methods)


1. Some of the methods offered by strings are:

capitalize() – changes all string letters to capitals;


center() – centers the string inside the field of a known length;
count() – counts the occurrences of a given character;
join() – joins all items of a tuple/list into one string;
lower() – converts all the string's letters into lower-case letters;
lstrip() – removes the white characters from the beginning of the string;
replace() – replaces a given substring with another;
rfind() – finds a substring starting from the end of the string;
rstrip() – removes the trailing white spaces from the end of the string;
split() – splits the string into a substring using a given delimiter;
strip() – removes the leading and trailing white spaces;
swapcase() – swaps the letters' cases (lower to upper and vice versa)
title() – makes the first letter in each word upper-case;
upper() – converts all the string's letter into upper-case letters.

2. String content can be determined using the following methods (all of them return
Boolean values):

endswith() – does the string end with a given substring?


isalnum() – does the string consist only of letters and digits?
isalpha() – does the string consist only of letters?
islower() – does the string consists only of lower-case letters?
isspace() – does the string consists only of white spaces?
isupper() – does the string consists only of upper-case letters?
startswith() – does the string begin with a given substring?

Exercise 1

What is the expected output of the following code?

for ch in "abc123XYX":
if ch.isupper():
print(ch.lower(), end='')
elif ch.islower():
print(ch.upper(), end='')
else:
print(ch, end='')
ABC123xyz

Exercise 2

What is the expected output of the following code?

s1 = 'Where are the snows of yesteryear?'


s2 = s1.split()
print(s2[-2])

The output of the following code is:

of

Exercise 3

What is the expected output of the following code?

the_list = ['Where', 'are', 'the', 'snows?']


s = '*'.join(the_list)
print(s)

The output of the following code is:

Where*are*the*snows?

Exercise 4

What is the expected output of the following code?

s = 'It is either easy or impossible'


s = s.replace('easy', 'hard').replace('im', '')
print(s)

It is either hard or possible

Key takeaways
1. Strings can be compared to strings using general comparison operators, but comparing
them to numbers gives no reasonable result, because no string can be equal to any
number. For example:

string == number is always False ;


string != number is always True ;
string >= number always raises an exception.

2. Sorting lists of strings can be done by:

a function named sorted() , creating a new, sorted list;


a method named sort() , which sorts the list in situ
3. A number can be converted to a string using the str() function.

4. A string can be converted to a number (although not every string) using either the
int() or float() function. The conversion fails if a string doesn't contain a valid number
image (an exception is raised then).

Exercise 1

Which of the following lines describe a true condition?

'smith' > 'Smith' 'Smiths' < 'Smith' 'Smith' > '1000' '11' < '8'

1, 3 and 4

Exercise 2

What is the expected output of the following code?

s1 = 'Where are the snows of yesteryear?'


s2 = s1.split()
s3 = sorted(s2)
print(s3[1])

The output of the following code is:

are

Exercise 3

What is the expected result of the following code?

s1 = '12.8'
i = int(s1)
s2 = str(i)
f = float(s2)
print(s1 == s2)

False

Key takeaways (Exceptions)


1. An exception is an event in a program execution's life caused by an abnormal situation.
The exception should he handled to avoid program termination. The part of your code
that is suspected of being the source of the exception should be put inside the try
branch.

When the exception happens, the execution of the code is not terminated, but instead
jumps into the except branch. This is the place where the handling of the exception
should take place. The general scheme for such a construction looks as follows:

:
# The code that always runs smoothly.
:
try:
:
# Risky code.
:
except:
:
# Crisis management takes place here.
:
:
# Back to normal.
:

2. If you need to handle more than one exception coming from the same try branch ,you
can add more than one except branch, but you have to label them with different
exception names, like this:

:
# The code that always runs smoothly.
:
try:
:
# Risky code.
:
except Except_1:
# Crisis management takes place here.
except Except_2:
# We save the world here.
:
# Back to normal.
:

At most, one of the except branches is executed – none of the branches is performed
when the raised exception doesn't match to the specified exceptions.

3. You cannot add more than one anonymous (unnamed) except branch after the named
ones.

:
# The code that always runs smoothly.
:
try:
:
# Risky code.
:
except Except_1:
# Crisis management takes place here.
except Except_2:
# We save the world here.
except:
# All other issues fall here.
:
# Back to normal.
:

Exercise 1

What is the expected output of the following code?

try:
print("Let's try to do this")
print("#"[2])
print("We succeeded!")
except:
print("We failed")
print("We're done")

Let's try to do this


We failed
We're done

Exercise 2

What is the expected output of the following code?

try:
print("alpha"[1/0])
except ZeroDivisionError:
print("zero")
except IndexingError:
print("index")
except:
print("some")

zero

Key takeaways
1. You cannot add more than one anonymous (unnamed) except branch after the named
ones.

:
# The code that always runs smoothly.
:
try:
:
# Risky code.
:
except Except_1:
# Crisis management takes place here.
except Except_2:
# We save the world here.
except:
# All other issues fall here.
:
# Back to normal.
:

2. All the predefined Python exceptions form a hierarchy, i.e. some of them are more
general (the one named BaseException is the most general one) while others are more or
less concrete (e.g. IndexError is more concrete than LookupError ).

You shouldn't put more concrete exceptions before the more general ones inside the
same except branche sequence. For example, you can do this:

try:
# Risky code.
except IndexError:
# Taking care of mistreated lists
except LookupError:
# Dealing with other erroneous lookups

but don't do that (unless you're absolutely sure that you want some part of your code to
be useless)

try:
# Risky code.
except LookupError:
# Dealing with erroneous lookups
except IndexError:
# You'll never get here

3. The Python statement raise ExceptionName can raise an exception on demand. The
same statement, but lacking ExceptionName, can be used inside the try branch only,
and raises the same exception which is currently being handled.

4. The Python statement assert expression evaluates the expression and raises the
AssertError exception when the expression is equal to zero, an empty string, or None .
You can use it to protect some critical parts of your code from devastating data.

Exercise 1

What is the expected output of the following code?

try:
print(1/0)
except ZeroDivisionError:
print("zero")
except ArithmeticError:
print("arith")
except:
print("some")

The output of the following code is:

zero

Exercise 2

What is the expected output of the following code?

try:
print(1/0)
except ArithmeticError:
print("arith")
except ZeroDivisionError:
print("zero")
except:
print("some")

The output of the following code is:

arith

Exercise 3

What is the expected output of the following code?

def foo(x):
assert x
return 1/x
try:
print(foo(0))
except ZeroDivisionError:
print("zero")
except:
print("some")

The output of the following code is:

some

Key takeaways
1. Some abstract built-in Python exceptions are:

ArithmeticError ,
BaseException ,
LookupError .

2. Some concrete built-in Python exceptions are:

AssertionError ,
ImportError ,
IndexError ,
KeyboardInterrupt ,
KeyError ,
MemoryError ,
OverflowError .

Exercise 1

Which of the exceptions will you use to protect your code from being interrupted through
the use of the keyboard?

KeyboardInterrupt

Exercise 2

What is the name of the most general of all Python exceptions?

BaseException

Exercise 3
Which of the exceptions will be raised through the following unsuccessful evaluation?

huge_value = 1E250 ** 2

OverflowError
Key takeaways (oop)
1. A class is an idea (more or less abstract) which can be used to create a number of
incarnations – such an incarnation is called an object.

2. When a class is derived from another class, their relation is named inheritance. The
class which derives from the other class is named a subclass. The second side of this
relation is named superclass. A way to present such a relation is an inheritance diagram,
where:

superclasses are always presented above their subclasses;


relations between classes are shown as arrows directed from the subclass toward
its superclass.

3. Objects are equipped with:

a name which identifies them and allows us to distinguish between them;


a set of properties (the set can be empty)
a set of methods (can be empty, too)

4. To define a Python class, you need to use the class keyword. For example:

class This_Is_A_Class:
pass

5. To create an object of the previously defined class, you need to use the class as if it
were a function. For example:

this_is_an_object = This_Is_A_Class()

Exercise 1

If we assume that pythons, vipers, and cobras are subclasses of the same superclass,
Snake, reptile, vertebrate, animal – all these answers are acceptable.

Exercise 2

Try to name a few python class subclasses.


Indian python, African rock python, ball python, Burmese python – the list is long.

Exercise 3

Can you name one of your classes just "class"?


No, you can't – class is a keyword!

Key takeaways (Stack, queue)


1. A stack is an object designed to store data using the LIFO model. The stack usually
accomplishes at least two operations, named push() and pop().

2. Implementing the stack in a procedural model raises several problems which can be
solved by the techniques offered by OOP (Object Oriented Programming):
3. A class method is actually a function declared inside the class and able to access all
the class's components.

4. The part of the Python class responsible for creating new objects is called the
constructor, and it's implemented as a method of the name __init__ .

5. Each class method declaration must contain at least one parameter (always the first
one) usually referred to as self , and is used by the objects to identify themselves.

6. If we want to hide any of a class's components from the outside world, we should start
its name with __ . Such components are called private.

Exercise 1

Assuming that there is a class named Snakes , write the very first line of the Python class
declaration, expressing the fact that the new class is actually a subclass of Snake.

class Python(Snakes):

Exercise 2

Something is missing from the following declaration – what?

class Snakes:
def __init__():
self.sound = 'Sssssss'

The __init__() constructor lacks the obligatory parameter (we should name it self to
stay compliant with the standards).

Exercise 3

Modify the code to guarantee that the venomous property is private.

class Snakes:
def __init__(self):
self.venomous = True

The code should look as follows:

class Snakes:
def __init__(self):
self.__venomous = True

Key takeaways (class properties)


1. An instance variable is a property whose existence depends on the creation of an
object. Every object can have a different set of instance variables.
Moreover, they can be freely added to and removed from objects during their lifetime. All
object instance variables are stored inside a dedicated dictionary named __dict__ ,
contained in every object separately.

2. An instance variable can be private when its name starts with __ , but don't forget that
such a property is still accessible from outside the class using a mangled name
constructed as _ClassName__PrivatePropertyName .

3. A class variable is a property which exists in exactly one copy, and doesn't need any
created object to be accessible. Such variables are not shown as __dict__ content.
All a class's class variables are stored inside a dedicated dictionary named __dict__ ,
contained in every class separately.

4. A function named hasattr() can be used to determine if any object/class contains a


specified property.

For example:

class Sample:
gamma = 0 # Class variable.
def __init__(self):
self.alpha = 1 # Instance variable.
self.__delta = 3 # Private instance variable.
obj = Sample()
obj.beta = 2 # Another instance variable (existing only inside the "obj" instance.
print(obj.__dict__)

The code outputs:

{'alpha': 1, '_Sample__delta': 3, 'beta': 2}

output

Exercise 1

Which of the Python class properties are instance variables and which are class
variables? Which of them are private?

class Python:
population = 1
victims = 0
def __init__(self):
self.length_ft = 3
self.__venomous = False

population and victims are class variables, while length and __venomous are instance
variables (the latter is also private).

Exercise 2

You're going to negate the __venomous property of the version_2 object, ignoring the
fact that the property is private. How will you do this?
version_2 = Python()
version_2._Python__venomous = not version_2._Python__venomous

Exercise 3

Write an expression which checks if the version_2 object contains an instance property
named constrictor (yes, constrictor!.

hasattr(version_2, 'constrictor')

Key takeaways (class built-in methods)


1. A method is a function embedded inside a class. The first (or only) parameter of each
method is usually named self , which is designed to identify the object for which the
method is invoked in order to access the object's properties or invoke its methods.

2. If a class contains a constructor (a method named __init__ ) it cannot return any


value and cannot be invoked directly.

3. All classes (but not objects) contain a property named __name__ , which stores the
name of the class. Additionally, a property named __module__ stores the name of the
module in which the class has been declared, while the property named __bases__ is a
tuple containing a class's superclasses.

For example:

class Sample:
def __init__(self):
self.name = Sample.__name__
def myself(self):
print("My name is " + self.name + " living in a " + Sample.__module__)

obj = Sample()
obj.myself()

The code outputs:

My name is Sample living in a __main__

output

Exercise 1

The declaration of the Snake class is given below. Enrich the class with a method named
increment() , adding 1 to the __victims property.

class Snake:
def __init__(self):
self.victims = 0`

class Snake:
def __init__(self):
self.victims = 0
def increment(self):
self.victims += 1

Exercise 2

Redefine the Snake class constructor so that is has a parameter to initialize the victims
field with a value passed to the object during construction.

class Snake:
def __init__(self, victims):
self.victims = victims

Exercise 3

Can you predict the output of the following code?

class Snake:
pass

class Python(Snake):
pass

print(Python.__name__, 'is a', Snake.__name__)


print(Python.__bases__[0].__name__, 'can be', Python.__name__)

Python is a Snake Snake can be Python

Key takeaways
1. A method named __str__() is responsible for converting an object's contents into a
(more or less) readable string. You can redefine it if you want your object to be able to
present itself in a more elegant form. For example:

class Mouse:
def __init__(self, name):
self.my_name = name
def __str__(self):
return self.my_name

the_mouse = Mouse('mickey')
print(the_mouse) # Prints "mickey".

2. A function named issubclass(Class_1, Class_2) is able to determine if Class_1 is a


subclass of Class_2 . For example:
class Mouse:
pass

class LabMouse(Mouse):
pass

print(issubclass(Mouse, LabMouse), issubclass(LabMouse, Mouse)) # Prints "False Tr

3. A function named isinstance(Object, Class) checks if an object comes from an


indicated class. For example:

class Mouse:
pass

class LabMouse(Mouse):
pass

mickey = Mouse()
print(isinstance(mickey, Mouse), isinstance(mickey, LabMouse)) # Prints "True Fals

4. A operator called is checks if two variables refer to the same object. For example:

class Mouse:
pass

mickey = Mouse()
minnie = Mouse()
cloned_mickey = mickey
print(mickey is minnie, mickey is cloned_mickey) # Prints "False True".

5. A parameterless function named super() returns a reference to the nearest


superclass of the class. For example:

class Mouse:
def __str__(self):
return "Mouse"

class LabMouse(Mouse):
def __str__(self):
return "Laboratory " + super().__str__()

doctor_mouse = LabMouse();
print(doctor_mouse) # Prints "Laboratory Mouse".
6. Methods as well as instance and class variables defined in a superclass are
automatically inherited by their subclasses. For example:

class Mouse:
Population = 0
def __init__(self, name):
Mouse.Population += 1
self.name = name
def __str__(self):
return "Hi, my name is " + self.name

class LabMouse(Mouse):
pass

professor_mouse = LabMouse("Professor Mouser")


print(professor_mouse, Mouse.Population) # Prints "Hi, my name is Professor Mouser

7. In order to find any object/class property, Python looks for it inside:

the object itself;


all classes involved in the object's inheritance line from bottom to top;
if there is more than one class on a particular inheritance path, Python scans them
from left to right;
if both of the above fail, the AttributeError exception is raised.

8. If any of the subclasses defines a method/class variable/instance variable of the same


name as existing in the superclass, the new name overrides any of the previous instances
of the name. For example:

class Mouse:
def __init__(self, name):
self.name = name
def __str__(self):
return "My name is " + self.name
class AncientMouse(Mouse):
def __str__(self):
return "Meum nomen est " + self.name
mus = AncientMouse("Caesar") # Prints "Meum nomen est Caesar"
print(mus)

Exercises
Scenario

Assume that the following piece of code has been successfully executed:

class Dog:
kennel = 0
def __init__(self, breed):
self.breed = breed
Dog.kennel += 1
def __str__(self):
return self.breed + " says: Woof!"

class SheepDog(Dog):
def __str__(self):
return super().__str__() + " Don't run away, Little Lamb!"

class GuardDog(Dog):
def __str__(self):
return super().__str__() + " Stay where you are, Mister Intruder!"

rocky = SheepDog("Collie")
luna = GuardDog("Dobermann")

Now answer the questions from exercises 14.

Exercise 1

What is the expected output of the following piece of code?

print(rocky)
`print(luna)

Collie says: Woof! Don't run away, Little Lamb!


Dobermann says: Woof! Stay where you are, Mister Intruder!

Exercise 2

What is the expected output of the following piece of code?

print(issubclass(SheepDog, Dog), issubclass(SheepDog, GuardDog))

print(isinstance(rocky, GuardDog), isinstance(luna, GuardDog))

True False False True

Exercise 3

What is the expected output of the following piece of code?

print(luna is luna, rocky is luna)


print(rocky.kennel)

True False 2

Exercise 4
Define a SheepDog 's subclass named LowlandDog , and equip it with an __str__() method
overriding an inherited method of the same name. The new dog's __str__() method
should return the string "Woof! I don't like mountains!" .

class LowlandDog(SheepDog):
def __str__(self):
return Dog.__str__(self) + " I don't like mountains!"

Key takeaways (oop exceptions)


1. The else: branch of the try statement is executed when there has been no exception
during the execution of the try: block.

2. The finally: branch of the try statement is always executed.

3. The syntax except _Exception_Name_ as an _exception_object_: lets you intercept an


object carrying information about a pending exception. The object's property named
args (a tuple) stores all arguments passed to the object's constructor.

4. The exception classes can be extended to enrich them with new capabilities, or to
adopt their traits to newly defined exceptions.

For example:

try:
assert __name__ == "__main__"
except:
print("fail", end=' ')
else:
print("success", end=' ')
finally:
print("done")

The code outputs: success done .

Exercise 1

What is the expected output of the following code?

import math
try:
print(math.sqrt(9))
except ValueError:
print("inf")
else:
print("fine")

3.0 fine
Exercise 2

What is the expected output of the following code?

import math

try: print(math.sqrt(-9))
except ValueError:
print("inf")
else:
print("fine")
finally:
print("the end")

inf the end

Exercise 3

What is the expected output of the following code?

import math

class NewValueError(ValueError):
def __init__(self, name, color, state):
self.data = (name, color, state)

try:
raise NewValueError("Enemy warning", "Red alert", "High readiness")
except NewValueError as nve:
for arg in nve.args:
print(arg, end='! ')

The output of the following code :

Enemy warning! Red alert! High readiness!

You might also like