GMashtalyar

Classes

.

class Person:

    amount = 0  # class variables for all objects

    def __init__(self, name, age, height):
        self.name = name
        self.age = age
        self.height = height
        Person.amount += 1  # class variables for all objects

    def __del__(self):
        Person.amount -= 1  # class variables for all objects

    def __str__(self):
        return f"Name: {self.name}, Age: {self.age}, Height: {self.height}"


person = Person("Mike", 30, 175)

print(person)
print(Person.amount)

Inheritance

.

class Person:
    amount = 0  # class variables for all objects
    def __init__(self, name, age, height):
        self.name = name
        self.age = age
        self.height = height
        Person.amount += 1  # class variables for all objects
    def __del__(self):
        Person.amount -= 1  # class variables for all objects
    def __str__(self):
        return f"Name: {self.name}, Age: {self.age}, Height: {self.height}"
person = Person("Mike", 30, 175)


class Worker(Person):

    def __init__(self, name, age, height, salary):
        super(Worker, self).__init__(name, age, height)
        self.salary = salary

    def __str__(self):
        text = super(Worker, self).__str__()
        text += ", Salary {}".format(self.salary)
        return text

    def cal_yearly_salary(self):
        return self.salary * 12


worker1 = Worker("Henry", 40, 176, 3000)
print(worker1)
print(worker1.cal_yearly_salary())


class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)

    def __sub__(self, other):
        return Vector(self.x - other.x, self.y - other.y)

    def __str__(self):
        return "X: {}, Y: {}".format(self.x, self.y)


v1 = Vector(2, 5)
v2 = Vector(6, 3)
print(v1)
print(v2)
v3 = v1 - v2

print(v3)

Multithreading

.

import threading


def function1():
    for x in range(10000):
        print("one")


def function2():
    for x in range(10000):
        print("two")


def hello():
    for x in range(50):
        print("hello!")

# t1 = threading.Thread(target=function1)
# t2 = threading.Thread(target=function2)
t3 = threading.Thread(target=hello)
# t1.start()
# t2.start()

t3.start()  # this way main thread continues
t3.join()  # this way main thread pauses
print("another hello")

Sync threads

.

import threading
import time


x = 8192
lock = threading.Lock()  #


def double():
    global x, lock
    lock.acquire()  #
    while x < 16384:
        x *= 2
        print(x)
        time.sleep(1)
    print("Reached the maximum!")
    lock.release()  #


def halve():
    global x, lock
    lock.acquire()  #
    while x > 1:
        x /= 2
        print(x)
        time.sleep(1)
    print("Reached the minimum!")
    lock.release()  #


# t1 = threading.Thread(target=halve)
# t2 = threading.Thread(target=double)

# t1.start()
# t2.start()


semaphore = threading.BoundedSemaphore(value=5)


def access(thread_number):
    print("{} is trying to access!".format(thread_number))
    semaphore.acquire()
    print("{} was granted access!".format(thread_number))
    time.sleep(10)
    print("{} is now releasing!".format(thread_number))
    semaphore.release()


for thread_number in range(1, 11):
    t = threading.Thread(target=access, args=(thread_number,))
    t.start()
    time.sleep(1)

Event Demon Threads

.

import threading
import time

# EVENTS
# event = threading.Event()
# def myfunction():
#     print("Waiting for event to trigger...\n")
#     event.wait()
#     print("Performing action XYZ now...")
# t1 = threading.Thread(target=myfunction)
# t1.start()
# x = input("Do you want to trigger the event? (y/n)\n")
# if x == "y":
#     event.set()

# DAEMON Threads

path = "text.txt"
text= ""


def readFile():
    global path, text
    while True:
        with open("text.txt", "r") as f:
            text = f.read()
        time.sleep(3)


def printloop():
    for x in range (10):
        print(text)
        time.sleep(1)


t1 = threading.Thread(target=readFile, daemon=True)
t2 = threading.Thread(target=printloop)
t1.start()
t2.start()

Queues

.

import queue

q = queue.Queue()

numbers = [10, 20, 30, 40, 50, 60, 70]

for number in numbers:
    q.put(number)

print(q.get())
print(q.get())

q2 = queue.LifoQueue()
for x in numbers:
    q2.put(x)

print(q2.get())


q3 = queue.PriorityQueue()

q3.put((2, "Hello World"))
q3.put((11, 99))
q3.put((5, 7.5))
q3.put((1, True))

while not q.empty():
    print(q3.get()[1])

Sockets

.

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('127.0.0.1', 55553))
s.listen()

while True:
    client, address = s.accept()
    print("Connected to {}".format(address))
    client.send("You're connected".encode())
    client.close()

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 55553))
message = s.recv(1024)
s.close()

print(message.decode())

Databases

.

import sqlite3


class Person:

    def __init__(self, id_number=-1, first="", last="", age=1):
        self.id_number = id_number
        self.first = first
        self.last = last
        self.age = age
        self.connection = sqlite3.connect('08_mydata.db')
        self.cursor = self.connection.cursor()

    def load_person(self, id_number):
        self.cursor.execute("""
        SELECT * FROM persons
        WHERE id = {}
        """.format(id_number))

        results = self.cursor.fetchone()

        self.id_number = id_number
        self.first = results[1]
        self.last = results[2]
        self.age = results[3]

    def insert_person(self):
        self.cursor.execute("""
        INSERT INTO persons values
        ({}, '{}', '{}', {})
        """.format(self.id_number, self.first, self.last, self.age))
        self.connection.commit()


p1 = Person()
p1.load_person(1)
print(p1.first)

p7 = Person(7, "Alex", "Robbins", 30)
p7.insert_person()

connection = sqlite3.connect("08_mydata.db")
cursor = connection.cursor()
cursor.execute("SELECT * FROM persons")
results = cursor.fetchall()
print(results)
connection.close()

# connection = sqlite3.connect('08_mydata.db')
# cursor = connection.cursor()

# cursor.execute("""
# CREATE TABLE IF NOT EXISTS persons (
#     id INTEGER PRIMARY KEY,
#     first_name TEXT,
#     last_name TEXT,
#     age INTEGER
# )
# """)

# cursor.execute("""
# INSERT INTO persons VALUES
# (1, 'Paul', 'Smith', 24),
# (2, 'Mark', 'Johnson', 43),
# (3, 'Anna', 'Smith', 34)
# """)

# cursor.execute("""
# SELECT * FROM persons
# WHERE last_name = 'Smith'
# """)

# rows = cursor.fetchall()
# print(rows)
# connection.commit()
# connection.close()

Recursion

.

n = 7
fact = 1
while n > 0:
    fact = fact * n
    n -= 1
print(fact)
def factorial(n):
    if n < 1:
        return 1
    else:
        number = n * factorial(n - 1)
        return number
print(factorial(7))


#######################

def fibonacci(n):
    a, b = 0, 1
    for x in range(n):
        a, b = b, a + b
    return a
print(fibonacci(996))


def fibonacci2(n):
    if n < 1:
        return n
    else:
        return (fibonacci2(n-1) + fibonacci2(n-2))
# print(fibonacci2(996))

XML

.

import xml.sax


class GroupHandler(xml.sax.ContentHandler):

    def startElement(self, name, attrs):
        self.current = name
        if self.current == "person":
            print("------Person------")
            print(f"ID: {attrs['id']}")

    def characters(self, content):
        if self.current == "name":
            self.name = content
        elif self.current == "age":
            self.age = content
        elif self.current == "weight":
            self.weight = content
        elif self.current == "height":
            self.height = content

    def endElement(self, name):
        if self.current == "name":
            print(f"Name: {self.name}")
        elif self.current == "age":
            print(f"Age: {self.age}")
        elif self.current == "weight":
            print(f"Weight: {self.weight}")
        elif self.current == "height":
            print(f"Height: {self.height}")
        self.current = ""


handler = GroupHandler()
parser = xml.sax.make_parser()
parser.setContentHandler(handler)
parser.parse('10_data.xml')

XML P2

.

import xml.dom.minidom

domtree = xml.dom.minidom.parse("10_data.xml")
group = domtree.documentElement

persons = group.getElementsByTagName('person')

for person in persons:
    print("-----PERSON-----")
    if person.hasAttribute("id"):
        print(f"ID: {person.getAttribute('id')}")

    print(f"Name: {person.getElementsByTagName('name')[0].childNodes[0].data}")
    print(f"Age: {person.getElementsByTagName('age')[0].childNodes[0].data}")
    print(f"Weight: {person.getElementsByTagName('weight')[0].childNodes[0].data}")
    print(f"Height: {person.getElementsByTagName('height')[0].childNodes[0].data}")


# persons[2].getElementsByTagName("name")[0].childNodes[0].nodeValue = "New Name"
# persons[0].setAttribute("id", "100")
# persons[3].getElementsByTagName("age")[0].childNodes[0].nodeValue = "-10"
# domtree.writexml(open("10_data.xml", "w"))

newperson = domtree.createElement("person")
newperson.setAttribute('id', "6")

name = domtree.createElement("name")
name.appendChild(domtree.createTextNode("Paul Green"))
age = domtree.createElement("age")
age.appendChild(domtree.createTextNode("30"))
weight = domtree.createElement("weight")
weight.appendChild(domtree.createTextNode("80"))
height = domtree.createElement("height")
height.appendChild(domtree.createTextNode("179"))

newperson.appendChild(name)
newperson.appendChild(age)
newperson.appendChild(weight)
newperson.appendChild(height)

group.appendChild(newperson)

domtree.writexml(open("10_data.xml", "w"))

Logging

# DEBUG # INFO # WARNING - python's security level # ERROR # CRITICAL

import logging

logging.basicConfig(level=logging.DEBUG)

logging.info("You have got 20 mails in your inbox!")
logging.critical("All components failed!")

logger = logging.getLogger("my logger")
logger.info("The best logger out there")
logger.critical("Your app is down")
logger.log(logging.ERROR, "An error occurred!")

logger.setLevel(logging.DEBUG)

handler = logging.FileHandler("11_mylog.log")
handler.setLevel(logging.INFO)

formatter = logging.Formatter("%(levelname)s - %(asctime)s: %(message)s")

handler.setFormatter(formatter)
logger.addHandler(handler)
logger.debug("This is a debug message!")
logger.info("This is important information!")

Methods & Dunder

.

class Person:

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __del__(self):
        print("Object is being deleted!")


p = Person("Mike", 25)


class Vector:

    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)

    def __repr__(self):
        return f"X: {self.x}, Y: {self.y}"

    def __len__(self):
        return 10

    def __call__(self):
        print("Hello! I was called!!!")


v1 = Vector(10, 20)
v2 = Vector(50, 60)
v3 = v1 + v2
print(v3.x)
print(v3.y)
print(v3)
print(len(v3))
v3()

Decorators

.

def mydecorator(function):
    def wrapper(*args, **kwargs):  # add *args, **kwargs to be safe
        print("I am decorating your function!")
        function(*args, **kwargs)
        function(*args, **kwargs)
        print("I am decorating your function!")
        return_value = function(*args, **kwargs)  # structure to return after printing
        print("I am decorating your function!")
        return return_value
    return wrapper


@mydecorator
def hello_world(person):
    print(f"Hello {person} World!")
    return f"Hello {person}!"


print(hello_world("Mike"))


# PRACTICAL Example #1 - Logging
def logged(function):
    def wrapper(*args, **kwargs):
        value = function(*args, **kwargs)
        with open('logfile.txt', 'a+') as f:
            fname = function.__name__
            print(f"{fname} retunred value {value}")
            f.write(f"{fname} retunred value {value}\n")
        return value
    return wrapper


@logged
def add(x, y):
    return x + y


print(add(10, 20))


# PRACTICAL Example #2 - Timing
import time
def timed(function):
    def wrapper(*args, **kwargs):
        before = time.time()
        value = function(*args, **kwargs)
        after = time.time()
        fname = function.__name__
        print(f"{fname} took {after-before} seconds to execute!")
        return value
    return wrapper

@timed
def myfunction(x):
    result = 1
    for i in range(1, x):
        result *= i
    return result

myfunction(100000)

Generators

IT DOESN'T STORE ANY VALUES. IT JUST YIELDS THE NEXT VALUE. IT DOESN'T WASTE MEMORY

import sys
def mygenerator(n):
    for x in range(n):
        yield x ** 3

values = mygenerator(10000)
print(next(values))
print(next(values))
print(next(values))
print(next(values))
print(next(values))
print(next(values))
for x in values:
    print(x)
print(sys.getsizeof(values))


######

def infinite_sequence():
    result = 1
    while True:
        yield result
        result *= 5

values = infinite_sequence()
print(next(values))
print(next(values))
print(next(values))
print(next(values))
print(next(values))
print(next(values))

Argument Parsing

# python3 03_Argument_parsing.py -f file.txt -m test # python3 03_Argument_parsing.py file.txt test

#     print(args[3])
#     print(kwargs['KEYONE'])
#     print(kwargs['KEYTWO'])
# myfunction('hey', True, 19, 'wow', KEYONE="TEST", KEYTWO=7)


# ACTUAL ARGUMENT PARSING
import sys

# print(sys.argv[0])
# print(sys.argv[1])

# Usage: main.py FILENAME
# filename = sys.argv[1]
# message = sys.argv[2]
# with open(filename, 'w+') as f:
#     f.write(message)


import getopt

opts, args = getopt.getopt(sys.argv[1:], "f:m:", ['filename', 'message'])  # change to f:m:t if nothing after

print(opts)
print(args)

filename = "test.txt"  # default values
message = "Hello"  # default values

for opt, args in opts:
    if opt == "-f":
        filename = args
    if opt == "-m":
        message = args

with open(filename, "w+") as f:
    f.write(message)

Encapsulation

.

class Person:
    def __init__(self, name, age, gender):
        self.__name = name
        self.__age = age
        self.__gender = gender

    @property
    def Name(self):
        return self.__name

    @Name.setter
    def Name(self, value):
        # we can write tests here to check for certain conditions are set
        if value == "Bob":
            self.__name = "Default Name"
        else:
            self.__name = value

    @staticmethod
    def mymethod():
        print("Hello World!")


Person.mymethod()

p1 = Person("Mike", 20, 'm')
print(p1.Name)

p1.mymethod()

p1.Name = "Bob"
print(p1.Name)

Type hinting

.

def myfunction(parameter: int) -> str:
    return f"{parameter + 10}"


def otherfunction(otherparameter: str):
    print(otherparameter)


otherfunction(myfunction(20))


def dosmth(param: list[int]):
    pass

Factory Design Pattern

.

from abc import ABCMeta, abstractstaticmethod, abstractmethod


class IPerson(metaclass=ABCMeta):

    @abstractstaticmethod
    def person_method():
        """ Interface Method """


class Student(IPerson):

    def __init__(self):
        self.name = "Badsic student name"

    def person_method():  # self?
        print("I am a student")


class Teacher(IPerson):

    def __init__(self):
        self.name = "Basic teacher name"

    def person_method():  # self?
        print("I am a teacher")


# p1 = IPerson
# p1.person_method()


s1 = Student
s1.person_method()
#
t1 = Teacher
t1.person_method()


class PersonFactory:
    @staticmethod
    def build_person(person_type):
        if person_type == "Student":
            return Student()
        if person_type == "Teacher":
            return Teacher()
        print("Invalid Type")
        return -1


if __name__ == "__main__":
    choice = input("What type of person do you want to create?\n")
    person = PersonFactory.build_person(choice)
    person.person_method()

Proxy Design Pattern

.

from abc import ABCMeta, abstractstaticmethod


class IPerson(metaclass=ABCMeta):
    @abstractstaticmethod
    def person_method():
        """Interface method"""


class Person(IPerson):
    def person_method(self):
        print("I am a person")


class ProxyPerson(IPerson):
    def __init__(self):
        self.person = Person()

    def person_method(self):
        print("I am the proxy functionality!")
        self.person.person_method()


p1 = Person()
p1.person_method()

p2 = ProxyPerson()
p2.person_method()

Singleton Design Pattern

.

from abc import ABCMeta, abstractstaticmethod


class IPerson(metaclass=ABCMeta):
    @abstractstaticmethod
    def print_data():
        """implement in child class"""


class PersonSingleton(IPerson):

    __instance = None

    @staticmethod
    def get_instance():
        if PersonSingleton.__instance == None:
            PersonSingleton("Default name", 0)
        return PersonSingleton.__instance

    def __init__(self, name, age):
        if PersonSingleton.__instance != None:
            raise Exception("Singleton cannot be instantiated more than once!")
        else:
            self.name = name
            self.age = age
            PersonSingleton.__instance = self

    @staticmethod
    def print_data():
        print(f"Name: {PersonSingleton.__instance.name}. Age: {PersonSingleton.__instance.age}")


p = PersonSingleton("Mike", 30)
print(p)
p.print_data()

# p2 = PersonSingleton("Bob", 25)
# print(p2)
# p2.print_data()

p3 = PersonSingleton.get_instance()
print(p3)
p3.print_data()

Composite Design Pattern

.

from abc import ABCMeta, abstractmethod, abstractstaticmethod


class IDepartment(metaclass=ABCMeta):

    @abstractmethod
    def __init__(self, employees):
        """ Implement in child class"""

    @abstractstaticmethod
    def print_department():
        """ implement in chile class"""


class Accounting(IDepartment):

    def __init__(self, employees):
        self.employees = employees

    def print_department(self):
        print(f"Accounting Department: {self.employees}")


class Development(IDepartment):

    def __init__(self, employees):
        self.employees = employees

    def print_department(self):
        print(f"Development Department: {self.employees}")


class ParentDepartment(IDepartment):

    def __init__(self, employees):
        self.employees = employees
        self.base_employees = employees
        self.sub_depts = []

    def add(self, dept):
        self.sub_depts.append(dept)
        self.employees += dept.employees

    def print_department(self):
        print("Parent Department")
        print(f"Parent Department Base Employees: {self.base_employees}")
        for dept in self.sub_depts:
            dept.print_department()
        print(f"Total number of employees: {self.employees}")


dept1 = Accounting(200)
dept2 = Development(200)
parent_dept = ParentDepartment(30)
parent_dept.add(dept1)
parent_dept.add(dept2)

parent_dept.print_department()