Python Institute Open Education & Development Group Provided by Edube Interactive
- Python Essentials 1 - PCAP-30-02 Certification
- Module 1
- Module 2
- Module 3
- Module 4
- Additional Notes
A Program is a set of instructions for the computer to execute that completes a series of tasks or operations on the system.
Natural Languages and Programming Languages contain four key aspects in order to be understood widely:
- alphabet
- lexis
- syntax
- semantics
An Instruction List is a complete set of known commands by the Machine Language. In Machine Language, the Instruction List (IL) is the alphabet.
A High-Level Programming Language is written using symbols, words and conventions easily read by humans.
Source Code is a program written in a high-level programming language.
A Script is a text file that contains instructions written in a high-level programming language.
In contrast, a Low-Level Programming Language is the actual Machine Code executed by the computers Instruction List.
Low-level languages are extremely difficult for humans to read and understand at face value, but are the fastest for a computer to complete.
Computer Programming is the act of writing a programming language in an order that achieves the desired effect or output.
Once a program is written in a programming language it needs to be translated so the computer can execute it. There are two different ways of transforming a program from a high-level programming language into (low-level) machine language.
- source code translated once down to machine code
- translation must be re-completed if the source code is modified
- the machine code executable file (ie. app.exe) is distributed to users
- users run the executable machine code directly on their machine systems
- usually executes code faster
- only the programmer needs the compiler
- machine code is difficult for end users to decipher, but easy to execute
- compilation can be very time consuming
- programmer needs as many compilers as hardware platforms the code is to be run on (Linux, Mac, Microsoft)
- the Interpreter translates the code every time it is executed
- the source code cannot distribute as-is
- the users machine needs the interpreter to be able to translate the source code into machine code to execute it
- reads a raw source code file text
- checks the text lines for language errors A. finds an error, program stops, shows error message B. no errors found, continue
- interpreter executes the line and continues to the next line
- read-check-execute can be repeated many times
- some code may execute before an error is even found
- code can run as soon as its written, as code is translated at runtime
- code can be run on computers using difference machine languages (no separate compilation for each hardware platform)
- code executes not as fast as machine code because the interpreter shares power with the computer
- end-users need to have the correct interpreter on their system to run the code
- an interpreted, object-oriented, high-level programming language
- named after Monty Python's Flying Circus (BBC TV Comedy sketch series)
- created by Guido van Rossum (b. 1956, Netherlands) between 1989-1999
Guido van Rossum presented in 1999 "Computer Programming for Everybody" proposal to DARPA:
- an easy and intuitive language just as powerful as those of the major competitors;
- open source, so anyone can contribute to its development;
- code that is as understandable as plain English;
- suitable for everyday tasks, allowing for short development times.
- Direct Competitors: Perl, Ruby
- web development
- scientific and numeric computing
- education
- desktop GUIs
- software development
- business operations
- CPython is the default implementation of the python programming language (Python Software Foundation)
- Cython is a superset of python that compiles python and C code
- Jython is a superset of python written in integrate with Java apps
- PyPy & RPython are a subset of python within python
Tools Needed for IDLE: Integrated Development and Learning Environment
- a code editor is a tool used to write python code
- a console is a command-line interpreter which lets you interact with your OS and execute Python commands and scripts
- a debugger is a tool that launches code step-by-step and inspect it at each moment of execution
Data types, variables, basic input-output operations, and basic operators.
- write and run simple python programs
- python literals, operators and expressions
- variables and the rules that govern them
- performing basic input and output operations
Comments are used to make your programs easier to understand, and also to disable pieces of code that are currently not needed
# comment like this
print("some action")
A function may cause an effect or result in a value*, and are provided with arguments.
They are built-in to the python language, provided by a python module, or custom written by a python programmer.****
Function arguments can be anonymous or provided by name; but all functions must be invoked by wrapping arguments in parentheses after the function name (function invocation).
print()
>
print("hello world")
> hello world
Functions must be declared prior to the where said function is invoked.
# INVALID: invoking the function before definition
customPrint(message="hello world")
> NameError
# defining the function
def customPrint(message=""):
print("custom print said:", message)
# invoking the function
customPrint(message="hello world")
> custom print said: hello world
NameError: name 'customPrint' is not defined
The print() function below:
- arguments: takes 0 or more
- in func: converts arguments into a human readable format
- effect: sends the resulting data to the output device (ie. the console)
Unlike most programming languages, Python requires that there cannot be more than one instruction in a line.
# INVALID
print("hello")print("world")
> SyntaxError
Functions with keyword arguments follow two specific rules:
- a keyword argument consists of three elements:
- a keyword identifying the argument
- an equal sign
- a value assigned to that argument
- any keyword arguments must be put after the last positional argument
# INVALID
print(end="end.", "This is the ")
> Error
# OK!
print("This is the ", end="end.")
> This is the end.
print("This is the", "end.", sep=" ")
> This is the end.
print("Hello arg...", end=" this is the end.", sep="-")
> Hello arg... this is the end.
print("My", "name", "is", "Monty", "Python.", sep="-")
> My-name-is-Monty-Python.
print("My", "name", "is", sep="_", end="*")
print("Monty", "Python.", sep="*", end="*\n")
> My_name_is*Monty*Python.*
>
Functions do not belong to any data: it gets data, it may create new data, and it may return data
result = function(arg)
A method is owned by the data it works for, while a function is owned by the whole code; methods behave functions, but can change the internal state of the data from which it was invoked
result = data.method(arg)
Literals are notations for representing some fixed value in code.
Numeric Literals express different number systems:
Binary numbers use a base 2 system; binary 1010 is 10 in decimal
Octal numbers use base 8
print(0o123)
Hexadecimal numbers use base 16
print(0x123)
Scientific numbers use base 10
print(3E8, 3e8) # 300000000
Integers (int) numbers without a fractional component
print(256, -1)
Floating-point numbers (float) numbers express a fraction
print(2.546, 2.5, -0.4, .4, 4.)
Boolean Literals (bool) express truthfulness (True, False)
print(True)
print(False)
print(True > False) # True
print(True < False) # False
String Literals (string) express text values; can be empty ""
The backslash \ is a unique character that effects the way the subsequent character is treated by the program
# w/o backslash INVALID
print("I like "Monty Python"")
> SyntaxError
# w/ backslash OK!
print("I like \"Monty Python\"")
# or
print('I like "Monty Python"')
print('', "")
None Literal or NoneType (none) object represents the absence of a value
Operators are symbols that act on values and perform mathematical operations
An Expression is a combination of values, variables, operators, or calls to functions that evaluate to a value
The Binding of the operator determines the order of computations performed. Most operators follow left-sided binding, but some cases use right-side binding (e.g. exponentiation)
The integer vs. float rule:
# if both args are int, result is an int
2 ** 3 = 8
# if at least one arg is float, result is a float
2 ** 3. = 8.0
2. ** 3 = 8.0
2. ** 3. = 8.0
Unary Operators takes one operand, to negates or makes a value positive
+2 is 2
+(-2) is 2
2 vs -2
Addition follows int v. float rule
2 + 3 = 5
2 + 3. = 5.0
Subtraction follows int v. float rule
2 - 3 = -1
2 - 3. = -1.0
Exponentiation or Exponents follow int v. float rule; uses right-sided binding
2 ** 3 = 8
2 ** 3. = 8.0
2 ** 3 ** 2
= 2 ** (3 ** 2)
= 2 ** 9
= 512
Multiplication Operator follows int v. float rule
6 * 2 = 12
6 * 2. = 12.0
1. * 3 = 3.0
2. * 3. = 6.0
Division operator always produces a float
6 / 3 = 2.0
6 / 3. = 2.0
1. / 3 = 2.0
2. / 3. = 2.0
Integer Division uses Floor Division to conform the result to the integer vs. float rule by always rounding the resulting to the lesser integer value
# round int
6 // 3 = 2
# round float
6 // 3. = 2.0
1. // 3 = 0.0
2. // 3. = 0.0
# int rounded down
6 // 4 = 1 1.5 -> 1
-6 // 4 = -2 -1.5 -> -2
# float rounded down
1. // 4 = 1.0 0.25 -> -0.0
2. // -4 = -2.0 -0.5 -> -1.0
Remainder (Modulo) returns the remaining values after the division operation, follows int v. float rule
ZeroDivisionError applies to division, integer division and the remainder operations
The Concatenation operator using the + symbol to join strings together ("string" + "string")
print("hello" + " " + "world")
> hello world
The Replication operator uses the * symbol to repeat a string some integer number of times; cannot replicate a string using a floating point value
string * integer
integer * string
# INVALID
string * float
> TypeError
Priorities of Operators perform higher priority operations before lower ones.
Python generally follows the PEMDAS Rule from mathematics:
priority | operator | note |
---|---|---|
1 | +, - | unary |
2 | ** | right-sided bindings |
3 | *, /, //, % | |
4 | +, - | binary |
Shortcut Operators:
Expression | Shortcut |
---|---|
a = a + 1 | a += 1 |
a = a - 1 | a -= 1 |
x = x * 2 | x *= 2 |
x = x / 2 | x /= 2 |
x = x // 2 | x //= 2 |
y = y ** 3 | y **= 3 |
z = z % z | z %= z |
A Variable is a named location reserved to store values in memory. Auto-initialized when you assign a variable a value.
Each variables must have a unique name, an Identifier, non-empty sequence of character, must begin with underscore or letter and cannot be a python keyword
a_string = "hello world"
times_int = 2
rand_float = 29.
repeat_string = a_string * times_int
print(repeat_string)
> hello worldhello world
Reserved Python Keywords:
False, None, True, and, as, assert, break, class, continue, def, del, elif, else, except, finally, for, from, global, if, import, in, is, lambda, nonlocal, not, or, pass, raise, return, try, while, with, yield
A Compound Assignment Operator (Shortcut Operators) modify the values assigned to variables
var += 1
var /= 2
Type Casting is used to coerce a value to be interpreted as a certain type
int(5.)
int("5")
# 5
float("2.5")
# 2.5
str(45)
# "45"
Boolean values, conditional execution, loops, lists and list processing, logical and bitwise operations.
Comparison Operators are used to check the truthiness between two values.
Operator | Description | Example |
---|---|---|
== | returns if operands' values are equal, and False otherwise | x == y # False x == z # True |
!= | returns True if operands' values are not equal, and False otherwise | x != y # True x != z # False |
> | True if the left operand's value is greater than the right operand's value, and False otherwise | x > y # False y > z # True |
< | True if the left operand's value is less than the right operand's value, and False otherwise | x < y # True y < z # False |
>= (≥) | True if the left operand's value is greater than or equal to the right operand's value, and False otherwise | x >= y # False x >= z # True y >= z # True |
<= (≤) | True if the left operand's value is less than or equal to the right operand's value, and False otherwise | x <= y # True x <= z # True y <= z # False |
A Conditional Statement uses a variable or expression that evaluates to a boolean, then executes the conditional statement body.
- do not mix tab and space indentation
- conditions are nestable, and indentation improves readability
if-elif-else
is also known as a cascadeelse
is always the last branch of the cascadeelse
must precede anif
statementelse
is an optional part of the cascade- if
else
branch in cascade, only one branch executed - if no
else
branch, is possible no branch executed
- if
Example Code:
# IF (single)
if this_is_true:
do_this_if_true()
always_do_this()
# IF-ELSE
if this_is_true:
do_this_if_true()
else:
do_this_otherwise()
always_do_this()
# IF-ELIF-ELSE is also known as a cascade
if the_weather_is_good:
go_for_a_walk()
elif tickets_are_available:
go_to_the_theater()
elif table_is_available:
go_for_lunch()
else:
play_chess_at_home()
always_drink_water()
Loops repeat actions in the Loop Body
Infinite Loops aka endless loops
Press Ctrl-C (or Ctrl-Break) in the console to cause a KeyboardInterrupt and exit an endless loop from continuing.
while
loops repeat indented code in the loop's body, as long as the condition evaluates to True
. If the condition is False
the body is not executed at all. The body should be able to change the condition's value to avoid infinite loops.
# Example 1
while True:
print("Stuck in an infinite loop.")
# Example 2
counter = 5
while counter > 2:
print(counter)
counter -= 1
for
loops iterate over a collection of data item by item.
# 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)
The break
keyword exits the loop immediately, and unconditionally ends the loop body operations. The program begins at the next instruction after the loop's body.
The continue
keyword will proceed to the next loop in the sequence and immediately recheck the loop's conditional expression.
Logical operators connect conditional statements together forming the basis of computer logic.
not
Logical Negations inverts boolean values, high priority
A | not A |
---|---|
False | True |
True | False |
and
Logical Conjunction both must be true, for statement to be true
A | B | A and B |
---|---|---|
False | False | False |
False | True | False |
True | False | False |
True | True | True |
or
Logical Disjunction one must be true, for statement to be false
A | B | A or B |
---|---|---|
False | False | False |
False | True | True |
True | False | True |
True | True | True |
Bitwise Operators manipulate single bits of data (must be integers 0/1, no floats)
&
(ampersand) bitwise conjunction|
(bar) bitwise disjunction~
(tilde) bitwise negation^
(caret) bitwise exclusive or (xor)
A | B | A & B | A | B | A ^ B |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 0 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
A | ~ A |
---|---|
0 | 1 |
1 | 0 |
Bitwise operators to manipulate single bits of data. Logical operators do not penetrate into the bit level of its argument.
Python Bitwise Examples:
Bitwise Operator | Bitwise Examples | In Binary |
---|---|---|
Example: | x = 15 y = 16 |
0000 1111 0001 0000 |
& bitwise and |
x & y = 0 |
0000 0000 |
| bitwise or |
x | y = 31 |
0001 1111 |
~ bitwise not |
~ x = 240* |
1111 0000 |
^ bitwise xor |
x ^ y = 31 |
0001 1111 |
>> bitwise right shift |
y >> 1 = 8 |
0000 1000 |
<< bitwise left shift |
y << 3 = |
1000 0000 |
Lists is a type of data that stores multiple objects, it is an ordered and mutable collection of comma-separated items between square brackets. Lists can be indexed and updated.
List Indexing is the operation of selecting an element from the list, but any expression can be the index
# create a list
numbers = [10, 5, 7, 2, 1]
# indexing the list
numbers[4]
# indexing the list using an expression
i = 2
numbers[i * 2]
= numbers[4]
# list can be nested
my_list = [1, "a", ["list", 2], False]
The length of a list may vary (dynamic entity)
len()
function returns the number of elements currently stored inside the list
del
keyword removes the given item from the list, (note: cannot access or remove an element that does not exist)
A Negative Indexing gets the item starting from the end of the list
numbers = [0,1,2,3,4,5]
print(numbers[-2])
> 4
The list.append()
method adds a new element to the end of the list
numbers = []
for i in range(1,5):
numbers.append(i)
print(numbers)
> [1, 2, 3, 4]
The list.insert(location, value)
method adds a new element at any location in the list, shifting the existing location elements to the right
numbers = []
for i in range(1,5):
numbers.insert(0, i)
print(numbers)
> [4, 3, 2, 1]
numbers = []
for i in range(1,5):
numbers.insert(-1, i)
print(numbers)
> [2, 3, 4, 1]
The in
keyword is used to loop through the elements in a list
my_list = ["hello", "world"]
for i in my_list:
print(i, end="")
> helloworld
The list.sort()
method reorders the elements in non-decreasing order
The list.reverse()
method reverses the order of the elements in the list
numbers = []
for i in range(1,5):
numbers.insert(-2, i)
print(numbers)
> [3, 4, 2, 1]
numbers.sort()
print(numbers)
> [1, 2, 3, 4]
numbers.reverse()
print(numbers)
> [4, 3, 2, 1]
Lists differ from ordinary variables because the name of a list references the name of a memory location where the list is stored
list_1 = [1]
list_2 = list_1
list_1[0] = 2
print(list_2)
> [2]
# not 1, because updating list_1,
# updates the single memory location
# that both lists reference
A list slice
makes a new copy or a list, or part of a list
# copies the entire list
list_1 = [1]
list_2 = list_1[:]
list_1[0] = 2
print(list_2)
> [1]
# slice part of a list
# list_slice[start:stop]
list_1 = [10, 8, 6, 4, 2]
list_2 = list_1[1:3]
print(list_2)
> [8, 6]
# negative indices are valid
my_list = [10, 8, 6, 4, 2]
new_list = my_list[2:-1]
print(new_list)
> [6, 4, 2]
# make empty list if start index is negative
my_list = [10, 8, 6, 4, 2]
new_list = my_list[-1:1]
print(new_list)
> []
# excluding start will begin from 0 index
# my_list[:end] => my_list[0:end]
my_list = [10, 8, 6, 4, 2]
new_list = my_list[:3]
print(new_list)
> [10, 8, 6]
# excluding end will end on an index equal to the len of the list
# my_list[start:] => my_list[start:len(my_list)]
my_list = [10, 8, 6, 4, 2]
new_list = my_list[3:]
print(new_list)
> [4, 2]
Use the del
keyword to delete a slice from a list:
# note: this does not produce any new list
my_list = [10, 8, 6, 4, 2]
del my_list[1:3]
print(my_list)
> [10, 4, 2]
# delete all the elements inside the list
my_list = [10, 8, 6, 4, 2]
del my_list[:]
print(my_list)
> []
# or delete the list entirely
del my_list
print(my_list)
> NameError: name 'my_list' is not defined
The in
and not in
keywords are able to determine if a value is store inside a list or not
my_list = [0, 3, 12, 8, 2]
print(5 in my_list)
> False
print(5 not in my_list)
> True
print(12 in my_list)
> True
List Comprehension is used to create list data on-the-fly during program execution (is not described statically)
# shorthand list comprehensive
list = [expression for element in list if conditional]
# if equivalent to
for element in list:
if conditional:
expression
twos = [2 ** i for i in range(8)]
print(twos)
> [1, 2, 4, 8, 16, 32, 64, 128]
odds = [x for x in squares if x % 2 != 0 ]
print(odds)
> [1, 9, 25, 49, 81]
Multi-Dimensional Arrays are equivalent to a matrix in mathematics:
row = []
for x in range(8):
for y in range(8):
row.append(y)
# make a chessboard
board = [[i for i in range(8)] for j in range(8)]
print(board)
> [[0, 1, 2, 3, 4, 5, 6, 7],
[0, 1, 2, 3, 4, 5, 6, 7],
[0, 1, 2, 3, 4, 5, 6, 7],
[0, 1, 2, 3, 4, 5, 6, 7],
[0, 1, 2, 3, 4, 5, 6, 7],
[0, 1, 2, 3, 4, 5, 6, 7],
[0, 1, 2, 3, 4, 5, 6, 7],
[0, 1, 2, 3, 4, 5, 6, 7]]
Functions, tuples, dictionaries, and data processing.
A Function is a block of code that performs a specific task when the function is called (invoked). Use functions to make your code reusable, better organized, and more readable; The DRY Principle Don't Repeat Yourself.
- functions can have parameters
- function may return values or cause an effect
- functions are invoked by passing arguments between the parenthesis after the function_name()
- positional arguments
- keyword arguments
Decomposition / Decomposing Code is the process of dividing the source code (or problem) into well-isolated pieces, each encoded into a function form; Decomposition allows us to share the work and the responsibility among many developers
Define the function using the def
keyword, followed by the indented function body
def my_function(): # define a function
print("Do stuff...") # function body
- Python built-in functions
- Python modules
- custom coded functions
- (functions connected with classes)
When Invoking a function:
- Python recalls the function by its name from memory and jumps into the function body
- the body of the function is then executed
- the end of the function returns to the place
Example Call:
# define function
def message():
print("Message")
# function returns None by default
# do stuff
print("Start)
# invoke the message() function
message()
> Message
# after function executes
# returns to this next line
print("Stop)
> Start
> Message
> Stop
Parameterized Functions declare parameter variables in the function parenthesis
- function parameters live inside functions, and can be only be defined between the pair of parentheses in the
def
statement - function arguments exist outside functions, and carry the value passed to corresponding function parameters
- You must provide as many arguments as there are defined parameters, unless the function parameter has a default value declared
Example Parameterized Functions:
# define a function
def my_function(a, b, c):
# function body
print(a, b, c)
# function invocation
my_function(1, 2, 3)
# a more practical example
def hello(name):
print("Hello", name, "!")
# pass an argument the the "name" parameter
username = input("Enter your name:")
hello(username)
Positional Parameter Passing:
def introduction(first_name, last_name):
print("Hello, my name is", first_name, last_name)
introduction("Jessie", "Owens")
> Hello, my name is Jessie Owens
introduction("James", "Bond", "007")
> TypeError: introduction() takes 2 positional arguments but 3 were given
Keyword Argument Passing:
def introduction(first_name, last_name):
print("Hello, my name is", first_name, last_name)
introduction(first_name = "James", last_name = "Bond")
> Hello, my name is James Bond
introduction(last_name = "Skywalker", first_name = "Luke")
> Hello, my name is Luke Skywalker
introduction(surname="Skywalker", first_name="Luke")
> TypeError: unexpected keyword argument 'surname'
Defining Default (Predefined) Values:
def introduction(first_name, last_name="Trump"):
print("Hello, my name is", first_name, last_name)
introduction("Donald")
introduction(first_name="Donald")
> Hello, my name is Donald Trump
Note: positional arguments must not follow keyword arguments
def subtract(a, b):
print(a - b)
subtract(5, b=2)
> 3
subtract(a=5, 2)
> Syntax Error
Functions can home some kind of effect (printing text to the console), but functions also can return
a value using the return
keyword in two variants:
-
return
without an expression causes the immediate termination of execution -
return
with an expression causes the immediate termination of the function's execution AND will evaluate the expression's value and return the result
Example Function return
:
def boring_function():
return 123
x = boring_function()
print("The boring_function has returned the value:", x)
> The boring_function has returned the value: 123
There are only two kinds of circumstances when None can be safely used:
# 1. assigning it to a variable (or return it as a function's result)
value = None
value = nothing_but_func() = None
# 2. comparing it with a variable to diagnose an internal state
if value is None:
print("Sorry, you don't carry any value")
> Sorry, you don't carry any value
Functions implicitly return None
if it doesn't return a value using a return
expression
def strange_function(n):
if(n % 2 == 0):
return True
output = strange_function(1)
print(output)
> None
output = strange_function(2)
print(output)
> True
# return T/F if it is a leap year
def is_year_leap(year):
if year % 400 == 0:
return True
elif year % 100 == 0:
return False
elif year % 4 == 0:
return True
else:
return False
# return number of days in a given year, month
def days_in_month(year, month):
if month in [1,3,5,7,8,10,12]:
return 31
elif month in [9,4,6,11]:
return 30
elif month == 2:
if is_year_leap(year):
return 29
else:
return 28
# calculate the number of days in a year, month, day
def day_of_year(year, month, day):
count = 0
for i in range(1, month+1):
count += days_in_month(year, i)
return count
# Testing
print(day_of_year(2000, 12, 31))
> 366
# calculate if a value is prime
def is_prime(num):
for i in range(2, num):
if num % i == 0:
return False
return True
# loop a range & print all prime numbers
for i in range(1, 20):
if is_prime(i + 1):
print(i + 1, end=" ")
print()
> 2 3 5 7 11 13 17 19
The Scope of a name (e.g., a variable name) is the part of the code where the name is properly recognizable
Function Scope Example 1: A variable that exists outside a function has a scope inside the function body
# example 1
var = 2
def multiply_by_var(x):
return x * var
print(multiply_by_var(7))
> 14
Function Scope Example 2 & 3: unless the function defines a variable of the same name
# example 2
def multiply(x):
var = 5
return x * var
print(multiply(7))
> 35
# example 3
def multiply(x):
var = 7
return x * var
var = 3
print(multiply(7))
> 49
Function Scope Example 4: A variable that exists inside a function has a scope inside the function body
# example 4
def adding(x):
var = 7
return x + var
print(adding(4))
print(var)
> 11
> NameError
Function Scope Example 5: Use the global
keyword followed by a variable name to make the variable's scope global
# example 5
var = 2
print(var)
> 2
def return_var():
global var
var = 5
return var
print(return_var())
print(var)
> 5
> 5
def ft_and_inch_to_m(ft, inch = 0.0):
return ft * 0.3048 + inch * 0.0254
def lb_to_kg(lb):
return lb * 0.45359237
def bmi(weight, height):
if height < 1.0 or height > 2.5 or weight < 20 or weight > 200:
return None
return weight / height ** 2
print(bmi(52.5, 1.65))
> 19.283746556473833
print(bmi(weight=lb_to_kg(176),
height=ft_and_inch_to_m(5, 7)
))
> 27.565214082533313
# The sum of any two sides of a triangle
# must be greater than the third side.
# long-form (inefficient)
def is_a_triangle(a, b, c):
if a + b <= c:
return False
if b + c <= a:
return False
if c + a <= b:
return False
return True
# shortened (better...)
def is_a_triangle(a, b, c):
if a + b <= c or b + c <= a or c + a <= b:
return False
return True
# condensed (now that's Pythonic!)
def is_a_triangle(a, b, c):
return a + b > c and b + c > a and c + a > b
# testing
print(is_a_triangle(1, 1, 1))
> True
print(is_a_triangle(1, 1, 3))
> False
# checking for right triangles
def is_a_right_triangle(a, b, c):
if not is_a_triangle(a, b, c):
return False
if c > a and c > b:
return c ** 2 == a ** 2 + b ** 2
if a > b and a > c:
return a ** 2 == b ** 2 + c ** 2
# testing
print(is_a_right_triangle(5, 3, 4))
> True
print(is_a_right_triangle(1, 3, 4))
> False
def factorial_function(n):
if n < 0:
return None
if n < 2:
return 1
product = 1
for i in range(2, n + 1):
product *= i
return product
# testing
for n in range(1, 6):
print(n, factorial_function(n))
> 1 1
> 2 2
> 3 6
> 4 24
> 5 120
def factorial(n):
if n == 1:
# base case (termination condition)
return 1
else:
# recursive function invocation
return n * factorial(n - 1)
def fib(n):
if n < 1:
return None
if n < 3:
return 1
elem_1 = elem_2 = 1
the_sum = 0
# pay attention to the var movements in loop
for i in range(3, n + 1):
the_sum = elem_1 + elem_2
elem_1, elem_2 = elem_2, the_sum
return the_sum
# testing
for n in range(1, 10):
print(n, "->", fib(n))
> 1 -> 1
> 2 -> 1
> 3 -> 2
> 4 -> 3
> 5 -> 5
> 6 -> 8
> 7 -> 13
> 8 -> 21
> 9 -> 34
Tuples are ordered and unchangeable (immutable) collections of data
Sequence Types may store one or more values (or be empty) and are browsed/scanned element by element (sequentially) using a for
loop
Mutability is a property of data that describes its ability to change during program execution.
Python has two kinds of data: mutable and immutable data.
Mutable data can be freely updated at any time or In Situ (in Latin translates literally in position)
# ALLOWED, lists are mutable data types
list.append(1) # container of items
Immutable data cannot be modified during program execution
# NOT ALLOWED, tuples are immutable sequence types
tuple.append(1) # AttributeError: 'tuple' object has no attribute 'append'
# sequence of items cannot be changed at execution
Tuples are Immutable Sequence Types where each element may be a different type, including literals and variables
tuple_1 = (1, 2, 4, 8)
tuple_2 = 1., .5, .25, .125
empty_tuple = ()
one_element_tuple_a = (1, )
one_element_tuple_b = 1.,
list = [1, 2, 3]
a_tuple = tuple(list)
print(a_tuple)
> (1, 2, 3)
Index a tuple to access its values
my_tuple = (1, 2.0, "string", [3, 4], (5, ), True)
print(my_tuple[3]) # outputs: [3, 4]
# tuple items cannot be deleted or changed
my_tuple = (1, 2.0, "string", [3, 4], (5, ), True)
my_tuple[2] = "guitar" # TypeError exception
# but tuples can be deleted entirely
del my_tuple
Use the tuple.count()
method to count the number of times a specified element occurs in a tuple
tup = 1, 2, 3, 2, 4, 5, 6, 2, 7, 2, 8, 9
duplicates = tup.count(2)
print(duplicates)
> 4
A Dictionary is a mutable data structure defined by a set of key-value pairs using a pair of curly braces {}
Dictionaries are not a sequence and each key must be unique.
Dictionaries are not Lists: Dicts hold pairs of values compared to Lists which contain a set of numbered values
# dict instantiation
empty_dictionary = {}
empty_dictionary = dict()
dictionary = {
"horse": "caballo",
"cat": "gato",
"dog": "perro"
}
phone_numbers = dict('boss': 0987654321,
'Suzy': 1234567890)
# example
words = ['cat', 'lion', 'horse']
for word in words:
if word in dictionary:
print(word, "->", dictionary[word])
else:
print(word, "is not in dictionary")
# output
> cat -> gato
> lion is not in dictionary
> horse -> caballo
The sorted()
function sorts dictionaries
dictionary = {"cat": "gato", "dog": "perro", "horse": "caballo"}
for key in sorted(dictionary.keys()):
print(key, "->", dictionary[key])
> cat -> gato
> dog -> perro
> horse -> caballo
The dict.get()
method will return the value of the given dictionary key-name
dictionary = {"cat": "gato", "dog": "perro", "horse": "caballo"}
print(dictionary.get("horse"))
> caballo
Use dict.keys()
to access values by referencing a certain key by its name:
dictionary = {"cat": "gato", "dog": "perro", "horse": "caballo"}
for key in dictionary.keys():
print(key, "->", dictionary[key])
> horse -> caballo
> cat -> gato
> dog -> perro
The dict.values()
method works similarly to .keys(), but returns values
dictionary = {"cat": "gato", "dog": "perro", "horse": "caballo"}
for spanish in dictionary.values():
print(spanish)
> gato
> perro
> caballo
The dict.items()
method returns each key-value pair as a tuple
dictionary = {"cat": "gato", "dog": "perro", "horse": "caballo"}
for english, spanish in dictionary.items():
print(english, "->", spanish)
> cat -> gato
> dog -> perro
> horse -> caballo
Adding/Inserting a dictionary item by declaring its dict[key] = value
span_eng = {"cat": "gato", "dog": "perro", "horse": "caballo"}
# update a dict key-value
span_eng['cat'] = 'león'
# adding non-existent key
span_eng['swan'] = 'cisne'
Use the dict.update()
method to insert/update items in a dictionary:
span_eng = {"flor": "flower"}
span_eng.update({"suelo": "soil"})
print(span_eng)
> {"flor": "flower", "suelo": "soil"}
The dict.popitem()
method will remove and return the last item in a dictionary:
span_eng = {"flor": "flower", "suelo": "soil"}
last_item = span_eng.popitem()
print(last_item)
> {"suelo": "soil"}
print(span_eng)
> {"flor": "flower"}
Use the del
keyword to delete a specific dictionary item or the dict.clear()
method to remove all dictionary items
dictionary = {"cat": "gato", "dog": "perro", "horse": "caballo"}
del dictionary["cat"]
print(dictionary)
> {"dog": "perro", "horse": "caballo"}
dictionary.clear()
print(dictionary)
> {}
The dict()
function will convert a list or tuple to dictionary:
# a tuple of tuples
colors = (("green", "#008000"), ("blue", "#0000FF"))
# a list of tuples
colors = [("green", "#008000"), ("blue", "#0000FF")]
# convert to `dict()`
colors_dictionary = dict(colors)
print(colors_dictionary)
> {'green': '#008000', 'blue': '#0000FF'}
Errors arise when:
- when code is fed bad data
- you write bad code with mistakes causing "bug"
It is better to beg for forgiveness than to ask for permission... In Python it is better to handle an error when it happens than to try to avoid it
try:
# run this block first, forgive later
value = int(input('Enter a natural number: '))
print('The reciprocal of', value, 'is', 1/value)
except ValueError:
# catch value error
print('I do not know what to do.')
except ZeroDivisionError:
# catch operational error
print('Division by zero is not allowed.')
except:
# catch default error
print('Something strange has happen... Sorry!')
Or you can consolidate exception handling using a tuple
try:
value = int(input('Enter a natural number: '))
print('The reciprocal of', value, 'is', 1/value)
except (ValueError, ZeroDivisionError):
# catch value or operational error
print('I cannot use that value.')
except:
# catch default error
print('Something strange has happen... Sorry!')
ZeroDivisionError occurs because you cannot divide any value by 0
n / 0 -> ZeroDivisionError
n // 0 -> ZeroDivisionError
n % 0 -> ZeroDivisionError
ValueError arises when dealing with values that are not allowed in come context
# each of these have their own ways of handling values
string()
int()
float()
list()
dict()
tuple()
TypeError arises when applying a data whose type cannot be accepted in the current context
short_list = [1]
one_value = short_list[0.5]
> TypeError: cannot use float as list index
AttributeError arises when activating a method which does not exist on the item you are dealing with
short_list = [1]
short_list.append(2)
short_list.depend(3)
AttributeError: 'list' has no attribute 'depend'
short_tup = (1,)
short_tup.append(2)
AttributeError: 'tuple' has no attribute 'append'
SyntaxError arises when the interpreter reaches a line of code which violates the Python language grammar/syntax
x = 92
if x > 90
print("You got an 'A'!")
> error, line #
> if x > 90:
> ^
> SyntaxError: expected ':'
Every novelist needs an editor and each programmer needs a tester.
Since Python is an interpreted language, the source code is parsed and executed at the same time. Consequentially, the program may not reach a block of code with an error.
Print Debugging sometimes called Interactive Debugging because it requires a developer to interact with the program to find the bug. Other forms of debugging involve pragmatically running your functions through systematic tests that automate the testing process to a degree.
-
Try to tell someone
- explain what your code is expected to do and how it actually behaves
- be concrete and answer any questions the listener has
- you'll likely realize the cause of the problem telling your story
-
Try to isolate the problem
- extract the part of the code that seems to be throwing an error
- comment out parts of the code that obscure the problem
- assign concrete values instead of reading from an
input()
- test functions using predictable argument values
- analyze the code, read it aloud
-
Analyze all the changes you introduce into your code, in particular if a bug appears that didn't show up earlier
-
Take a break, taking walks and drinking coffee help the blood flow
-
Be optimistic, solving problems equals brain power over time, patience and persistence are great skills to build
Unit Testing is about testing the software and how the code itself is written
Writing/running tests are inseparable parts of the code and preparing the test data is an inseparable part of coding.
We will go into Unit Testing more deeply in the Associate and Professional Certification Modules!
print("", sep="", end="\n")
max(10, 50, 33) # 50
min(2, -5, 10) # -5
range(start=0, stop=100, step=1)
# [0,1,2,...98,99]
numbers = [0, 1, 2]
len(numbers) # 3
numbers[] = 3
len(numbers) # 4
Priority | Operator | Description |
---|---|---|
0 | () |
Parentheses |
1 | f(args…) |
Function call |
2 | (expressions…), [expressions…], {expressions…} {key: value…} |
Displaying Sequences Dictionaries |
3 | x[index], x[index:index], x(arguments), x.attribute |
Indexing, slicing, calling, attribute referencing |
4 | await x |
Await expression |
5 | ** |
Exponent |
6 | +x, –x, ~x |
(unary) Positive, Negative, Bitwise NOT |
7 | *, /, //, % |
Multiplication, Division, Remainder |
8 | +, – |
(binary)Addition, subtraction |
9 | <<, >> |
Bitwise left and right shifts |
10 | & |
Bitwise AND |
11 | ^ |
Bitwise XOR |
12 | | |
Bitwise OR |
13 | in, not in, is, is not, <, >,<=, >=, !=, ==, <> |
Comparisons, identity, and membership operators |
14 | not |
Boolean NOT |
15 | and |
Boolean AND |
16 | or |
Boolean OR |
17 | if-else |
Conditional Expression |
18 | lambda |
Lambda expression |