Python Notes

  1. Variables & Memory Management
  2. Datatypes
  3. Sequences
  4. Sets & Dictionary
  5. Literals & Identifiers
  6. Reserved Words
  7. Arithmetic & Assignment Operators
  8. Unary Minus, Relational, Logical & Boolean Operators
  9. Escape Characters
  10. Output Statements
  11. Input Statements
  12. Built-in Functions & Modules
  13. Conditionals
  14. Loops
  15. Comments & Doc Strings
  16. Strings
  17. Lists
  18. Tuples
  19. Dictionaries
  20. Indexing & Slicing
  21. Functions
  22. Local & Global Variables
  23. Introduction to OOP
  24. Classes & Objects
  25. init Method & self Param
  26. Solving Task : OOPS
  1. Multiple C'tors
  2. Encapsulation
  3. Public & Private Methods
  4. Inheritance
  5. Getters & Setters
  6. Creating and Importing Modules
  7. Creating a User-defined Module
  8. Multiple Inheritance
  9. The super Function
  10. Naming Convention
  11. Composition & Aggregation
  12. Abstract Types
  13. Operator Overloading
  14. Types of Errors
  15. Exceptions
  16. Exception Handling
  17. Try, Except, Else & Finally
  18. Raising Exceptions
  19. User-defined Exceptions
  20. Special Keyword
  21. Create & Write Text Files
  22. Appending to a Text File
  23. Reading a Text File
  24. IDEs
  25. Python Package Management System

Variables & Memory Management

no capital letters or spaces permitted in variable names
to get the memory location of a variable
   id(<variable name>)
multiple variables can point to the same memory location
    x = 5
    y = 5
    ml1 = id(x)
    ml2 = id(y)
ml1 and ml2 both point to the same memory location
if the value of x is changed to 6 it receives a new memory location

in essence a memory location contains an immutable value
a variable points to a shared memory location based on the value
when the variable's value changes the memory location it points to changes

Index

Datatypes

built-in data types : to find the type of a variable
    x = 50 + 5j
    type(x)
    <class 'complex'>
Index

Sequences

4 types of sequences Index

Sets & Dictionary

set is an unordered collection of elements
no indexing
    # note curly brackets
    s = {10,5,7}
    # create set from list
    my_list = ["flip", 23, 6.3]
    s = set(my_list)
    print(s)
    {'flip', 6.3, 23}
    
create a dictionary aka key:value pair
    # note curly brackets
    d = {1:"wn1vkn",2:"wa1vkn",3:"n4jvp"}
    # to print use a key
    print(d[1])
Index

Literals & Identifiers

    # a (variable name) is the identifier
    # 15 (value) is the literal
    a = 15
three types of literals
Index

Reserved Words

and as assert break class
class continue def del elif
else except False finally for
from global if import in
is lambda nonlocal None not
or pass raise return True
while with yield    

Index

Arithmetic & Assignment Operators

six types of operators Arithmetic Operators
OperatorOperation
+Addition
-Subtraction
*Multiplication
/Division
%Modulus
//Quotient
**Exponent

Assignment Operators
OperatorOperation
+=Addition
-=Subtraction
*=Multiplication
/=Division
%=Modulus
//=Quotient
**=Exponent

Index

Unary Minus, Relational, Logical, & Boolean Operators

Unary Minus
    n = 10
    print(-n)
    -10
Relational Operators
OperatorOperation
>greater than
<less than
==the same as
!=not the same as
>=not the same as or greater than
<=not the same as or less than

Logical Operators
OperatorOperation
andTrue if both operands are true
orTrue if either operand is true
not True if operand is false
complements the operand
    x = False
    y = not x
    print(y)
    True

Boolean Operators
    a = True
    b = False
    a and b
    False
    a or b 
    True
    not a
    False
Index

Escape Characters

backslash ahead of character to be escaped

Index

Output Statements

    # format method
    x = 5
    y = 50
    print("Multiplication of {0} and {1} is {2}.".format(x, y, x*y)
    Multiplication of 5 and 50 is 250.

    # string format
    my_name = "Flip"
    print("Hello %s" % my_name)
    Hello Flip

    # format float
    num = 123.444666
    print("The value is %f" % num")
    The value is 123.444666

    # format 2 decimal places
    num = 123.444666
    print("The value is %.2f" % num")
    The value is 123.44

    # format using a tuple
    int-num = 150
    print("The values are %.2f and %d" % (num, int_num)
    The values are 123.44 and 150
Index

Input Statements

    my_name = input()
    # result from input
    Flip
    print(my_name)
    Flip

    # input with a prompt
    my_name = input("Please enter your name : ")
    Please enter your name : Flip
    print(my_name)
    Flip
input method returns a string
    age = input("Enter your age :")
    Enter your age : 68
    type(age)
    <class 'str'>
    # use int method
    int_age = int(age)
    type(int_age)
    <class 'int'>
Index

Built-in Functions & Modules

Python.org has a list of built-in functions along with notes on each
from a prompt
    dir(__builtins__)
will return a list of function names
an example of using math module
    import math
    math.sqrt(5)
    2.23606797749979
from a prompt
    dir(math)
will return a list of function names in the math module

Index

Conditionals

with a conditional it must be followed by a colon
lines to be executed are indented following the conditional
colon must be character immediatedly after conditional
    if age >= 18:
    # this will not work
    if age >= 18 :
        ...
elif is Python shorthand for else if
multiple conditions use and and or
    if i >= 0 and i <= 100:
        ...
    elif i <= 0:
        ...
    else:
        ...
Index

Loops

while loop can be followed with else condition
    sum = 0
    num = 1
    while num != 0:
        num = int(input("Enter a number : "))
        sum += num
        print("Sum :", sum)
    else:
        print("The final total is", sum)
for loops can be used with lists, tuples, sets, strings and dictionaries
to check if a value is found in a collection
    a = [0,1,2,3,4,5]
    print(2 in a)

    b = ["A","B","C","D"]
    print(C in b)
for loop
    a = [0,1,2,3,4,5]
    for i in a:
        print(i)
running a dictionary through a for loop iterates the keys
    a = {
            "name":"Flip", 
            "age":68
        }
    for i in a:
        print(i)
to iterate keys and values
    a = {
            "name":"Flip",
            "age":68
        }
    for x, y in a.items():
        print(x + " ", y)
range statement
    range(<start inclusive>, <end exclusive>, <step>)
break statements
    a = [0,1,2,3,4,5]
    for i in a:
        if i = 2:
            break;
        print(i)
continue statements
    a = [0,1,2,3,4,5]
    for i in a:
        if i = 2:
            continue;
        print(i)
Index

Comments & Doc Strings

octothorpe/pound sign/hashtag starts a comment
    # this is a comment
to comment a block of lines
    """
    x += 1
    y += 1
    """
can also use ctrl-slash to comment a line or block of lines
    # x += 1
    # y += 1
    
Index

Strings

strings have methods
    x = "hello world"
    y = x.capitalize()
    print(y)
y is Hello world
strings are zero-based arrays of char
    print(y[0])
    # H
slicing for substrings
    <string variable>[<start index>:<length>]        
    print(y[0:5])
    # Hello
trimming strings with strip method
    x = "          Hello world               "
    # strip methods
    print(x.strip())
    print(x.rstrip())
    print(x.lstrip())
some other methods
Index

Lists

ordered element container aka sequence
zero-index
lists are mutable
    x = ["Flip", 23, "C#", "Python", 68]
    y = x[2]
    print(y)
    # C#
length of list
    list_length = len(x)
    # 5
some list methods to delete a list
    del x
Index

Tuples

tuples are immutable
usually faster than lists
can add tuples
    a = (10,20)
    b = (5,15)
    c = a + b
    print(c)
    # result is (10, 20, 5, 15)
to distinguish single element tuple
    x = ("hello", )
    y = x * 5
    print(y)
    # ('Hello','Hello','Hello','Hello','Hello') 
some tuple methods
Index

Dictionaries

mutable using key-value pairs
selements below are a string, an int, and a tuple
    emp = {"name":"flip", "age":68, ("h","w"):(67,200)}
indexed by key name
    x = emp["name"]
    print(x)
    # flip
to add entry to dictionary
    emp["sal"] = 1000000
some dictionary methods
Index

Indexing & Slicing

negative indexing starts with -1
indexing is zero-based
    x = [100, 101, 102, 103, 104, 105, 106, 107, 108, 109]
    y = (00, 10, 20, 30, 40, 50, 60, 70, 80, 90)
    z = "Flip"

    a = x[-2]
    print(a)
    # 108
slice operation
    <sequence variable>[<start index>:<count>:<step>]
step defaults to 1
    b = x[0:3:1]
    # [100, 101, 102]
index from a position to the end
    x[4:]
    # [104, 105, 106, 107, 108, 109]
index from a position to the start
    c = x[:4]
    # [100, 101, 102, 103]
step 2
    print(x[::2])
    # [100, 102, 104, 106, 108]
reverse order
    print(x[::-1])
    # [109, 108, 107, 106, 105, 104, 103, 102, 101, 100]
Index

Functions

built-in functions and user-defined functions
can name udf anything except a keyword
names are lowercase with underscores separating words
    def sumf(arg1, arg2):
        print(arg1 + arg2)
    
    sumf(23,22)
x and y are global variables
z is a local variable
    x = 23
    y = 22

    def sumf(arg1, arg2):
        z = arg1 + arg2
        print(z)
    
    sumf(x,y)
to make z a global variable
    def sumf(arg1, arg2):
        global total
        total = arg1 + arg2
        print(total)
a global declaration must be on its own line
function returning a value
     def sumf(arg1, arg2):
        total = arg1 +arg2
        return total
    
    result = sumf(x,y)
    print(result)
Index

Local & Global Variables

4 types of arguments
    def shop(item, price):
        print("Item : ", item)
        print("Price : ", price

    # positional args
    shop("sugar", 50)
    # keyword args
    shop(price=50, item="sugar")

    # default arg
    def shopx(item, price = 50):
        print("Item : ", item)
        print("Price : ", price

    # variable length - note asterisk
    def student(name, course, *grades):
        print("Name : ", name)
        print("Course : ", course)
        # print("Grades : ", grades)
        for x in grades:
            print("Grade : ", x)

    student("Flip", 12, 95, 96, 99)

    # multiple keywords - note asterisks
    def student(name, course, **grades):
        print("Name : ", name)
        print("Course : ", course)
        print("Grades : ", grades)

    student(name = "Flip", course = 12, math = 95, english = 96, science = 99)

    # dictionary displays multiples
    # Grades: {'math': 90, 'english': 96, 'science': 99}
    
Index

Introduction to OOP

procedural oriented programming languages include C, Pascal, Fortran
POP disadvantages OOP
Index

Classes & Objects

a class can have actions and attributes
    class Student:
        def __init__(self):
            # attributes
            self.name = "Flip"
            self.age = 68
            self.marks = 100
        
        #action    
        def talk(self):
            print("Name - ", self.name)               
            print("Age - ", self.age)               
            print("Marks - ", self.marks)    
            
    # c'tor        
    s1 = Student()      
    s1.talk()  
Index

init Method & self Param

__init__(self) is the c'tor
self refers to class instance
    class Student:
        def __init__(self):
            # attributes
            self.name = "Flip"
            self.age = 68
            self.marks = 100
Index

Solving Task : OOPS

pass arguments using c'tor'
    class Student:
    def __init__(self, name, age, marks):
        self.name = name
        self.age = age
        self.marks = marks
        
    def display(self):
        print(self.name)
        print(self.age)
        print(self.marks)
Index

Multiple C'tors

no multiple c'tors
if a class has multiple c'tors only the last one will be called
self is the this pointer

Index

Encapsulation

starting an attribute's name with double underscore makes the attibute private
    class Speed:
        def __init__(self):
            self.__speed = 60
       
        def get_speed(self):
            return self.__speed
    
        def set_speed(self, new_speed):
            self.__speed = new_speed
           
    s =  Speed()  

    print("changing speed by assignment")
    s.__speed = 100
    print(s.__speed)
    # prints 100
    print(s.get_speed())
    # prints 60

    print("changing speed by setter")
    s.set_speed(100)
    print(s.__speed)
    # prints 100
    print(s.get_speed())
    # prints 100
when __speed is 'changed' by assignment, the private attribute is not changed
instead a new public attribute named __speed is assigned to the Speed instance
this gives the instance 2 __speed attributes, one public and one private
use of a getter and a setter encapsulates the private attribute

Index

Public & Private Methods

underscore usage
   class Example:
        def __init__(self):
            # public
            self.x = 10
            # _single weak 'internal use' indicator
            self._y = 50
            # private
            self.__z = 100
        
        def public_method(self):
            print(self.x)
            print(self._y)
            print(self.__z)
        
        # private
        def __private_method(self):
            print("private_method")
        
    s = Example()
    s.public_method()
    # error - cannot access private method
    # s.__private_method()
Index

Inheritance / Getters & Setters

a later section covers abstract classes
    class Polygon:
        # None is null
        __width = None
        __height= None
    
        def set_value(self, width, height):
            self.__width = width
            self.__height = height
    
        def get_width(self):
            return self.__width
        def get_height(self):
            return self.__height
    
    class Square(Polygon):
        def area(self):
            return self.get_height() * self.get_width() 
    
    class Triangle(Polygon):
        def area(self):
            return self.get_height() * self.get_width() * 1/2 
    
    s = Square();
    # calling area() before set_value() will cause error : null * null
    # print(s.area())    
    s.set_value(22,23)
    print(s.area())

    t =Triangle()
    t.set_value(22,23)
    print(t.area())
Index

Creating and Importing Modules

built-in modules simple module
   # filename is mymath.py
    def add(x, y):
        return x + y

    def multiply(x, y):
        return x * y
the main file
    # filename is main.py
    import mymath

    result = mymath.add(22, 23)
    print(result)
this assumes the module and main files are in the same directory
if module in subdirectory named foo
   from foo import mymath
or can qualify the module's name
    import foo.mymath

    result = foo.mymath.add(22, 23)
    print(result)
or the imported module can be aliased
    import foo.mymath as bar

    result = bar.mymath.add(22, 23)
    print(result)
or
   from foo import mymath as bar
Index

Creating a User-defined Module

the polygon example from a previous section is split into three modules below is the Square class which is derived from the Polygon class
    import polygon

    class Square(polygon.Polygon):
        def area(self):
            return self.get_height() * self.get_width() 
and the main module is
    from square import Square
    import triangle

    s = Square()
    s.set_value(10, 10)
    a = s.area()
    print(a)

    t = triangle.Triangle()
    t.set_value(10, 10)
    b = t.area()
    print(b)
Index

Multiple Inheritance

add a Shape class
    class Shape:
        __color = None
    
        def set_color(self, color):
            self.__color = color
        
        def get_color(self):
            return self.__color
have the Polygon-derived class also inherit from Shape
    import polygon
    import shape

    class Square(polygon.Polygon, shape.Shape):

        def area(self):
            return self.get_height() * self.get_width() 
the main module
    from square import Square
    import triangle

    s = Square()
    s.set_value(10, 10)
    s.set_color("Blue")
    a = s.area()
    c = s.get_color()
    print(a, c)

    t = triangle.Triangle()
    t.set_value(10, 10)
    t.set_color("Red")
    b = t.area()
    d = t.get_color()
    print(b, d)
Index

The super Function

two ways to call super-class c'tor
    class Parent:
        def __init__(self, name):
            print("Parent init - ", name)
        
    class Child(Parent):
        def __init__(self):
            print("Child init")
            Parent.__init__(self, "Flip")
        
    chld = Child()  
using super
    class Child(Parent):
        def __init__(self):
            print("Child init")
            super().__init__("Flip")
Index

Naming Convention

for modules for classes for global variables for instance variables for functions for method arguments for constants Index

Composition & Aggregation

composition - tight relationship between Employee and Salary types
aggregation - loose relationship between Employee and Salary types
composition example
    class Salary:
        def __init__(self, pay, reward):
            self.pay = pay
            self.reward = reward
    
        def annual_salary(self):
            return (self.pay * 12) + self.reward

    class Employee:
        def __init__(self, name, position, pay, reward):
            self.name = name
            self.position = position
            self.salary = Salary(pay, reward)
        
    emp = Employee("Flip", "CSO", 10000, 10000)     
    print(emp.salary.annual_salary())
aggregation example
    class Salary:
        def __init__(self, pay, reward):
            self.pay = pay
            self.reward = reward
    
        def annual_salary(self):
            return (self.pay * 12) + self.reward

    class Employee:
        def __init__(self, name, position, salary):
            self.name = name
            self.position = position
            self.salary = salary
        
    sal = Salary(10000, 10000)        
    emp = Employee("Flip", "CSO", sal)     
    print(emp.salary.annual_salary())
Index

Abstract Types

ABC is Abstract Base Class
pass means an empty method
abstractmethod decorator identies abstract methods
    from abc import ABC, abstractmethod
    # shape class is abstract
    class Shape(ABC):
        @abstractmethod
        def area(self):
            pass
        @abstractmethod
        def perimeter(self):
            pass
    
    class Square(Shape):
        def __init__(self, side):
            self.__side = side
        def area(self):
            return self.__side * self.__side
        def perimeter(self):
            return self.__side * 4  
   
    sq = Square(10)     
    print(sq.area())   
    print(sq.perimeter())
Index

Operator Overloading

the snippet below generates a TypeError because of the unsupported operand
    class Books:
        def __init__(self, pages):
            self.pages = pages

    b1 = Books(100)
    b2 = Books(150)
    # '+' is the unsupported operand
    print(b1+b2)   
plus symbol is internally connected to a special method __add__
override the __add__ method to overload the operator
    class Books:
        def __init__(self, pages):
            self.pages = pages

        # override the add method
        def __add__(self, book):
            return self.pages + book.pages

    b1 = Books(100)
    b2 = Books(150)
    # b1.__add__(b2)
    print(b1+b2)   
operator overloading special functions
OperatorExpressionInternally
Additionp1 + p2p1.__add__(p2)
Subtractionp1 - p2p1.__sub__(p2)
Multiplicationp1 * p2p1.__sub__(p2)
Powerp1 ** p2p1.__pow__(p2)
Divisionp1 / p2p1.__truediv__(p2)
Floor Divisionp1 // p2p1.__floordiv__(p2)
Remainder (modulo)p1 % p2p1.__mod__(p2)
Bitwise Left Shiftp1 << p2p1.__lshift__(p2)
Bitwise Right Shiftp1 >> p2p1.__rshift__(p2)
Bitwise ANDp1 & p2p1.__and__(p2)
Bitwise ORp1 | p2p1.__or__(p2)
Bitwise XORp1 ^ p2p1.__xor__(p2)
Bitwise NOT~p1p1.__invert__()

Index

Types of Errors

3 types of errors Index

Exceptions

Exceptions are a type of run-time errors
only exceptions can be handled
other run-time errors can not be handled

class hierarchy
Base Exception
Exception
StandardErrorWarning

derived from StandardError derived from Warning
Index

Exception Handling

simple exception handler
    result = None
    x = int(input("numerator : "))
    y = int(input("denominator : "))

    try:    
        result = x/y
    except Exception as e:
        print("An error has occured : ", e)
        print(type(e))
    
    print(result)
Index

Try, Except, Else & Finally

the else block is entered if the except block hasn't been entered
    result = None
    x = int(input("numerator : "))
    y = int(input("denominator : "))

    try:    
        result = x/y
    except Exception as e:
        print("An error has occured : ", e)
        print(type(e))
    else:
        print("inside the else block")
    finally:
        print("inside the finally block")   
    print(result)
Index

Raising Exceptions

simple example
    class Tea: 
        def __init__(self, temperature):
            self.__temperature = temperature
        
        def drink_tea(self):
            if self.__temperature > 85:
                # print("too hot")
                raise Exception("too hot")
            elif self.__temperature < 65:
                print("too cold")
            else:
                print("just right")
            
    t = Tea(100)     
    t.drink_tea()
Index

User-defined Exceptions

simple example
    class TeaException(Exception):
        def __init__(self, msg):
            self.msg = msg

    class Tea: 
        def __init__(self, temperature):
            self.__temperature = temperature
        
        def drink_tea(self):
            if self.__temperature > 85:
                raise TeaException("too hot")
            elif self.__temperature < 65:
                 raise TeaException("too cold")
            else:
                print("just right")
            
    t = Tea(100)     
    t.drink_tea()
Index

Special Keyword

mymath.py from earlier
    def add(x, y):
        return x + y

    def multiply(x, y):
        return x * y

    print(add(10,20))
when used as an import by this module
    import mymath

    print(mymath.add(50,50))
the terminal will print
    30
    100
obviously the call inside mymath.py is not desired
to prevent this behavior use the __name__ keyword
    def add(x, y):
    return x + y

    def multiply(x, y):
        return x * y

    # if mymath.py is running as the main module 
    if __name__ == "__main__":
        print(add(10,20))
Index

Create & Write Text Files

two types of Python files to open file
    open(<filename>,<access mode>)
file access modes
characterfunction
r read only
start reading from beginning of file
default mode
r+ open file for reading and writing
pointer placed at beginning of file
w open file for writing only
pointer placed at beginning of file
overwrites existing file or creates a new file
w+same as w but allows reading
a open file for appending
starts writing at end of file
creates a new file if one does not exist

create and write to a new file
    fh = open("example.txt", "w")
    fh.write("Hello file system!")
    fh.close()
Index

Appending to a Text File

create, write and close the file
    fh = open("example.txt", "w")
    try:
        for i in range(1, 11):
            fh.write("%d \n" %i)
    finally:
        fh.close()
append to file
    fh = open("example.txt", "a")
    try:
        for i in range(1, 11):
            fh.write("%d \n" %i)
    finally:
        fh.close()
can be written using with statement
    with open("example.txt", "a") as fh:
        for i in range(1, 11):
            fh.write("%d \n" %i)
Index

Reading a Text File

read entire file
    with open("demo.txt", "r") as fh:
        print(fh.read())
read by character
    with open("demo.txt", "r") as fh:
        # read first two characters of file
        print(fh.read(2))   
        # pointer is now at 3
        # reads characters 3 through 12
        print(fh.read(10))
read a line and move the pointer to the next line
    print(fh.readline())
to get a list of lines
    print(fh.readlines())
to read a file line by line
    for line in fh:
        print(line)
Index

IDEs

benefits Working with Index

Python Package Management System

pip is a package management system used to install and manage software package written in Python
installed with Python
from terminal prompt to check pip installation
    pip --version
for help
    pip --help
usage
    pip <command> [<options>]
Python Package Index is a repository of Python software
module needs to import cv2 module
    import cv2

    ...
to import using pip from the terminal
    pip install opencv-python
to check package was installed
    pip show opencv-python
to uninstall
    pip uninstall opencv-python
to list installed packages
    pip list
Index