Fundamentele Programării in PYTHON
Fundamentele Programării in PYTHON
Limbajul de programare
PYTHON
Ce este programarea
Hardware / software
Hardware - computere(desktop,laptop, etc) i alte dispozitive (mobile, atm,
etc)
Software - programe sau sisteme ce ruleaz pe hardware
Limbaj de programare Notaii i reguli pentru scrierea de programe
(sintax i semantic)
Python: Limbaj de programare de nivel nalt (high level programming
language).
Interpretor Python: un program care permite rularea/interpretarea
programelor scrise in limbajul Python.
Biblioteci Python: Funcii, module, tipuri de date disponibile n Python,
scrise de ali programatori
Informaii i date
Date - o colecie de simboluri stocate ntr-un computer (Ex. 123 decimal
sau irul de caractere abc) sunt stochate folosind reprezentarea binara
Informaii - interpretarea unor date (Ex. 123, abc)
Procesarea datelor i informaiilor
Dispozitivele de intrare transform informaiile n date (ex. 123
citit de la tastatur)
Datele sunt stocate n memorie (ex. 1111011 pentru numrul
123)
Dispozitivele de ieire produc informaii din date
Operaii de baz ale procesoarelor
n reprezentare binar
Operaii (and, or, not; add, etc)
Elemente de baz ale unui program Python
Program 2 - Adding two integers
Elemente lexicale
Un program Python este alctuit din mai multe linii de cod
Comentarii
ncep cu # i in pn la sfritul liniei
bool (boolean):
Valorile True i False.
Operaii: and, or, not
Literali: False, True; 0, 1
Secvene:
Mulimi finite i ordonate, indexate prin numere ne-negative.
Dac a este o secven atunci:
len(a) returnez numrul de elemente;
a[0], a[1], , a[len(a)-1] elementele lui a.
Examples: [1, a]
Stringuri:
este o secven inmutabil;
caractere Unicode .
Literali: abc, abc
Liste
secven mutabil
ex: [] sau [1, a, [1, 3]]
Liste
operaii:
creare [7, 9]
accesare valori,lungime (index, len), modificare valori (listele sunt mutabile),
verificare daca un element este in lista (2 in [1, 2, 'a'])
stergere inserare valori (append,insert,pop) del a[3]
slicing, liste eterogene
listele se pot folosi in for
lista ca stiv(append, pop)
folositi instructiunea help(list) pentru mai multe detalii despre operaii posibile
# create # slicing
a = [1, 2, 'a'] print a[:2]
print (a) b = a[:]
x, y, z = a print (b)
print(x, y, z) b[1] = 5
print (b)
# indices: 0, 1, ..., len(a) 1 a[3:] = [7, 9]
print a[0] print(a)
print ('last element = ', a[len(a)-1]) a[:0] = [-1]
print(a)
# lists are mutable a[0:2] = [-10, 10]
a[1] = 3 print(a)
print a
# lists as stacks # nesting
stack = [1, 2, 3] c = [1, b, 9]
stack.append(4) print (c)
print stack
print stack.pop()
print stack
#generate lists using range #list in a for loop
l1 = range(10) l = range(0,10)
print l1 for i in l:
l2 = range(0,10) print i
print l2
l3 = range(0,10,2)
print l3
l4 = range(9,0,-1)
print l4
Tuple
Sunt secvene inmutabile. Conine elemente, indexat de la 0
Operations:
Crearea - packing (23, 32, 3)
eterogen
poate fi folosit in for
unpacking
Expressi
O combinaie de valori, constante, variabile, operatori i funcii care sunt
interpretate conform regulilor de preceden, calculate i care produc o alt
valoare
Exemple:
numeric : 1 + 2
boolean: 1 < 2
string : 1 + 2
Funcii utile:
help(instructiune) - ajutor
id(x) identitatea obiectului
dir()
locals() / globals() - nume definite (variabile, funcii, module, etc)
Instruciuni
Atribuire/Legare
Instructiunea =.
Atribuirea este folosit pentru a lega un nume de o variabil
Poate fi folosit i pentru a modifica un element dintr-o
secvena mutabil.
Legare de nume:
x = 1 #x is a variable (of type int)
Re-legare name:
x = x + 2 #a new value is assigned to
x
Modificare secven:
y = [1, 2] #mutable sequence
y[0] = -1 #the first item is bound to
-1
Blocuri
Parte a unui program care este executat ca o unitate
Secven de instruciuni
Se realizeaz prin identarea liniilor (toate instruciunile
identate la acelai nivel aparin aceluiai bloc
Instruciuni - If, While
def gcd(a, b):
"""
Return the greatest common divisor of two positive integers.
"""
if a == 0:
return b
if b == 0:
return a
while a != b:
if a > b:
a = a - b
else:
b = b - a
return a
print gcd(7,15)
Instruciuni For
#use a list literal
for i in [2,-6,"a",5]:
print (i)
#using a variable
x = [1,2,4,5]
for i in x:
print (i)
#using range
for i in range(10):
print (i)
for i in range(2,100,7):
print (i)
#using a string
s = "abcde"
for c in s:
print (c)
Cum se scriu programe
Cerine (requirements)
Cerinele definesc n detaliu de ce este nevoie n program din perspectiva
clientului. Definete:
Ce dorete clientul
Ce trebuie inclus n sistemul informatic pentru a
satisface nevoile clientuli.
Reguli de elaborare a cerinelor:
Cerinele exprimate corect asigur dezvoltarea sistemului
conform ateptrilor clienilor. (Nu se rezolv probleme ce
nu s-au cerut)
Descriu lista de funcionaliti care trebuie oferite de sistem.
Funcionalitile trebuie s clarifice orice ambiguiti din enun.
Funcionalitate
Pentru programe mai simple putem folosi scenarii de rulare (tabelar) pentru a
nelege problema i modul n care funcionalitatea se manifest n program. Un
scenariu descrie interaciunea ntre utilizator i aplicaie.
23 1
24 2
64 2
02 2
20 2
24 9 3
-2 0 ValueError
0 -2 ValueError
Programare procedural
Paradigm de programare
stil fundamental de scriere a programelor, set de convenii ce dirijeaz
modul n care gndim programele.
Programare imperativ
Calcule descrise prin instruciuni care modific starea programului. Orientat
pe aciuni i efectele sale
Programare procedural
Programul este format din mai multe proceduri (funcii, subrutine)
Ce este o funcie
O funcie este un bloc de instruciuni de sine stttor care are:
un nume,
poate avea o list de parametrii (formali),
poate returna o valoare
are un corp format din instructiuni
are o documentaie (specificaie) care include:
o scurt descriere
tipul i descriere parametrilor
condiii impuse paramterilor de intrare (precondiii)
tipul i descrierea valorii returnate
condiii impuse rezultatului, condiii care
sunt satisfcute n urma executrii (post-
condiii).
Excepii ce pot s apar
O funcie ca i n exemplu de mai joi, este corect sintactic (funcioneaz n Python) dar
la laborator/examen nu consideram astfel de funcii:
def f(k):
l = 2
while l<k and k % l>0:
l=l+1
return l>=k
def isPrime(nr):
"""
Verify if a number is prime
nr - integer number, nr>1
return True if nr is prime, False otherwise
"""
div = 2 #search for divider starting from 2
while div<nr and nr % div>0:
div=div+1
#if the first divider is the number itself than the number is prime
return div>=nr;
Definiia unei funcii n Python
max(2,5)
n Python avem mai multe spaiile de nume, ele sunt create n momente
diferite i au ciclu de viaa diferit.
General/implicit creat la pornirea interpretorului, conine
denumiri predefinite (built-in)
global creat la incrcarea unui modul, conine nume globale
globals() - putem inspecta spaiu de nume global
local creat la apelul unei funcii, conine nume locale funciei
locals() - putem inspecta spaiu de nume local
Transmiterea parametrilor
Parametru formal este un identificator pentru date de intrare. Fiecare apel
trebuie s ofere o valoare pentru parametru formal (pentru fiecare
parametru obligatoriu)
Parametru actual valoare oferit pentru parametrul formal la apelul
funciei.
def change_or_not_immutable(a):
print ('Locals ', locals())
print ('Before assignment: a = ', a, ' id = ', id(a))
a = 0
print ('After assignment: a = ', a, ' id = ', id(a))
def change_or_not_mutable(a):
print ('Locals ', locals())
print ('Before assignment: a = ', a, ' id = ', id(a))
a[1] = 1
a = [0]
print ('After assignment: a = ', a, ' id = ', id(a))
global_var = 100
def f():
local_var = 300
print local_var
print global_var
Domeniu de vizibilitate
Reguli de accesare a variabilelor (sau orice nume) ntr-o funcie:
cand se folosete un nume de variabil ntr-o funcie se caut
n urmtoarele ordine n spaiile de nume:
spaiu local
spaiu local funciei exterioare (doar dac avem funcie declarat
n interorul altei funcii)
spaiu global (nume definite n modul)
spaiul built-in
operatorul = schimba/creaz variabile n spaiu de nume local
Putem folosi declaraia global pentru a referi/importa o
variabil din spaiu de nume global n cel local
nonlocal este folosit pentru a referi variabile din funcia
exterioar (doar dac avem funcii n funcii
a = 100 a = 100
def f(): def f():
a = 300 global a
print (a) a = 300
print (a)
f()
print (a) f()
print (a)
globals() locals() - funcii built-in prin care putem inspecta spaiile de nume
a = 300
def f():
a = 500
print (a) print
locals()
print globals()
f()
print (a)
Cum scriem funcii Cazuri de testare
nainte s implementm funcia scriem cazuri de testare pentru:
a specifica funcia (ce face, pre/post condiii, excepii)
ca o metod de a analiza problema
s ne punem n perspectiva celui care folosete funcia
pentru a avea o modalitate sa testam dup ce implementm
Cazurile de testare:
se pot face n format tabelar, tabel cu date/rezultate.
executabile: funcii de test folosind assert
biblioteci/module pentru testare automat
assert expresie
24 9 3
Implementare gdc
def gcd(a, b):
"""
Compute the greatest common divisor of two positive integers
a, b integers a,b >=0
Return the greatest common divisor of two positive integers.
"""
if a == 0:
return b
if b == 0:
return a
while a != b:
if a > b:
a = a - b
else:
b = b - a
return a
Cum se scriu funcii
Dezvoltare dirijat de teste (test-driven development - TDD)
Dezvoltarea drijat de teste presupune crearea de teste automate, chiar
nainte de implementare, care clarific cerinele
Paii TDD pentru crearea unei funcii:
Addaug un test
Scriei o funcie de test (test_f()) care conine
cazuri de testare sub forma de aseriuni
(instruciuni assert).
La acest pas ne concentram la specificaiile funciei
f.
Definim funcia f: nume, parametrii, precondiii,
post-condiii, i corpul gol (instruciunea pass).
Rulm toate testele i verificm ca noul test pic
Pe parcursul dezvoltrii o sa avem mai multe
funcii, astfel o s avem mai multe funcii de test .
La acest pas ne asigurm ca toate testele
anterioare merg, iar testul nou adugat pic.
Scriem corpul funciei
La acest pas avem deja specificaiile, ne
concentrm doar la implementarea funciei
conform specificaiilor i ne asigurm ca noile
cazuri de test scrise pentru funcie trec (funcia de
test)
La acest pas nu ne conentrm la
aspecte technice (cod duplicat,
optimizri, etc).
Rulm toate testele i ne asigurm c trec
Rulnd testele ne asigurm c nu am stricat nimic
i noua funcie este implementat conform
specificaiilor
Refactorizare cod
La acest pas inbuntim codul,
folosind refactorizri
Dezvoltare dirijat de teste (test-driven development - TDD)
Dezvoltarea drijat de teste presupune crearea de teste automate, chiar
nainte de implementare, care clarific cerinele
def test_gcd():
"""
test function for gdc
"""
assert gcd(0, 2) == 2
assert gcd(2, 0) == 2
assert gcd(2, 3) == 1
assert gcd(2, 4) == 2
assert gcd(6, 4) == 2
assert gcd(24, 9) == 3
import ui.console
Iniializare modul
Modulul poate conine orice instruciuni. Cnd modulul este importat
prima dat se execut toate instruciunile.Putem include instruciuni
(altele dect definiiile de funcii) care iniializeaz modulul.
Domeniu de vizibilitate n modul
La import:
se creaz un nou spaiu de nume
variabilele i funciile sunt introduse n noul spaiu de nume
doar numele modulului ( name ) este adugat n spaiul de
nume curent.
#only import the name ui.console into the current symbol table
import ui.console
#import the function name gdc into the local symbol table
from utils.numericlib import gcd
Fiecare director care conine pachete trebuie sa conin un fiier init .py. Acesta
poate conine i instruciuni (codul de iniializare pentru pachet)
Eclipse + PyDev IDE (Integrated Development Environment)
Eclipse: Mediu de dezvoltare pentru python (printre altele).
Pydev: Plugin eclipse pentru dezvoltare aplicaii Python n
Eclipse
Instalare:
Java JRE 7 (varianta curenta de PyDev funcioneaz doar cu aceast
versiune de Java
Eclipse Luna (sau alta versiune de eclipse de la 3.5 n sus)
Instalat pluginul de PyDev
Proiect
Editor Python
ProjectExplorer: Pachete/Module
Outline: Funcii
Rulare/Depanare programe
Cum organizm aplicaia pe module i pachete
Dependene
funcia: apeleaz o alt funcie
modul: orice funcie din modul apelaz o funcie din alt modul
dependenelor
Cuplare
Cu ct exist mai multe conexiuni ntre module cu att modulul este mai greu de neles,
ntreinut, refolosit i devine dificil izolarea prolemelor cu ct gradul de cuplare este mai
sczut cu att mai bine
Gradul de cuplare sczut(Low coupling) faciliteaz dezvoltarea de aplicai care pot fi uor
modificate (interdependena ntre module/funcii este minim astfel o modificare afecteaz doar
o parte bine izolat din aplicaie)
Coeziunea
Msoar ct de relaionate sunt resposabilitile unui element din program (pachet,modul,
clas)
Modulul poate avea:
Grad de coeziune ridicat (High Cohesion): elementele implementeaz
responsabiliti nrudite
Grad de coeziune sczut (Low Cohesion): implementeaz responsabiliti
diverse din arii diferite (fr o legatur conceptual ntre ele)
Dac elementele modulului implementeaza responsabiliti disparate cu att modulul este mai
greu de Modulele ar trebui sa aib grad de coeziune ridicat
neles/ntreinut
Arhitectur stratificat (Layered Architecture)
Arhitectur stratificat este un ablon arhitectural care permite dezvoltarea de sisteme flexibile
n care componentele au un grad ridicat de independen
Fiecare strat comunic doar cu startul imediat urmtor (depinde doar doar de
stratul imediat urmtor)
Fiecare strat are o interfa bine definit (se ascun detaliile), interfa folosit de stratul
imediat superior
Arhitectur stratificat
#domain
l = [["Ion",50],["Ana",30],["Pop",100]]
def filterScoreDomain(st, end): #filter the score board
global l
rez = filterMatrix(l, 1, st, end)
l = rez
return rez
>>> x=0
>>> print 10/x
def compute(a,b):
print ("compute :start ")
aux = a/b
print ("compute:after division")
rez = aux*10
print ("compute: return")
return rez
def main():
print ("main:start")
a = 40
b = 1
c = compute(a, b)
print ("main:after compute")
print ("result:",c*c)
print ("main:finish")
main()
Tratarea excepiilor (Exception handling)
Procesul sistematic prin care excepiile aprute n program sunt gestionate, executn
aciuni necesare pentru remedierea situaiei.
try:
#code that may raise exceptions
pass
except ValueError:
#code that handle the error
pass
Excepiile pot fi tratate n blocul de instruciuni unde apar sau n orice bloc exterior care
in mod direct sau indirect a apelat blocul n care a aprut excepia (excepia a fost
aruncat)
Dac excepia este tratat, acesta oprete rularea programului
def f():
# x = 1/0
raise ValueError("Error Message") # aruncm excepie
try:
f()
except ValueError as msg:
print "handle value error:", msg
except KeyError:
print "handle key error"
except:
print "handle any other errors"
finally:
print ("Clean-up code here")
execuie
Specificaii
Nume sugestiv
scurta descriere (ce face funcia)
tipul i descrierea parametrilor
condiii asupra parametrilor de intrare (precondiii)
tipul, descrierea rezultatului
relaia ntre date i rezultate (postcondiii)
Excepii care pot fi aruncate de funcie, i condiiile in care se arunc
Clasele se folosesc pentru crearea de noi tipuri de date (tipuri de date definite de utilizator)
Tip de date:
domeniu
operatii
Clasele sunt folosite ca un sablon pentru crearea de obiecte (instante), clasa defineste
elementele ce definesc starea si comportamentul obiectelor.
Definitie de clas n python
class MyClass:
<statement 1>
.
<statement n>
Instruciunile din interiorul clasei sunt n general definiii de funcii, dar i alte instruciuni
sunt permise
Clasa are un spaiu de nume propriu, definiiile de funcii din interiorul clasei (metode)
introduc numele funciilor n acest spaiu de nume nou creat. Similar i pentru variabile
Obiect
Object (instan) este o colecie de date i funcii care opereaz cu aceste date
Fiecare obiect are un tip, este de tipul clasei asociate: este instaa unei clase
Obiectul:
inglobeaz o stare: valorile campurilor
folosind metodele:
putem modifica starea
putem opera cu valorile ce descriu starea obiectelor
Fiecare obiect are propiul spaiu de nume care conine campurile i metodele.
Creare de obiecte. Creare de instane a unei clase ( init )
Instanierea une clase rezulte in obiecte noi (instane). Pentru creara de obiecte se
foloseste notaie similar ca i la funcii.
x = MyClass()
Operaia de instaniere (apelul unei clase) creaz un obiect nou, obiectul are tipul
MyClass
O clas poate defini metoda special init care este apelat n momentul instanierii
class MyClass:
def init (self):
self.someData = []
init :
creaz o instan
foloseste self pentru a referi instana (obiectul) curent (similar cu this din alte
limbaje orientate obiect)
Putem avea metoda init care are i ali parametrii n afar de self
Campuri
x = RationalNumber(1,3) y
= RationalNumber(2,3)
x.m = 7
x.n = 8
y.m = 44
y.n = 21
class RationalNumber:
"""
Abstract data type for rational numbers
Domain: {a/b where a and b are integer numbers b!=0}
"""
self.n = a vs n=a
def testCreate():
"""
Test function for creating rational numbers
"""
r1 = RationalNumber(1,3) #create the rational number 1/3
assert r1.getNominator()==1
assert r1.getDenominator()==3
r1 = RationalNumber(4,3) #create the rational number 4/3
assert r1.getNominator()==4
assert r1.getDenominator()==3
class RationalNumber:
"""
Abstract data type rational numbers
Domain: {a/b where a,b integer numbers, b!=0, greatest common divisor
a, b =1}
"""
def init (self, a, b):
"""
Initialize a rational number
a,b integer numbers
"""
self. nr = [a, b]
def getDenominator(self):
"""
Getter method
return the denominator of the rational number
"""
return self. nr[1]
def getNominator(self):
""""
Getter method
return the nominator of the method
"""
return self. nr[0]
Metode speciale. Suprncrcarea operatorilor. (Operator overloading)
str - conversie in tipul string (print representation)
def str (self):
"""
provide a string representation for the rational number
return a string
"""
return str(self. nr[0])+"/"+str(self. nr[1])
lt , le , gt , ge - comparaii (<,<=,>,>=)
eq - verify if equals
Operator overloading
call (self, arg) - to make a class behave like a function, use the ()
a = A()
a()
Vizibilitate i spaii de nume n Python
class RationalNumber:
"""
Abstract data type for rational numbers
Domain: {a/b where a and b are integer numbers b!=0}
"""
#class field, will be shared by all the instances
numberOfInstances =0
numberOfInstances =0 def
init (self,n,m):
self.n = n
self.m = m
RationalNumber.numberOfInstances+=1
def testNumberInstances():
assert RationalNumber.numberOfInstances == 0
r1 = RationalNumber(1,3)
#show the class field numberOfInstances
assert r1.numberOfInstances==1
# set numberOfInstances from the class
r1.numberOfInstances = 8
assert r1.numberOfInstances==8 #access to the instance field
assert RationalNumber.numberOfInstances==1 #access to the class field
testNumberInstances()
Class Methods
Funcii din clas care nu opereaza cu o instana.
Alte limbaje: metode statice
class RationalNumber:
#class field, will be shared by all the instances
numberOfInstances =0
@staticmethod
def getTotalNumberOfInstances():
"""
Get the number of instances created in the app
"""
return RationalNumber.numberOfInstances
def testNumberOfInstances():
"""
test function for getTotalNumberOfInstances
"""
assert RationalNumber.getTotalNumberOfInstances()==0
r1 = RationalNumber(2, 3)
assert RationalNumber.getTotalNumberOfInstances()==1
testNumberOfInstances()
Datele care reprezint starea i metodele care manipuleaza datele sunt strns legate, ele
formeaz o unitate coeziv.
Starea si comportamentul ar trebui ncapsulat n acelasi unitate de program (clasa)
Ascunderea informaiilor
Reprezentarea interna a obiectelor (a strii) trebuie protejat fa de restul aplicaiei.
Ascunderea reprezentrii protejeaz integritatea datelor i nu permite modificarea starii din
exteriorul clasei, astfel se evit setarea, accidentala sau voita, unei stari inconsistente.
Clasa comunica cu exteriorul doar prin interfaa public (mulimea tuturor metodelor vizibile in
exterior) i ascunde orice detalii de implementare (modul n care am reprezentat datele,
algoritmii folosii,etc).
De ce:
Definirea unei interfee clare i ascunderea detaliilor de implementare asigur ca alte module
din aplicaie sa nu pot face modificri care ar duce la stari inconsistente. Permite evoluia
ulterioar (schimbare reprezentare, algoritmi etc) fr s afectm restul aplicaiei
Limitai interfaa (metodele vizibile n exterior) astfel nct s existe o libertate n modificarea
implementrii (modificare fr a afecta codul client)
Codul client trebuie s depind doar de interfaa clasei, nu de detalii de implementare. Dac
folosii acest principiu, atunci se pot face modificri fr a afecta restul aplicaiei
Membri publici. Membrii privai Ascunderea implementrii in Python
Un nume care incepe cu _ sau semnaleaza faptul ca atributul (camp, metode) ar trebui tratat
ca fiind un element care nu face parte din interfaa public. Face parte din reprezentarea
intern a clasei, nu ar trebui accesat din exterior.
Recomandri
Creai metode pentru a accesa campurile clasei (getter)
folositi conveniile de nume _, pentru a delimita interfaa public a clasei de
detaliile de implementare
Codul client ar trebui sa funcioneze (fr modificri) chiar daca schimbam
reprezentarea intern, atta timp ct interfaa public rmne
neschimbat. Clasa este o abstractizare, o cutie neagra (black box)
Specificaiile funciilor trebuie sa fie independente de reprezentare
Cum crem clase
Folosim Dezvoltare dirijat de teste
Campurilie clasei (reprezentarea) se declar private ( nume). Se creaz metode getter pentru
a accesa cmpurile clasei
Tipuri abstracte de date (Abstract data types)
Tip abstract de date:
operaiile sunt specificate independent de felul n care operaia este
implementat
operaiile sunt specificate independent de modul de reprezentare a datelor
Relaii UML
O relaie UML este un termen general care descrie o legatur logic ntre
dou elemente de pe o diagram de clase.
Un Link este relaia ntre obiectele de pe diagram. Este
reprezentat printr-o linie care conecteaza dou sau mai multe
dreptunghiuri.
Associeri
Asocierile binare se reprezint printr-o linie ntre dou clase.
Agregare
Agregarea este o asociere specializat. Este o asociere ce reprezint
relaia de parte-ntreg (part-whole) sau apartenena (part-of).
Dependene, Pachete
Relaia de dependen este o asociere n care un element depinde sau
foloseste un alte element
Exemple de dependene:
creaz instane
are un parametru
foloseste un obiect n interiorul unei metode
Principii de proiectare
Creaz aplicaii care:
Sunt uor de neles, modificat, ntreinut, testat
Clasele abstracte, ncapsulare, ascunderea reprezentrii, uor de
testat, uor de folosit i refolosit
Funcionaliti (Features)
F1 Adauga student
F2 vizualizare studeni
F3 caut student
F4 terge student
Plan de iteraii
IT1 - F1; IT2 F2; IT3 F3; IT4 - F4
a add a student
give student id
give name
Ion
a add student
give student id
give name
abloane Grasp
General Responsibility Assignment Software Patterns (or Principles)
conin recomandri pentru alocarea responsabilitilor pentru clase obiecte
ntr-o aplicaie orientat obiect.
High Cohesion
Low Coupling
Information Expert
Controller
Protected Variations
Creator
Pure Fabrication
High Cohesion
Aloc responsabilitile astfel nct coeziunea n sistem rmne
ridicat
Low Coupling
Aloc responsabiliti astfel nct cuplarea rmne slab (redus)
Forme de cuplare:
TypeX are un cmp care este de TypeY.
TypeX are o medod care refer o instan de tipul TypeY n orce
form (parameterii, variabile locale, valoare returnat, apel la
metode)
TypeX ete derivat direct sau indirect din clasa TypeY.
Information Expert
Aloc responsabilitatea clasei care are toate informaiile necesare
pentru a ndeplini sarcina
Point of Sale
Conform Expert
1. Menine ncapsularea
2. Promoveaz cuplare slab
3. Promoveaz clase puternic coezive
4. Poate sa conduc la clase complexe - dezavantaj
Creator
Crearea de obiecte este o activitate important ntr-un sistem orientat
obiect. Care este clasa responsabil cu crearea de obiecte este o
proprietate fundabental care definete relaia ntre obiecte de diferite
tipuri.
Work items
Task
T1 Create Student
T2 Validate student
T3 Store student (Create repository)
T4 Add student (Create Controller)
T5 Create UI
def getId(self):
return self.id
def getName(self):
return self.name
def getAdr(self):
return self.adr
Protected Variations
Cum alocm responsabilitatea astfel nct variaiile curente i viitoare nu
vor afecta sistemul (nu va fi necesar o revizuire a sistemului, nu trebuie sa
facem schimbri majore n sistem)?
Algoritmul de validare:
Poate fi o metoda in clasa student
o metoda statica, o funcie
ncapsulat ntr-o clas
separat Poate semnala eroarea
prin:
returnare true/false
returnare lista de erori
excepii care conin lista de erori
Pure Fabrication
Cnd un element din sistem ncalc primcipiul coeziunii ridicate i cuplare
slab (n general din cauza aplicrii succesive a ablonului expert):
Aloc un set de responsabiliti la o clas artificial (clas ce nu reprezint
ceva n domeniul problemei) pentru a oferi coeziune ridicat, cuplare
slab i reutilizare
ablonul Repository
Un repository reprezint toate obiectele de un anumit tip ca si o mulime
de obiecte.
Obiecte sunt adugate, terse, modificate iar codul din repository
insereaza, sterge obiectele dintr-un depozit de date persistent.
class InMemoryRepository:
"""
Manage the store/retrieval of students
"""
def init (self):
self.students = {}
if (self.validator!=None):
self.validator.validate(st)
self.students[st.getId()] = st
GRASP Controller
Scop: decuplarea sursei de evenimente de obiectul care gestioneaz
evenimentul. Decuplarea startului de prezentare de restul aplicaiei.
Application coordinator
Dependency injection (DI) este un principiu de proiectare pentru
sisteme orientat obiect care are ca scop reducerea cuplrii ntre
componentele sistemului.
Folosind DI, obiectul nu are nevoie s cunoasc modul n care alte pri ale
sistemului sunt implementate/create. Aceste dependene sunt oferite (sunt
injectate), inpreun cu un contract (specificaii) care descriu
comportamentul componentei
#create validator
validator = StudentValidator()
#crate repository
rep = InMemoryRepository(None)
#create console provide(inject) a validator and a repository
ctr = StudentController(rep, validator)
#create console provide controller
ui = Console(ctr)
ui.showUI()
Review applicaie
Entiti
Entitate (Entity) este un obiect care este definit de identitatea lui (se identific
cu exact un obiect din lumea real).
def testIdentity():
#attributes may change
st = Student("1", "Ion", "Adr")
st2 = Student("1", "Ion",
"Adr2") assert st==st2
def eq (self,ot):
"""
Define equal for
students ot - student
return True if ot and the current instance represent the same student
"""
return self. id==ot. id
Atributele entitii se poat schimba dar identitatea rmbe acelai (pe ntreg
existena lui obiectul reprezint acelai obiect din lumea real )
def testCreateStudent():
"""
Testing student creation
Feature 1 - add a student
Task 1 - Create student
"""
st = Student("1", "Ion", Address("Adr", 1, "Cluj"))
assert st.getId() == "1"
assert st.getName() == "Ion"
assert st.getAdr().getStreet()=="Adr"
Agregate i Repository
Grupai entiti i obiecte valoare n agregate. Alegei o entitate radcin (root) care
controleaz accesul la toate elementele din agregat.
Obiectele din afara agregatului ar trebui s aib referina doar la entitatea principal.
Metode:
write(str) scrie string n fiier
readline() - citire linie cu line, returneaz string
read() - citete tot fiierul, returneaz string
close() - nchide fiier, elibereaz resursele
ocupate
Excepii:
IOError arunc aceast excepie daca apare o eroare de intrare/ieire (no file, no
disk space, etc)
Exemple Python cu fiiere text
def storeToFile(self,sts):
"""
Store all the students in to the file
raise CorruptedFileException if we can not store to the file
"""
#open file (rewrite file)
f = open(self. fName, "w")
for st in sts:
strf = st.getId()+";"+st.getName()+";"
strf = strf + st.getAdr().getStreet()+";"+str(st.getAdr().getNr())
+";"+st.getAdr().getCity()
strf =
strf+"\n"
f.write(strf)
f.close()
Dynamic Typing
Verificarea tipului se efectueaza n timpul execuiei (runtime) nu n timpul
compilrii (compile-time).
n general n limbajele cu dynamic typing valorile au tip, dar variabilele nu. Variabila
poate referi o valoare de orice tip
Duck Typing
Duck test: When I see a bird that walks like a duck and swims like a duck and quacks
like a duck, I call that bird a duck
def getCourse(self):
return self. course
l = [Student(1, "Ion"), Professor("1", "Popescu", "FP"), Student(31, "Ion2"),
Student(11, "Ion3"), Professor("2", "Popescu3", "asd")]
for el in l:
print el.getName()+" id "+str(el.getId())
def myPrint(st):
print el.getName(), " id ", el.getId()
for el in l:
myPrint(el)
#create a validator
val = StudentValidator()
#create repository
repo = StudentFileRepository("students.txt")
#create controller and inject dependencies
ctr = StudentController(val, repo)
#create Grade controller
gradeRepo = GradeFileRepository("grades.txt")
ctrgr = GradeController(gradeRepo, GradeValidator(), repo)
#create console ui and provide (inject) the controller
ui = ConsoleUI(ctr,ctrgr)
ui.startUI()
#create a validator
val = StudentValidator()
#create repository
repo = StudentRepository()
#create controller and inject dependencies
ctr = StudentController(val, repo)
#create Grade controller
gradeRepo = GradeRepository()
ctrgr = GradeController(gradeRepo, GradeValidator(), repo)
#create console ui and provide (inject) the controller
ui = ConsoleUI(ctr,ctrgr)
ui.startUI()
Asocieri ntre obiecte din domeniu
n lumea real, conceptual sunt multe relaii de tip many-to-many dar
modelarea acestor relaii n aplicaie nu este ntodeauna fezabil.
Scopul este sa modelm lumea real ct mai fidel dar n acelai timp sa
simplificm modelul pentru a nu complica implementare.
Asocieri
Exemplu Catalog
anumite aspecte.
n exemplul de mai sus GradeRepository salveaz doar id-ul studentului (nu toate
campurile studentului) astfel nu se poate implementa o funcie getAll n care se
returneaza toate notele pentru toi studenii. Se poate n scimb oferi metoda
getAll(st) care returneaz toate notele pentru un student dat
Avem nevoie de obiecte speciale (obiecte de transfer) pentru acest caz de utilizare.
Funciile din repository nu ajung pentru a implementa (nu avem getAll()).
Se creaza o noua clas care conine exact informaiile de care e nevoie.
n repository:
n controller:
def getTop5(self,disc):
"""
Get the best 5 students at a given discipline
disc - string, discipline
return list of StudentGrade ordered descending on
the grade
"""
sds = self. grRep.getAllForDisc(disc)
#order based on the grade
sortedsds = sorted(sds, key=lambda
studentGrade: studentGrade.getGrade(),reverse=True)
#retain only the first 5
sortedsds =
sortedsds[:5]
#obtain the student names
for sd in sortedsds:
st = self.
stRep.find(sd.getStudentID())
sd.setStudentName(st.getName())
return sortedsds
Motenire
Motenirea permite definirea de clase noi (clase derivate) reutiliznd clase existente (clasa de
baz). Clasa nou creat moteneste comportamentul (metode) i caracteristicile (variabile membre,
starea) de la clasa de baz
Dac A i B sunt dou clase unde B moteneste de la clasa A (B este derivat din clasa A sau clasa B este
o specializare a clasei A) atunci:
clasa B are toate metodele si variabilele membre din clasa A
clasa B poate redefini metode din clasa A
clasa B poate adauga noi membrii (variabile, metode) pe lng cele motenite de la clasa A.
Reutilizare de cod
Una din motivele pentru care folosim motenire este reutilizarea codului existent ntr-o clas (motenire de
implementare).
Motenire n Python
Syntax:
class DerivedClassName(BaseClassName):
Dac acessm un membru (cmp, metod) : se caut n clasa curent, dac nu se gsete
atunci cautarea continu n clasa de baz
class B(A): class A:
""" def init (self):
This class extends A print "Initialise
A is the base class, A"
B is the derived class
B is inheriting everything from class A def f(self):
""" print "in method f from A"
def init (self):
#initialise the base class def g(self):
A. init (self) print "in method g from A"
print "Initialise B"
def g(self):
"""
Overwrite method g from A
"""
#we may invoke the function from the
base class
A.f(self)
print "in method g from B"
b = B()
#f is inherited from A
b.f()
b.g()
Clasele Derivate pot suprascrie metodele clasei de baza.
Suprascrierea poate nlocui cu totul metoda din clasa de baz sau poate extinde funcionalitatea
(se execut i metoda din clasa de baz dar se mai adaug cod)
Relaia de generalizare ("is a") indic faptul c o clas (clasa derivat) este o
specializare a altei clase (clasa de baz). Clasa de baz este generalizarea clasei
derivate.
Repository cu Fiiere
class StudentFileRepository(StudentRepository):
"""
Repository for students (stored in a file)
"""
pass
class StudentFileRepository(StudentRepository):
"""
Store/retrieve students from file
"""
def init (self,fileN):
#properly initialise the base class
StudentRepository. init (self) self.
fName = fileN
#load student from the file
self. loadFromFile()
def loadFromFile(self):
"""
Load students from file
raise ValueError if there is an error when reading from the file
"""
try:
f = open(self. fName,"r")
except IOError:
#file not exist
return
line = f.readline().strip()
while line!="":
attrs = line.split(";")
st = Student(attrs[0],attrs[1],Address(attrs[2], attrs[3], attrs[4]))
StudentRepository.store(self, st)
line = f.readline().strip()
f.close()
Suprascriere metode
def testStore():
fileName = "teststudent.txt"
repo = StudentFileRepository(fileName)
repo.removeAll()
st = Student("1","Ion",Address("str",3,"Cluj"))
repo.store(st)
assert repo.size()==1 assert
repo.find("1") == st
#verify if the student is stored in the file
repo2 = StudentFileRepository(fileName)
assert repo2.size()==1
assert repo2.find("1") == st
def store(self,st):
"""
Store the student to the file.Overwrite store
st - student
Post: student is stored to the file
raise DuplicatedIdException for duplicated id
"""
StudentRepository.store(self, st)
self. storeToFile()
def storeToFile(self):
"""
Store all the students in to the file
raise CorruptedFileException if we can not store to the file
"""
f = open(self. fName,"w")
sts = StudentRepository.getAll(self)
for st in sts:
strf = st.getId()+";"+st.getName()+";"
strf = strf + st.getAdr().getStreet()
+";"+str(st.getAdr().getNr()) +";"+st.getAdr().getCity()
strf = strf+"\n"
f.write(strf)
f.close()
Excepii
def createdStudent(self):
"""
Read a student and store in the apllication
"""
id = input("Student id:").strip() name
= input("Student name:").strip()
street = input("Address - street:").strip()
nr = input("Address - number:").strip() city
= input("Address - city:").strip() try:
self. ctr.create(id, name,street,nr,city)
except ValueError as msg:
print (msg)
def createdStudent(self):
"""
Read a student and store in the apllication
"""
id = input("Student id:").strip() name
= input("Student name:").strip()
street = input("Address - street:").strip()
nr = input("Address - number:").strip() city
= input("Address - city:").strip() try:
self. ctr.create(id, name,street,nr,city)
except ValidationException as ex:
print (ex)
except DuplicatedIDException as ex:
print (ex)
class ValidationException(Exception):
def init (self,msgs):
"""
Initialise
msg is a list of strings (errors)
"""
self. msgs = msgs
def getMsgs(self):
return self. msgs
class StudentCRUDException(Exception):
pass
class ValidationException(StudentCRUDException):
def init (self,msgs):
"""
Initialise
msg is a list of strings (errors)
"""
self. msgs = msgs
def getMsgs(self):
return self. msgs
def str (self):
return str(self. msgs)
class RepositorException(StudentCRUDException):
"""
Base class for the exceptions in the repository
"""
def init (self, msg):
self. msg = msg
def getMsg(self):
return self. msg
def str (self):
return self. msg
class DuplicatedIDException(RepositorException):
def init (self):
RepositorException. init (self, "Duplicated ID")
def createdStudent(self):
"""
Read a student and store in the apllication
"""
id = input("Student id:").strip() name
= input("Student name:").strip()
street = input("Address - street:").strip()
nr = input("Address - number:").strip() city
= input("Address - city:").strip() try:
self. ctr.create(id, name,street,nr,city)
except StudentCRUDException as ex:
print (ex)
Testarea programelor
Testarea este observarea comportamentului unui program n multiple execuii.
Se execut programul pentru ceva date de intrare i se verific daca rezultate sunt corecte n
raport cu intrrile.
Testarea nu demonstreaz corectitudinea unui program (doar ofer o anumit sigurana ,
confiden). In general prin testare putem demonstra c un program nu este corect, gsind un
exemplu de intrri pentru care rezultatele sunt greite.
Metode de testare
Testare exhaustiv
Verificarea programului pentru toate posibilele intrri.
Imposibil de aplicat n practiv, avem nevoie de un numr finit de cazuri de testare.
Nivele de testare
Testele se pot categoriza n funcie de momentul n care se creaz (n cadrul procesului de
dezvoltare) sau n funcie de specificitatea testelor.
Unit testing
Se refer la testarea unei funcionalitai izolate, n general se refer la testarea la nivel de
metode. Se testeaz funciile sau pri ale programului, independent de restul applicaiei
Integration testing
Consider ntreaga aplicaie ca un ntreg. Dup ce toate funciile au fost testate este nevoie de
testarea comportamentului general al programului.
teste automate
scrierea specificaiilor (inv, pre/post, excepii)
implementarea codului
/shutdown) necesare pentru teste
PyUni fixture
agregarea testelor
t test suite
- independena testelor fa de modalitatea de raportare
biblio
import unittest
tec class TestCaseStudentController(unittest.TestCase):
Pytho def setUp(self):
#code executed before every testMethod
n val=StudentValidator()
pentr self.ctr=StudentController(val, StudentRepository())
st = self.ctr.create("1", "Ion", "Adr", 1, "Cluj")
u unit
def tearDown(self):
testin #cleanup code executed after every testMethod
g
def testCreate(self):
modulul self.assertTrue(self.ctr.getNrStudents()==1)
unittest #test for an invalid student
ofer: self.assertRaises(ValidationEx,self.ctr.create,"1", "", "", 1, "Cj")
test
e #test for duplicated id
aut self.assertRaises(DuplicatedIDException,self.ctr.create,"1", "I",
om "A", 1, "j")
ate
mo def testRemove(self):
dali #test for an invalid id
tat self.assertRaises(ValueError,self.ctr.remove,"2")
e
uni self.assertTrue(self.ctr.getNrStudents()==1)
for
m st = self.ctr.remove("1")
de self.assertTrue(self.ctr.getNrStudents()==0)
pre self.assertEquals(st.getId(),"1")
gat self.assertTrue(st.getName()=="Ion")
ire/ self.assertTrue(st.getAdr().getStreet()=="Adr")
cur
aa
re if name == ' main ':
(se unittest.main()
tup
Depa depanare n cercm s identificm cauza erorii, modaliti de rezolvare. Scopul
este sa elminm eroarea.
nare Se pate realiz folosind:
(Debu instructiuni print
gging instrumente specializate oferite de IDE
def factorial(n):
"""
compute the factorial
n is a positive
integer return n!
"""
if n== 0:
return 1
return factorial(n-1)*n
m
e
n
t Recursivitate direct: P apeleaz P
a
r Recursivitate indirect: P apeleaz Q, Q apeleaz P
i
i
f Cum rezolvm probleme folosind recursivitatea:
o
r Definim cazul de baz: soluia cea mai simpl.
m Punctul n care problema devine trivial (unde se
a
t oprete apelul recursiv)
a Pas inductiv: nprim problema ntr-o variant mai
s robleme plus ceva pai simplii
i ex. apel cu n-1, sau doua apeluri recusive cu n/2
m
def recursiveSum(l):
"""
def fibonacci(n):
Compute the sum of
numbers l - list of """
number compute the fibonacci
number n - a positive
return int, the sum of
numbers """ integer
#base case return the fibonacci number for a given
if l==[]: n """
return 0 #base case
#inductive step if n==0 or n==1:
return 1
return l[0]+recursiveSum(l[1:])
#inductive step
p return fibonacci(n-1)+fibonacci(n-2)
l
Obs recursiveSum(l[1:]):
l[1:] - creaz o copie a listei l
a exerciiu: modificai funcia recursiveSum pentru a evita
l l[1:]
a Recursivitate n python:
c la fiecare apel de metod se creaz o noua tabel de
e simboluri (un nou namespace). Aceast tabel conine
l valorile pentru parametrii i pentru variabilele locale
e tabela de simboluri este salvat pe stack, cnd apelul se
a termin tabela se elimin din stiv
def isPalindrome(str):
"""
verify if a string is a
palindrome str - string
return True if the string is a palindrome False otherwise
"""
dict = locals()
print id(dict)
print dict
if len(str)==0 or len(str)==1:
return True
i
Recursivitate
p
Avantaj fiecare recursie se creaz o nou tabel de simboluri
e:
cl Analiza complexitii
ari
tat Analiza complexiti studiul eficienei algoritmilor.
e
co
d Eficiena algoritmilor n raport cu:
m timpul de execuie necesar pentru rularea programului
ai spaiu necesar de memorie
si
m
Timp de execuie, depinde de:
pl
algoritmul folosit
u
datele de intrare
Dezava hardwareul folosit
ntaje: sistemul de operare (apar diferene de la o rulare la alta).
co
ns Exemplu timp de execuie
u def fibonacci(n): def fibonacci2(n):
m """
compute the fibonacci number
"""
compute the fibonacci numb
de n - a positive integer n - a positive integer
return the fibonacci number for a given n return the fibonacci numbe
m """ """
e #base case
if n==0 or n==1:
sum1 = 1
sum2 = 1
m return 1 rez = 0
#inductive step for i in range(2, n+1):
ori return fibonacci(n-1)+fibonacci(n-2) rez = sum1+sum2
sum1 = sum2
e sum2 = rez
m return rez
ai def sw measureFibo(nr):
= StopWatch()
m print "fibonacci2(", nr, ") =", fibonacci2(nr) print
"fibonacci2 take " +str(sw.stop())+" seconds"
ar
sw = StopWatch()
e print "fibonacci(", nr, ") =", fibonacci(nr)
p print "fibonacci take " +str(sw.stop())+" seconds"
e measureFibo(32)
n fibonacci2( 32 ) = 3524578
t fibonacci2 take 0.0 seconds
fibonacci( 32 ) = 3524578 fibonacci
r take 1.7610001564 seconds
u
fiind cantitatea de resurse utilizate de algoritm (timp, memorie).
Eficiena
Msurarea eficienei:
algoritmilor analiz matematic a
E algoritmului - analiz
fi asimptotic Descrie eficiena
c sub forma unei funcii
i matematice. Estimeaza timpul
e de execuie pentru toate intrrile
n pisibile.
o analiz empiric a algoritmului
a
determinarea timpului exact de
a
l execuie pentru date specifice nu
g putem prezice timpul pentru toate
o datele de intrare.
ri
Timpul de execuie pentru un algoritm este studiat n relaie cu
t dimensiunea datelor de intrare.
m Estimm timpul de execuie n funcie de dimensiunea datelor.
il
Realizm o analiz asymptotic. Determinm ordinul de mrime
o
pentru resursa utilizat (timp, memorie), ne intereseaz n special
r
pentru cazurile n care datele de inrare sunt mari
p
o
Complexitate
a
t caz favorabil - datele de intrare care conduc la timp de execuie
minim
e
fi best-case complexity (BC):
d
e
fi
n
it
c
a
BC( A) min E(I )
ID
Fiindc
0 log 2 n n,
n 1 i
n n,
n 1, putem conclude c temenul n3
domin aceast
expre mare r im execuie a algoritmului
sie Ca e pu crete cu ordinul lui
n , ceea se
3
cand ur , l
n este t de scrie sub
ma forma
3
T (n) O(n ) i se citete T(n) este de ordinul n3
dac
T (n)
lim f (n)
n
Observaii.
n3
n , atunci
T (n)
lim 13 . Deci, putem spune c
2 3
n
3 n
T (n) O(n ) .
dac
T (n)
lim f (n)
n
n n0 .
T (n) ( f (n))
dac
T (n)
lim f (n)
n
Observaii.
1. Timpul de execuie al unui algoritm este ( f (n))
3
n dedus i din tul O(n ) i T ).
3
n
Sume
presupunnd c ceea ce este n corpul structurii repetitive (*) se execut n f(i) pai
timpul de execuie al ntregii structuri repetitive poate fi estimat astfel
n
T (n)
f (i)
i 1
Exemple cu sume
Analizai complexitatea ca timp de execuie pentru urmtoarele funcii
def f1(n): n
s = 0 T ni1 1n T nn
for i in range(1,n+1):
s=s+i Complexitate (Overall complexity) n
return s
Cazurile Favorabil/Mediu/Defavorabil sunt identice
def f2(n): n
i = 0 while T ni1 1n T nn
i<=n:
#atomic operation
i = i + 1 Overall complexity n
Cazurile Favorabil/Mediu/Defavorabil sunt identice
def f3(l): Caz favorabil:
"""
l list of numbers primul element e numr par: T n1 1
return True if the list contains
an even nr Caz defavorabil:
""" Nu avem numere pare n list: T nn n
poz = 0
while poz<len(l) and l[poz]%2 !=0: Caz mediu:
poz = poz+1 While poate fi executat 1,2,..n ori (acelai probabilita
return poz<len(l)
Numrul de pai = numrul mediu de iteraii
T n12...n nn12 T n n
Complexitate O n
Exemple cu sume
2n2 2n 2n2
def f4(n): T ni1 1i 1 2ni1
for i in range(1,2*n-2): ji2
for j in range(i+2,2*n):
#some computation 2n2 2n2 2n2
pass T ni1 2n i1 ii1 1
2n2
Overall complexity O n2
Formule cu sume:
1 n
i 1
suma constant.
i 1
i 1
n(n 1)
i 2
n(n 1)(2n 1)
i2 2
ptratic
1
nln(n) O(1)
i
i 1
c
i
i 1
n 1
c 1,
c1
c1
suma armonic
T (n) O(log2 n)
- complexitate logaritmic:
timp foarte bun (este ceea ce cutm, n general, pentru orice algoritm);
log2 1000 complexitate cutare binar,
log2 1.000.000 nlimea unei arbore binar echilibrat
20 ;
k
T (n) O((log n) )
2
- unde k este factor constant; se numete complexitate polilogaritmic
(este destul de bun);
- complexitate liniar;
Complexit
i uzuale
T (n) O(n)
2
T (n) O(n )
- este complexitate ptratic (cuadratic);
dac n este de ordinul milioanelor, nu este prea bun;
k
T (n) O(n )
- unde k este constant; este complexitatea polinomial (este
practic dora daca k nu este prea mare);
n 3
T (n) O(2 ), O(n ), O(n!)
- complexitate exponenial (algoritmii cu astfel de complexiti sunt
practici
n 10, n 20 ).
doar
pentru
valori
mici ale
lui
h 1
N (h) 3 N (0) (1 3
Recurene 3 ... 3 ) 3
2 h 1 i
i 0
h1
Explicaia ar fi urmtoarea:
Numrul de noduri dintr-un arbore ternar complet
de nlime 0 este 1.
Numrul de noduri dintr-un arbore ternar
complet de nlime h se obine ca fiind de 3 ori
numrul de noduri din subarborele de nlime
h-1, la care se mai adaug un nod (rdcina
arborelui).
Dac ar fi s rezolvm recurena, am obine c
numrul de noduri din arborele ternar complet
de nlime h este
Exemple
def recursiveSummemorie necesar algoritmului pentru stocarea datelor de intrare, a
"""
Compute the rezultatelor finale i a rezultatelor intermediare. Se estimeaz, ca i
sum of numbers
l - list of number
return int, timpul
the sumdeofexecuie al unui algoritm, n notaiile
numbers
"""
#base case O , , .
if l==[]:
return
#inductive step
return l[0
Toate obsevaiile referitoare la notaia asimptotic a complexitii
def hanoi(n, x, ca
y,timp
z): de execuie sunt valabile i pentru complexitatea ca spaiu
"""
n -number of disk on the x
stick de memorare.
x - source
y - destination stick z
"""
- intermediate
Exemplu
if n==1:
Analizai complexitatea ca spaiu de memorare pentru
print "disk 1 from"
return
hanoi(n-1, x, z, y)
urmtoarele funcii
print "disk "
hanoi(n-1, z,defy,iterativeSum(l):
x)
"""
Avem nevoie de spaiu pen
Compute the sum of numbers
l - list of number T nn n
return int, the sum of numbers
"""
Comp rez = 0
for nr in l:
lexita rez = rez+nr
return rez
tea
spaiu
def recursiveSum(l):
"""
Compute the sum of numbers
Recuren: T n T n11
0 for
de l - list of number
return int, the sum of numbers
memo """
#base case
rare if l==[]:
return 0
#inductive step
return l[0]+recursiveSum(l[1:])
Compl
exitatea unui Analza complexitii (timp/spaiu)
algoritm din
punct de
pentru o funcie
vedere al 1 Dac exist caz favorabil/defavorabil:
spaiului de descrie Caz favorabil
memorare calculeaz complexitatea pentru Best Case
estimeaz descrie Worst Case
cantitatea de calculeaz complexitatea pentru Worst case
calculea egaliti
z altfel
comple
xitatea calculeaz folosind sume
medie
calculea
Algoritmi de cutare
z
comple datele sunt n memorie, o secven de
xitatea
general nregistrri (k1, k2, ..., kn )
se caut o nregistrare avnd un cmp
2 Dac
Favorabil
egal cu o valoare dat
= cheia de cutare.
Defavorabi
l = Mediu Dac am gsit nregistrarea, se returneaz
(nu avem
cazuri poziia nregistrrii n secven
favorabile/
defavorabil
dac cheile sunt ordonate atunci ne
e) intereseaz poziia n care trebuie inserat
calculea
z
o nregistare nou astfel nct ordinea se
comple menine
xitatea
P
or (p=-1 dac cheia nu
r
exist).
e
c Cutare secvenial cheile nu sunt
o ordonate
n def searchSeq(el,l): def searchSucc(el,l):
""" """
d Search for an element in a list
el - element
Search for an elemen
el - element
l - list of elements l - list of elements
i return the position of the element
or -1 if the element is not in l
return the position
or -1 if the e
""" """
poz = -1
for i in range(0,len(l)):
i = 0
while i<len(l) and el!
if el==l[i]: i=i+1
i poz = i
return poz
if i<len(l):
return i
return -1
i
:
T nn1 1
i0 i: nN, n, and k0 < k1 < .... < kn-1 ;
Rezultate p;
Post-condiii: (p=0 and a k0) or
(p=n and a > kn-1) or
Spec
((0<pn-1) and (kp-1 < a
ifica
ii kp)).
pent
Cutare secvenial chei ordonate
ru
cut def searchSeq(el,l): def searchSucc(el,l):
are """
Search for an element in a list
el - element
"""
Search for an elemen
el - element
chei l - list of ordered elements
return the position of first occurrence
l - list of ordered
return the pos
ordo or the position where the element
can be inserted
occurrence or
the element ca
nate: """
if len(l)==0:
return 0
"""
if len(l)==0:
return 0
poz = -1 if el<=l[0]:
for i in range(0,len(l)): return 0
if el<=l[i]: if el>=l[len(l)-1]:
poz = i return len(l)
if poz==-1: i = 0
return len(l) while i<len(l) and el>
return poz i=i+1
return i
Date
T nn1 1n n Best case: the element is at the f
a,n, i0 T n1
Worst-case: the element is in the
(ki, T nn
i=0, Average case: while can be exec
T n12...n1 n
n-1); Overall complexity O n
PAl
reco go
ndii ri
t
m cesiv toate cheile
i cheile nu sunt ordonate
d cutare binar
e folosete divide and conquer
r h
a
e n
e
l
e
m
e
n
t
i
cutar n
e a
secven l
i
s
ial t
e
se l
ex -
am e
l
e
ine m
e
az n
t
suc t
o
b in which
e we search
return the position of first
s occurrence or the insert position
e """
a if
r l
c e
h f
e t
d >
l =
r
- i
g
a h
t
l -
i 1
s :
t
r
o e
f t
u
o r
r n
d
e r
i
r
g
e
h
d
t
m
e
l =
e
m (
e l
n e
t f
s t
+
l r
e i
f g
t h
, t
r )
i /
g 2
h
t i
f
t
h e
e l
<
s =
u l
b [
l m
i ]
s :
t r
etu
r
n a
b l
i i
n s
a t
r
y e
S l
(
e -
l
, e
l
l e
, m
e
l n
e t
f
t t
, o
m b
)
e
e
s
l
s e
e a
: r
c
retur
h
n
binar e
yS(el d
, l, l - a list of ordered elements
m, return the position of first
right occurrence or the insert position
) """
if len(l)==0:
def r
searchBinaryR e
t
ec(el, l):
u
""" r
S n
e
a 0
r
c i
h f
a e
n l
<
e l
l [
e 0
m ]
e :
n return 0
t if
e
i l
n >
l
[ n
T
l
e
n
(
l
)
-
1
]
:
r
e
t
u
r
n
l
e
n
(
l
)
return
binaryS(e
l, l, 0,
len(l))
Recuren
cutare
binar
if
n
T
(
n
(1), otherwise
Cutare binar (iterativ)
def searchBinaryNonRec(el, l):
"""
Search an element in a
list el - element to be
searched
l - a list of ordered elements
return the position of first occurrence or the position where the element can be
inserted
"""
if len(l)==0:
return 0
if el<=l[0]:
return 0
if el>=l[len(l)-1]:
return len(l)
right=len(l)
left = 0
while right-left>1:
m = (left+right)/2
if el<=l[m]:
right=m
else:
left=m
return right
Complexitate
Timp de execuie
Algoritm best worst case average overall
case
SearchSeq (n) (n) (n) (n)
Vizualizare cautri
- eq
Searching in python- in
l = range(1,10)
found = 4 in l
def add(self,obj):
self.l.append(obj)
def testIn():
container = MyClass2() for i in
range(0,200):
container.add(MyClass(i,"ad")) findObj =
MyClass(20,"asdasd") print findObj in container
search 200 search 100
BinaryRec in 0.000000 sec; poz=200 Binary
Performan - PythIndex in 0.000000 sec; poz=200
PythonIn in 0.000000 sec BinaryNon
PythIn
Pytho
cutare in 0.000000 sec; poz=200 searchSuc
in 0.000000 sec; poz=200
Binary
search
descresctor: if K(i) ,
K(j) for 0 i<j<n
.
Sortare intern
n memorie .
.
,
Dat
k
e n
)
n }
,
K P
; r
e
{ c
K o
= n
( d
k i
1
,
i
i permutare al lui
: K, avnd
elementele sortate,
k k'1 k'2 ... k'n.
i
Sortare prin selecie (Selection
Sort)
R
,
se determin elementul avnd cea mai
i mica cheie, interschimbare elementul
cu elementul de pe prima poziie
=
reluat procedura penru restul de
1 elemente pn cnd toate elementele au
, fost considerate.
K'
e
def selectionSort(l):
"""
sort the element of the
list l - list of element
return the ordered list (l[0]<l[1]<...)
"""
for i in range(0,len(l)-1):
ind = i
#find the smallest element in the rest of the list
for j in range(i+1,len(l)):
if (l[j]<l[ind]):
ind =j
if (i<ind):
#interchange
aux = l[i]
l[i] = l[ind]
l[ind] = aux
Complexitate timp de
execuie
n (n 1)
Overall time complexity: n1 n 1 (n 2 )
i1 j i1 2
Caz defavorabil:
T (n)
i 2
n (n 1)
(n ) 2
2
(i 1)
nu rul maxim de iteraii cnd lista este ordonat
Avem m descresctor
Caz mediu:
2
n 3 n n
1
(n )
2
4 i 1 i
Pentru un i fixat i un k,
1ki, probabilitatea ca xi
i
s fie al k-lea cel mai mare
element n
x1 , x 2 ,..., xi
subsecvena
este 1
un i i 2 i
Astfel, pentru i fixat, i
putem deduce: fix
(i
at
est 1
Numarul de )
e:
iteraii while numrul2de iteraii
c
1 i
1
1
2 1
1
2
... 1
i
... i
i-1
i
(i
Rezult c numrul de 2)
iteraii while medii pentru
Caz favorabil:
T (n) 1 n 1 (n)
i 2
(1) .
Sortare prin inserie este un
algoritm in-place.
n (n 1)
Overall time complexity: n1 n 1 (n 2 )
i1 j i1 2
se parcurg elementele
Caz mediu
(n 2 ) .
este un algoritm
de sortare in-place .
QuickSort
Quick-Sort
def partition(l,left,right):
"""
Split the values:
smaller pivot greater return pivot position
post: left we have < pivot right we have > pivot
"""
pivot = l[left] i = left
j = right while i!=j:
while l[j]>=pivot and i<j: j = j-1
l[i] = l[j]
while l[i]<=pivot and i<j: i = i+1
l[j] = l[i] l[i] = pivot return i
def quickSortRec(l,left,right):
Complexitatea este
partiie cu n-1 elemente
QuickSort T (n) T (1) T (n 1) (n) T (n
Caz favorabil 1) (n) (k) (n ) .
2
k 1
singur element i o
(n log 2 n) (notm cu L )
caz defavorabil (unlucky) cu (n 2 ) (notm cu U ).
complexitatea
Avem recurena:
n
L lucky case
)
U
(n
2
U (n) L(n 1) (n)
unlucky case
Rezult
n
L(n
L ( log
1 L
Coplexitatea ca
timp de
execuie pentru
sortri: Algorithm worst-c
SelectionSort (n 2
rezult din operaii asupra unor elemente dintr-o
alt secven
paranteze drepte coninnd o expresie urmat de o
clauz for , apoi zero sau mai multe clauze for sau
if
Python -
Python Parametrii optionali parametrii cu
nume
Quick-Sort
def qsort(list):
def f(a=7,b = [],c="adsdsa"):
"""
Quicksort using list comprehensions
"""
if list == []:
return []
else:
pivot = list[0]
lesser = qsort([x for x in list[1:] if x < pivot])
greater = qsort([x for x in list[1:] if x >= pivot])
return lesser + [pivot] + greater
Putem avea parametrii cu valori default;
rez = []
for x in l[1:]:
if x<pivot:
rez.append(x)
Interclasare
(Merging)
technic
Technici de programare
Divide and conquer
Metoda divizrii -
strategii de rezolvare a pai
problemelor mai dificile
algoritmi generali Pas 1 Divide -
pentru
rezolvarea se mparte
unor problema n
tipuri de probleme mai
probleme mici (de acelai
de multe ori o problem structur)
mprirea problemei n
se poate rezolva cu mai dou sau mai multe
multe technici se alege probleme disjuncte care
se poate rezolva
metoda mai eficient folosind acelai algoritm
algoritm general
def divideAndConquer(data):
if size(data)<a:
#solve the problem directly
#base case
return rez
#decompose data into d1,d2,..,dk
rez_1 = divideAndConquer(d1)
rez_2 = divideAndConquer(d2)
...
rez_k = divideAndConquer(dk)
#combine the results
return combine(rez_1,rez_2,...,rez_k)
T n
T n11
T n1 T
n21 T => T n11...1n n
n2 T
n31
... ...
T 2 T 1
2 k 2 3 k 3 2
2 T2 2 T 2 2 =>
Divizare n date de ... ...
def findMax(l):
"""
find the greatest element in the
list l list of elements
return
max """
if len(l)==1:
#base case
return l[0]
#divide into 2 of size n/2
mid = len(l) /2
max1 = findMax(l[:mid])
max2 = findMax(l[mid:])
#combine the results
if max1<max2:
return max2
return max1
2k1T 2 2k T 12
dimensiune n/k
Complexitate ca timp:
Recurena:T
1
n
2
otherwise
k
2 T 2k11 2 T 2k1 22 T 2k22
Notm: n2k
=> k log2 n
T n12k1 1
22. ..2k2k11212k 212 n1n
Rezolvare cu metoda divizrii:
k
x x
k2
xk
2
fo
r
k
ev
en
x
k
2
x
k
2
x
f
o
r
k
o
d
d
Backtracking
se aplic la probleme de cutare unde se caut mai multe soluii
genereaz toate soluiile (dac sunt mai multe) pentru problem
caut sistematic prin toate variantele de soluii posibile
este o metod sistematic de a itera toate posibilele configuraii n spaiu de
cutare
este o technic general trebuie adaptat pentru fiecare problem n
parte.
Dezavantaj are timp de execuie exponenial
x 1 2 2 3 1 2 3 1 2 3
1 2 3 1 2 3 1 x2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1
3
Probleme:
Numrul total de liste generate este 33, n cazul general nn
iniial se genereaz toate componentele listei, apoi se verifica dac lista este o
permutare in unele cazul nu era nevoie sa continum generarea (ex. Lista ce
incepe cu 1,1 sigur nu conduce la o permutare
Nu este general. Funcioneaz doar pentru n=3
nbuntiri posibile
1 2 3 1 2
x
3 2 1 2 3
1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 x 1 2 3 1 2 3 1
3
generate([],3)
Testare se
tiprete doar
soluia
def generateAndTest(x,DIM): [0, 1, 2] Rezultat: 8 poziii de
if len(x)==DIM and isSet(x): [0, 2, regine
1] pe tabl
print x [1, 0, 2]
if len(x)>DIM: [1, 2, 0] Un rezultat partial e valid:
return [2, 0, 1]
x.append(0) [2,
dac nu exist regine care se
1, 0]
for i in range(0,DIM): atac
x[-1] = i
generateAndTest(x[:],DIM) nu e pe aceli coloana,
generateAndTest([],3) linieor sau diagonal
Numrul total de posibile
n continuare se genereaza toate listele ex: poziii (att valide ct i
invalide):
liste care ncep cu 0,0
combinri de 64
ar trebui sa nu mai generm dac conine luate cte 8, C(64,
duplicate Ex (0,0) aceste liste cu siguran 8) 4.5 109)
nu conduc la rezultat la o permutare Genereaz i testeaz nu
rezolv problma n timp
rezonabil
Reducem spatiu de cutare nu generm chiar
toate listele posibile
def backRec(x):
x.append(0) #add a new component to the candidate solution
for i in range(0,DIM):
x[-1] = i #set current component
if consistent(x):
if solution(x):
solutionFound(x)
backRec(x[:]) #recursive invocation to deal with next components
def solution(x):
"""
The candidate x is a solution if
we have all the elements in the
permutation """
return len(x)==DIM
pe parcurs
folosit n multe probleme practice
care necesite selecia unei mulimi Avnd un set de
obiecte C candidai
de elemente care satisfac anumite
pentru a face parte din
condiii i realizeaz un optim
soluie, se cere s se
Probleme gseasc un subset B (B
C) care indeplinete
Problema rucsacului anumite condiii (condiii
interne ) i maximizeaz
Se d un set de obiecte, caracterizate prin (minimizeaz) o funcie
greutate i utilitate, i un rucsac care are de obiectiv.
capacitatea totala
W. Se caut o submultime de obiecte astfel
nct greutatea total este mai mic dect W i Dac un subset X
suma utilitii obiectelor este maximal. ndeplinete
condiiile interne
atunci subsetul X este
Monede acceptabil (posibil)
Unele probleme pot
def greedy(c):
Principiu (strategia) Greedy : """
adaug succesiv la rezultat elementul Greedy
care realizeaz optimul local algorithm
c - a list of
o decizie luat pe parcurs nu se mai candidates
return a
modific ulterior list (B) the
Algoritmul Greedy solution found (if
exists) using the
greedy strategy,
Poate furniza soluia optim (doar pentru None if the
anumite probleme) algorithm
selectMostP
alegerea optimului local nu garanteaza romissing - a
tot timpul optimul global function that
return the most
solutie optim - dac se gsete o promising
modalitate de a alege (optimul candidate
local) astfel ncat se ajunge la acceptable -
a function that
solutie optim
returns True if a candidate t
solution can be extended to a h
solution e
solution - verify if a given
candidate is a solution b
""" e
b = [] s
#start t
with an
empty set c
as a a
candidate n
solution d
while not i
solution( d
b) and c! a
=[]: t
# e
s )
e
l c
e a
c n
t d
i
t d
h a
e t
e
l
o =
c
a s
l e
l
o e
p c
t t
i M
m o
u s
m t
P
( r
o e
m m
i o
s v
s e
i (
n c
g a
( n
c d
) i
# d
r a
e t
m e
o )
v #
e i
f
t
h t
e h
e
c
u n
r e
r w
e
n e
t x
t
c e
a n
n d
d e
i d
d
a c
t a
e n
d
c i
. d
r a
te o
solution
is s
acceptab o
le if l
acceptab u
le(b+ t
[candida i
te]): o
b.append(candidate) n
if r
s e
o t
l u
u r
t n
i
o N
n o
( n
b e
)
: Algoritm Greedy
r
- elemente
e
t
u 1. Mulimea
r candidat
n (candidate set)
de unde se aleg
b elementele soluiei
#
t 2. Funcie de
h selecie
e
r (selection
e function)
i alege cel
s mai bun
n
candidat
pentru a fi adugat la soluie; d
3. Acceptabil (feasibility function) e
folosit pentru a determina dac un
candidat poate contribui la soluie -
4. Funcie obiectiv ( objective function)
o valoare pentru soluie i pentru C
orice soluie parial O
5. Soluie (solution function), - indic I
dac am ajuns la soluie N
S
Exemplu
=
Se da o sum M i tipuri (ex: 1, 5,
25) de monede (avem un numar nelimitat {
1
de monede din fiecare tip de moned). S ,
se gseasc o modalitate de a plti suma
M de bani folosind ct mai puine 5
monezi. ,
Set Candidat: 2
L 5
i ,
s
t 5
a 0
}
d
e S
o
m l
o u
n
e
i candidat este egal
e cu suma cerut
Monede cod
C
a
python
n
d #Let us consider that we have a sum M
i #The problem is to establish a modalit
def selectMostPromissing(c):
d """
select the largest coin from the
a c - candidate coins
t return a coin
"""
: return max(c)
def solution(b):
o list de monede - X X 0, X 1,. . , X k
"""
unde verify if a candidate solution is a
basically verify if the coins condu
X i COINS b candidate solution
"""
moned sum = _computeSum(b)
return sum==SUM
def _computeSum(b):
Funcia de selecie: """
candidate solution: X X X . , X
0, 1,. k
compute the payed amount with the c
return int, the payment
alege moneda cea mai mare care e b candidate solution
"""
mai mic dect ce mai e de pltit sum = 0
for coin in b:
din sum nrCoins = (SUM-sum) / coin
#if this is in a candidate sol
use at least 1 coin
if nrCoins==0: nrCoins =1
Acceptabil (feasibility function):
k sum += nrCoins*coin
Soluie candidat: X X X . , X S
0, 1,. k
return sum
X M
i0 i
Greedy
suma monedelor din soluia
candidat nu depete suma cerut
1. Algoritmul Greedy are
Soluie: k
complexitate
Soluie candidat: X X X . , X
0, 1,. k S polinomial - candidat
X M
i0 i C
suma monedelor din soluia
2
O(n )
unde n este numrul de
elemente din lista
2. nainte de a aplica Greedy este n probleme pentru care
nevoie s demonstrm c metoda e Greedy nu gsete soluia
gsete soluia optim. De multe o optim. n unele cazuri se
ori demonstraia este netrivial ri prefer o soluie obinut n
3. Exist o mulime de probleme ce e timp rezonabil
se pot rezolva cu greedy. Ex: nt (polinomial) care e aprope
Algoritmul Kruskal at de soluia optim, n loc de
determinarea arborelui de4. Ex soluia optim obinut n
acoperire, Dijkstra, Bellman- is timp exponenial
Kalaba drum minim ntrun graf t (heuristics algorithms).
Programare Dinamic
Fie stritle s0, s1, ..., sn-1, sn, unde s0 este starea iniial, sn este starea
final, prin aplicariea succesiv a deciziilor d1, d2, ..., dn se ajunge la starea
final (decizia di duce din starea si-1 n starea si, pentru i=1,n):
d1 d2
s0 s1 s2
Programare Dinamic
Caracteristici:
principiul optimalitii;
probleme suprapuse (overlapping sub problems);
memoization.
Principiul optimalitii
optimul general implic optimul parial
la greedy aveam optimul local implic optimul global
Principiul optimalitii
Dac
d1 , d 2 ,..., d n
2
,
.
.
.
,
d
k
s0 n
st sk , k, 1 k n . (backward variant)
a
r
e
a
3). d i d1 , d 2 ,..., d k
k
1
,
d
k
2
,.
..
,
d
n
sunt s ecvene optime de decizii care conduc sistemul din
st s n , n starea
k
a starea respecti
r s v, din
n
e starea
a s0
sk , k, 1 k n . (mixed variant)
suprapuse problema are sub- mai o (Memorization)
(Overlapp probleme multe ri salvarea rezultatelor de
ing Sub- suprapuse daca ori z la o subproblem
Sub-
problems) poate fi inprit n a pentru a fi refolosit
Proble
O subprobleme care r
me Mem e
se refolosesc de
Cum aplicm programare dinamic
se calculeaz
in manier bottom-up, ncepem cu subproblema cea mai
simpl p entru care soluia este cunoscut.
Cea mai lung sublist cresctoare
Se d o list
Soluie:
a1 , a2 ,..., an . Determinai cea mai lung sublist cresctoare
a , a ,..., a i
i1 2 s
a listei date.
Pricip alitii T
iul varianta nainte forward h structu
optim e re of
the optimal solution
Construim dou iruri:
l l1 .l2 ,...ln i
p p1. p2 ,... pn .
lk ak .
lungime
sublistei
care
incepe
cu
elementu
l
p
k
indexul elementului a care dup
urmeaz
element n sublista cea mai lung care
ul ak
in pe cu ak . D fi ia recursiv
ce e ni ln 1, pn 0
lk
max{1 li | ai ak , k 1 i n},
k n 1, n 2,...1
pk
arg max{1 li | ai ak , k n 1, n 2,...,1
k 1 i n},
Ce
a
ma
i
lun
g
su
bli
st
cre
sc
toa
re
pyt
ho
n
def longestSublist(a):
"""
Determines the longest
increasing sub-list a - a list
of element
return sublist of x, the longest increasing sublist
"""
#initial
ise l
and p l
=
[0]*len(
a)
p = [0]*len(a)
l[lg-1] = 1
p[lg-1]=-1
for k in range(lg-
2, -1, -1):
print p, l
p[k] = -1
l[k]=1
for i in range(k+1, lg):
if a[i]>=a[k] and
l[k]<l[i]+1:
l[k] = l[i]+1
p[k] = i