Introducere în limbajul Python

Python este un limbaj de scripting de nivel înalt. Vom prezenta în continuare primii pași care trebuie făcuți pentru a scrie un program Python, câteva exemple și unele sfaturi care să va ajute în depășirea problemelor de inceput.

Ce este Python?

Python este un limbaj de programare care caștigă tot mai multă popularitate, oferind posibilitatea programarii structurale dar și orientate pe obiecte și incluzând și elemente din paradigma funcțională. Este un limbaj de scripting, ceea ce înseamnă ca este interpretat și nu compilat, economisind mult timp în procesul de dezvoltare și depanare.

Limbajul combină o putere remarcabilă cu o sintaxă foarte clară. Are module, clase, excepții, tipuri dinamice și garbage collector. API-ul Python oferă module pentru o gamă foarte largă de funcționalități, de la cele de bază pentru lucruri cu șiruri și fișiere, până la cele pentru lucrul cu procese, threaduri, sockets, serializare etc. Multe din aceste module oferă o interfață foarte similară programării la nivel de sistem din C (ceea ce se studiază la SO), astfel încât funcțiile Python au același nume si aproximativ aceiași parametrii ca cele pentru funcțiile din C pentru apeluri de sistem. Există o varietate de API-uri și pentru aplicații cu GUI, cum ar fi PyQT , PyGTK, wxWidgets. Pentru calcul numeric există bibliotecile NumPy, SciPy și Matplotlib.

Implementarea principală a Python, CPython (scrisă în C) a fost concepută pentru a fi portabilă: funcționează pe Linux, Unix, Windows, Mac OS X, si chiar pe unele telefoane mobile de la Nokia (Symbian). Pe platformele mobile actuale există implementări pentru iOS iar Android oferă SL4A, o platformă pentru limbaje de scripting cu suport și pentru Python.
Programele pot fi executate, de asemenea, și pe mașina virtuală Java prin folosirea compilatorului Jython, care le transformă în bytecode Java și permite și folosirea de clase Java în cadrul acestora. Similar, există IronPython pentru .NET.

De ce Python?

Python este un limbaj ce oferă foarte multe funcționalități și are o curbă de învățare rapidă atât pentru programatorii ce cunosc deja limbaje precum C si Java, cât și pentru începători. Deși este un limbaj interpretat, acest lucru nu a stat în calea popularității sale și folosirii în numeroase proiecte. Pentru proiecte open-source puteți consulta statistici pe site-ul http://www.ohloh.net/languages/python, și compara evoluția contribuțiilor în proiecte cu cod Python față de proiecte în alte limbaje de programare, ca exemplul de pe acest link.

Puteți utiliza Python atât pentru scripturi, dezvoltarea unor infrastructuri de testare cât și pentru aplicații web folosind framework-uri cum ar fi Django. Există aplicații desktop variind de la clienți BitTorrent până la unele jocuri video, iar multe produse software conțin și componente scrise în Python, așa cum este cazul Instagram ( detalii aici). Statistici legate de site-uri ce folosesc Python găsiți aici, iar o listă a aplicațiilor ce folosesc Python găsiți aici.

Instalare

:!: În cadrul laboratoarelor vom lucra doar cu Python 2.6 si 2.7, nu și cu versiunile >= 3. Python nu oferă backwards compatibility astfel încât programe scrise pentru o versiune pot să genereze erori de interpretare pe o altă versiune (de exemplu tratarea excepțiilor în versiuni >= 2.6 are altă sintaxă decât în 2.4). De asemenea, Python3 este incompatibil cu versiunile 2.x, mai multe detalii găsiți aici.

Python se poate descărca de pe site-ul oficial, secțiunea Download.

Pe un sistem Linux, e posibil să fie deja instalat. Verificați acest lucru dintr-o consolă:

  1. $ python
  2. Python 2.6.6 (r266:84292, Sep 15 2010, 15:52:39)
  3. [GCC 4.4.5] on linux2
  4. Type "help", "copyright", "credits" or "license" for more information.
  5. >>>

Daca nu îl aveți instalat, pasul urmator ar fi să-l căutați în repository-urile distribuției cu care lucrați. Exemplele următoare prezintă instalarea pe o distribuție bazată pe Debian și pe una bazată pe Red Hat.

  1. $ sudo apt-get install python
  1. $ sudo yum install python

Python poate fi și descarcat, apoi compilat și instalat manual:

  1. ./configure
  2. make
  3. make install

Pe un system Windows se poate descărca de la Download versiunea curentă 2.7.3. După instalare se poate adăuga calea către executabilul Python în global PATH, pentru a putea fi gasit de oriunde.

Cum se execută un program Python

În Windows, dacă extensia .py este deja înregistrată, un dublu-click pe numele scriptului este suficient. Se poate edita programul folosind GUI-uri ca IDLE (Python GUI) și Eclipse sau editat în notepad++ și executat din consolă (Start→Run→cmd).

Daca folosiți Linux, există mai multe posibilități:

  • fie se lansează interpretorul cu numele scriptului:
  1. $ cat hello.py
  2. print 'Hello World!'
  3. $ python hello.py
  4. Hello World!
  • fie prima linie din program este de forma #!/calea/catre/interpretor iar scriptul se face executabil:
  1. $ cat hello.py
  2. #!/usr/bin/python
  3. print 'Hello World!'
  4. $ chmod +x hello.py
  5. $ ./hello.py
  6. Hello World!

Pentru a testa anumite funcționalități sau a verifica o anumită sintaxă nici nu este nevoie să scrieți un script, puteți folosi direct consola Python. Din ea se iese scriind quit() sau Ctrl-D.

  1. $python
  2. Python 2.6.6 (r266:84292, Sep 15 2010, 15:52:39)
  3. [GCC 4.4.5] on linux2
  4. Type "help", "copyright", "credits" or "license" for more information.
  5. >>> print "hello"
  6. hello
  7. >>> import io
  8. >>> help(open)

Din consolă puteți obține documentația despre anumite module, clase, metode folosind help(nume), inclusiv despre modulele si metodele scrise de voi dacă includeți în cod comentarii docstring (similare javadoc-ului din Java). Alternativ, dacă doriți să vedeți metodele disponibile pentru un anumit obiect puteți folosi funcția dir(obiect), ca în exemplele de aici.

Particularități de sintaxă

  • Indentarea - în Python este mai mult decat parte a stilului de programare, este chiar parte din sintaxă (indentarea se referă la spațiile/distanța între începutul unui rand și primul cuvant)
    • o linie nouă termină o declarație, pentru a continua o declarație pe mai multe linii, se foloseste caracterul “\”.
    • un bloc de cod are toate liniile indentate cu același număr de spații (nu există begin și end sau {}). Instructiunile dintr-un bloc de cod vor fi grupate unele sub altele, pe același nivel de indentare.
    • definițiile neindentate într-un program Python vor fi de obicei variabile globale, definiții de clase, proceduri, funcții sau părți ale “programului principal”.
    • dupa instrucțiuni nu se pune simbolul ';' precum în alte limbaje de programare, indentarea corespunzatoare fiind suficientă.
    • este foarte important sa nu uitați simbolul ':' care precede o indentare, deoarece omiterea sa poate să fie cauza multor erori, cel puțin la început.
  • Comentarii
    • o singură linie se poate comenta în Python folosind simbolul #.
    • pentru comentarii multiline se folosesc trei ghilimele succesive """ sau ''' la inceputul și respectiv la sfârșitul zonei de comentat.
  • Code style - pe site-ul oficial găsiți recomandările de code style, scrise chiar de creatorul limbajului, Guido van Rossum.

:!: Structurile de control, definirea de rutine, clase, toate necesită o mai mare grijă în scrierea codului. Exemplu de folosire a indentării pentru a delimita blocurile de cod:

  1. a = 1
  2. """
  3. Afisam numerele de la 1 la 10
  4. """
  5. while a <= 10:
  6. print a,
  7. a += 1
  8. #b = 1
  9. b = 2
  10. print "Am terminat"

Tipuri de date și variabile

Python oferă tipuri de date numerice, booleene, șiruri (string, liste etc), dicționare, fișiere, clase, instanțe și excepții.

Din punct de vedere al tipării Python folosește tipuri pentru obiecte, însă numele de variabile nu au tip, adică la definirea variabilelor nu trebuie precizat tipul acestora. Constrângerile de tip sunt verificate la execuție, astfel încât pot apărea erori si excepții generate de folosirea unui tip necorespunzător în atribuiri și excepții.

Python asociază numele unei variabile cu un obiect, care poate fi număr, șir de caractere sau ceva mai complex. Când este folosită o variabilă, tipul acesteia este tipul obiectului cu care este asociată. Este greșită folosirea intr-o expresie a unei variabile care nu a fost asociată cu un obiect.

Astfel, dacă se scrie:

  1. i = 5

i va fi de tip Integer. Dacă se scrie:

  1. i = "Hello"

i va fi de tip String.

Alocarea și dealocarea de memorie se face automat de către Python, existând un mecanism de garbage collection.

În Python se poate face atribuirea de valori unor mai multe variabile simultan:

  1. x, y = 2, 3

Datorita faptului că partea dreapta a unei expresii este evaluată înainte de a se face atribuirea, valorile celei de-a doua variabile pot fi foarte usor interschimbate, făra a avea nevoie de o a treia variabilă:

  1. x, y = y, x

Tipuri de date numerice

În Python se poate lucra cu numere intregi și numere în virgulă mobilă. Numerele întregi dintr-o expresie se convertesc automat în numere in virgula mobilă dacă este necesar. Cele patru tipuri numerice int, long, float ;i complex și operațiile acestora sunt descrise în API.

Deoarece Python este strongly typed, nu se face conversie automată între tipurile de date dintr-o expresie, cum ar fi operațiile între tipurile String și Integer. Pentru acest lucru se folosesc funcțiile int(some_string) pentru transformarea din string în integer și respectiv: str(some_int) sau repr(some_int) sau `some_int` (` - backquote) pentru transformarea din integer în string. Se poate folosi și scrierea formatată folosind structura '[string]%type[string]' % (var_name). Exemplul de mai jos ilustrează folosirea acestor conversii.

  1. i = "1"
  2. j = "2"
  3. a = 1
  4. b = 2
  5. print "Un string:", i+j
  6. print "Un numar:", int(i)+int(j)
  7. print "Un string", str(a)+str(b)
  8. print "Afisare formatata:", 'persoana %s are %d ani' % (j, a)

va afișa:

  1. Un string: 12
  2. Un numar: 3
  3. Un string 12
  4. Afisare formatata: persoana 2 are 1 ani

Atenție! În cazul transformării din string în integer, dacă stringul ce trebuie convertit conține și alte caractere decât cifre, la execuție va apărea o eroare: Value Error: invalid literal for int() with base 10.

În Python se poate lucra direct cu numere complexe, folosind sintaxa: a+bj unde a = partea reală și b = partea imaginară, ca în exemplul de mai jos.

  1. >>> print (2.0+3.0j)*(2.1-6.0j)
  2. (22.2-5.7j)

În Python, se folosesc simbolurile aritmetice standard, cu % pentru operația modulo.

Stringuri

Pentru lucrul cu șiruri de caractere, Python oferă tipul String și o serie de operații de bază pe acestea, descrise în documentație, iar pentru lucruri mai specifice, cum ar fi căutarea sau separarea unor substringuri poate fi folosit și modulul //re// - regular expressions .

Stringurile sunt incluse între ghilimele " sau '. Stringurile ce conțin mai multe linii sunt înconjurate de trei ghilimele succesive """ sau '''.

  1. s = "string pe o linie"
  2. linie = """string
  3. pe mai multe linii"""

Stringurile sunt tratate ca liste, cuvant[i] fiind caracterul din șir ce are indexul i unde i ia valori în intervalul [-length,length). Folosirea unei valori în afara acestui interval va genera o eroare: IndexError: string index out of range.

Nu exista un tip de date special pentru caractere, acestea sunt văzute drept șiruri de lungime 1. Lungimea unui string se poate afla cu ajutorul functiei: len(some_string).

stringul:         s   t   r   i   n   g
index:            0   1   2   3   4   5
index negativ:   -6  -5  -4  -3  -2  -1 

Caracterul : specifica un subșir al unui sir folosind sintaxa: some_string[x:y]. Subșirul obținut conține toate caracterele din șirul inițial (some_string) între pozițiile x si y-1 (inclusiv). Dacă nu se specifică x sau y, acestea au implicit valorile 0, respectiv lungimea șirului.

NU se pot modifica caracterele unui șir folosind adresarea cu indici în atribuire:

  1. >>> s="abcdef"
  2. >>> s[0]="g"
  3. Traceback (most recent call last):
  4. File "<stdin>", line 1, in <module>
  5. TypeError: 'str' object does not support item assignment

Șirurile de caractere pot fi concatenate folosind simbolul + si pot fi multiplicate folosind caracterul *. De exemplu, execuția instructiunilor:

  1. s = "string"
  2. print s[0:2]
  3. print s[:3]
  4. print s[3:]
  5. s2 = "one"
  6. print "Write " + 2*s2 + " " + s

va afișa:

  1. st
  2. str
  3. ing
  4. Write oneone string

Liste și Tupluri

Python pune la dispoziție două tipuri de structuri pentru a grupa mai multe elemente: tupluri și liste. Diferența principală dintre cele două tipuri este că tuplul nu mai poate fi modificat dupa ce a fost declarat (este immutable).

Lista se declară folosind paranteze drepte: [].

Tuplul se declară folosind paranteze rotunde: ().

Elementele unei liste sau ale unui tuplu pot fi de tipuri diferite.

  1. lista = ["string", 10]
  2. tuplu = ("string", 10)

Operații utile (lista completă a operațiilor și funcțiilor pentru tipuri de secvență o găsiți în documentație):

  • len(lista) - întoarce numarul de elemente din listă
  • lista.append(x) - adaugă un element la sfarșitul listei
  • lista.extend(alta_lista) - concateneaza alta_lista la lista
  • lista.sort() - sortează elementele listei
  • lista.reverse() - inversează ordinea elementelor din listă
  • afisarea unei liste se poate face folosind un simplu print lista.

Accesarea elementelor unei liste sau unui tuplu se face la fel ca în cazul șirurilor de caractere, cu indecși pozitivi, negativi sau folosind operatorul :. Spre deosebire de stringuri, elementele unei liste pot fi modificate cu ajutorul accesarii prin indecși.

Putem referi o sublistă a unei liste, ajutându-ne de doi indecși:

  1. sublista = lista[index1:index2]

Indexarea se face de la zero. Mai sus, se vor întoarce elementele listei inițiale de la index1 la index2-1. Astfel, lista[n:(n+1)] va întoarce o listă care conține un singur element, cel de pe poziția n, iar lista[n:n] va intoarce [].

  1. alta_lista = [1,2,3,4]
  2. lista = []
  3. lista.append(5)
  4. lista.extend(alta_lista)
  5. del lista[2]
  6. del lista[0:2]

Elementele unui tuplu nu mai pot fi modificate după ce au fost declarate. Din acest motiv nicio funcție prezentată mai sus ce modifică elementele unei liste nu poate fi aplicată asupra tuplurilor. Exemplul de mai jos ilustrează faptul că listele pot fi modificate și sunt mutable, iar tuplurile immutable.

  1. >>> a = [1,2,3]
  2. >>> b = a
  3. >>> b[1] = 5
  4. >>> b
  5. [1, 5, 3]
  6. >>> a
  7. [1, 5, 3]
  8. >>> t = (1,2,3)
  9. Traceback (most recent call last):
  10. File "<stdin>", line 1, in <module>
  11. TypeError: 'tuple' object does not support item assignment

List comprehensions

O nouă listă poate fi creată din altă lista folosind “list comprehensions”: o expresie urmată de o clauza for, apoi de 0 sau mai multe clauze for sau if. De exemplu, execuția instrucțiunilor:
  1. >>> print (2.0+3.0j)*(2.1-6.0j)
  2. (22.2-5.7j)
  3. >>> lista_veche = [1,2,3,4]
  4. >>> lista = [ elem*2 for elem in lista_veche if elem!= 3]
  5. >>> print lista
  6. [2, 4, 8]
  7. >>> print [(x, x**2) for x in lista_veche]
  8. [(1, 1), (2, 4), (3, 9), (4, 16)]

În expresia de mai sus, if este opțional.

Dicționare

O structură dicționar este un set neordonat de chei și valori în care valoarea poate fi cautată folosindu-se cheia. Cheile sunt obiecte hashable, ceea ce presupune că au o funcție hash ce întoarce întotdeauna aceeași valore unică pentru obiectul respectiv, deci oricare două obiecte diferite au valori hash diferite. Ordinea în care se stochează este arbitrară, iar cheile pot să fie de tipuri diferite, de obicei cele mai folosite sunt numerele întregi sau stringurile. Atenție! listele, dicționarele și alte tipuri de date mutable nu sunt hashable, deci folosirea lor drept chei nu este indicată.

  1. dict[0] = "primul"
  2. dict["unu"] = 2

Pentru a accesa un element al unui dicționar se procedează în felul urmator:

  1. var1 = dict[0]
  2. var2 = dict["unu"]

Dicționarele sunt declarate folosind acolade, elementele sunt de forma cheie:valoare, despărțite de virgule.

  1. dict = {0: "primul" , "unu":2}

Câteva operații utile (lista completă o găsiți în documentație):

  • len(some_dict) - pentru a afla dimensiunea unui dicționar
  • del some_dict[cheie] - pentru a șterge o intrare din dicționar
  • operatorul in - pentru a afla dacă o cheie este în dicționar. Similar se poate folosi funcția has_key(cheie)
  • keys() - întoarce o listă ce conține toate cheile din dicționar
  1. >>> d = {1:"val1", 2:"val2"}
  2. >>> len(d)
  3. 2
  4. >>> d.has_key(1)
  5. True
  6. >>> d.has_key("5")
  7. False
  8. >>> 2 in d
  9. True
  10. >>> del d[1]
  11. >>> if 2 in d: d["3"] = 2
  12. ...
  13. >>> d
  14. {2: 'val2', '3': 2}

Structuri condiționale

  1. if conditie1:
  2. instructiuni
  3. elif conditie2:
  4. instructiuni
  5. else:
  6. instructiuni

Pot exista mai multe secțiuni elif sau nici una, iar secțiunea else apare o dată sau niciodată.

Numarul 0, liste și tupluri goale, stringuri vide și valoarea None sunt considerate False daca sunt folosite în evaluarea unei condiții.

Structuri repetitive

Instrucțiunea ''for''

Instrucțiunea for iterează după elementele unei secvențe, fie ea String, list sau tuple.
  1. for el in lista:
  2. instrutiuni

Funcția range() construiește o lista cu elemente în progresie aritmetică. Are urmatoarea sintaxă: range(x[,y[,pas]]) - formează o listă cu elemente mai mici ca y în progresie aritmetică, cu rația pas. Primul element al listei este x. Implicit x este 0 si rația este 1.

  1. for i in range(len(s)):
  2. print s[i]

Instrucțiunea ''while''

Instrucțiunea while continuă iterația cât timp condiția specificată este adevarată.
  1. while conditie:
  2. instructiuni

Instrucțiunea break termină forțat orice bucla while sau for, iar instrucțiunea continue sare la următoarea iterație.

:!: Instructiunile while si for pot avea o clauză else. Aceasta se execută când se termină lista după care se face iterația for sau atunci când condiția while a devenit false. Instrucțiunile din clauza else nu se execută în cazul în care bucla este terminată printr-o instrucțiune break.

  1. while conditie:
  2. instructiuni
  3. else:
  4. instructiuni

Funcții

Funcțiile sunt definite folosind cuvantul def, ca în exemplul următor:

  1. def fractie(x,y):
  2. if (y==0):
  3. return
  4. else:
  5. return float(x)/float( y)
  6.  
  7. print fractie(6,4)

Se specifică doar numele argumentelor, tipul lor fiind cel trimis la apelarea funcției.

Funcțiile care se termină fară să folosească instrucțiunea return sau care execută return fară argumente, întorc o valoare None.

Se pot specifica valori implicite pentru parametrii unei funcții.

  1. def fractie(x, y=1):
  2. corpul functiei

La apelare se pot specifica două valori sau doar una. Dacă funcția se apelează cu doua valori nu se ține cont de valoarea implicită a lui y, dacă se apelează cu o valoare (de ex fractie(4)), x va lua valoarea 4, iar y valoarea implicită 1.

Funcțiile mai pot fi apelate folosind cuvinte cheie de forma: cuvant_cheie = valoare. Pentru exemplul de mai sus se poate mai apela funcția și astfel:

  1. fractie(y=7, x=5)
  2. fractie(6,y=1)

Dacă o functie are un parametru de tipul *lista, atunci la apelare funcția va primi un tuplu de argumente. Execuția instrucțiunilor:

  1. def suma(*lista):
  2. s=0
  3. for i in lista:
  4. s=s+i
  5. return s
  6.  
  7. print suma(2,3,5)

va afișa:

  1. 10 # adica 2+3+5

Dacă o funcție are un parametru de tipul **nume, atunci la apelare functia va primi o listă de cuvinte cheie de forma cuv_cheie=valoare. Execuția instrucțiunilor:

  1. def afisare(**nume):
  2. for i in nume.keys():
  3. print i,':',nume[i]
  4.  
  5. afisare(client="Alex", vanzator="Alina")

va afișa:

  1. client : Alex
  2. vanzator : Alina

Pentru a accesa variabilele globale ale programului, trebuie să folosim cuvantul-cheie global cu sintaxa: global some_var. Nu este necesară folosirea acestui cuvânt atunci când în funcție doar se citește variabila respectivă. Este obligatorie folosirea global dacă în funcție se modifică valoarea variabilei, fără această declarație variabila nu ar rămâne modificată după terminarea funcției, pentru că ar fi privită drept o variabila declarată local.

Includerea de cod extern

În Python se pot include în alte programe funcții, variabile și clase scrise în alte fișier. Un astfel de fișier ce poate fi inclus poartă denumirea de **modul**. Exemplu:

  1. import random

Atunci când includem modulul putem să îl folosim cu un alt nume, eventual pentru a evita coliziuni de denumiri:

  1. import random as rand

Instrucțiunea import din exemplul de mai sus nu incarcă în tabela de simboluri numele funcțiilor definite în modulul random, ci doar numele modulului. Folosind acest nume se pot accesa funcții definite în interiorul modulului folosindu-se sintaxa nume_modul.nume_functie(parametri).

  1. random.random()

Un alt mod de a include este folosind from <nume_modul> import <lista_constructii>, în felul acesta vom avea acces doar la clasele/metodele din modul precizate în <lista_constructii>. Această modalitate este indicată atunci când un modul are un număr foarte mare de clase. Un alt avantaj al acestei metode este că nu mai trebuie folosit numele atunci când se utilizează construcția inclusă, ca în exemplul de mai jos:

  1. from random import random # se include doar metoda random()
  2. random() # se apeleaza metoda random

Clase și obiecte

Trebuie subliniat că în Python, cuvantul “obiect” nu se referă neapărat la instanța unei clase. Clasele în sine sunt obiecte, iar, în sens mai larg, în Python toate tipurile de date sunt obiecte. Există tipuri de date care nu sunt clase: numerele întregi, listele, fișierele. Toate tipurile de date însa au aproximativ același comportament, și este mai ușor de explicat dacă ne referim la aceste tipuri de date folosind cuvantul “obiect”.

Un obiect se crează în Python prin folosirea cuvantului cheie class, ca în exemplul de mai jos, în care
crează un obiect de tip clasa și i se dă numele className.

  1. class className [(super_class1 [, super_class2]*)]:
  2. [interiorul clasei]

Interiorul clasei poate conține definiții de metode locale și atribuiri pentru variabile locale. Clasa este derivată din super_class1 și din super_class2.

  1. class MyClass (object): ...

În lucrul cu clase, trebuie avute în vedere următoarele reguli:

  • Primul argument pentru metodele unei clase este întotdeauna obiectul sursa, numit self prin convenție.
  • Când ne referim la membri ai clasei, vom folosi self.membru, într-un mod asemanator cu folosirea “this” din Java.
  • Metoda specială __init__() este apelată la instanțierea clasei (crearea unui obiect de tipul clasei) și poate fi asemuită cu un constructor. Definirea metodelor __init__() este opțională.
  • Metoda specială __del__() este apelată când nu mai sunt referințe la acest obiect și poate fi asemuită cu un destructor. Definirea metodelor __del__() este opțională.
  • În cazul moștenirii, în metoda __init__() trebuie întâi apelat __init__()-ul claselor părinte.
  • Pentru accesul la variabile, diferențierea se face doar prin numele functiei/variabilei. Implicit toate variabilele si metodele claselor sunt publice, pentru private trebuie pus __ la începutul numelui acestora, iar noțiunea de protected nu există, pentru mai multe detalii citiți aici.
  • Instanțierea se face prin apelarea obiectului clasă, posibil cu argumente (astfel instance=apply(aClassObject, args…) creează o instanță). Spre exemplu:
  1. class Complex:
  2. def __init__(self, realpart, imagpart):
  3. self.r = realpart
  4. self.i = imagpart
  5.  
  6. x = Complex(3.0, -4.5)

De multe ori vom implementa clase derivând din clasa 'Thread', caz în care ar trebui respectate următoarele reguli:

  • Subclasați threading.Thread()
  • Suprascrieți __init__() și run()
  • Nu suprascrieți metoda start()
  • În __init__(), apelați Thread.__init__()

Pe partea OOP, trebuie reținut că în Python clasele suportă multiple inheritence și că nu există un contract propriu-zis pentru interfețe. Pentru a creea clase abstracte există începand cu versiunea 2.6 api-ul abc (Abstract Base Classes). De asemenea în metodele pe care vreți să le lăsați abstracte puteți transmite excepția Not Implemented Error sau să adăugați în corpul funcției doar keyword-ul pass.

Excepții

Ca și Java și alte limbaje de nivel înalt, Python oferă suport pentru excepții. Pentru prinderea excepțiilor aruncate de către funcții se folosește mecanismul try-except, asemănator celui try-catch din Java.

  1. try:
  2. x = int(buffer)
  3. except(ValueError):
  4. print "Date de intrare invalide"
  5. finally:
  6. # clean-up

Mecanismul funcționează în felul urmator:

  • se execută instrucțiunile din blocul try
  • dacă apare o excepție tratată de un bloc except, execuția sare la instrucțiunile din blocul repectiv. Dupa ce excepția este tratată, execuția continuă cu prima instructiune de după blocul try
  • daca apare o excepție ce nu este tratată de niciun bloc except, aceasta este propagată ascendent în alte blocuri try și primeste denumirea de exceptie netratată (unhandled exception) dacă ajunge să nu fie tratată in nici un astfel de bloc.
  • instrucțiunile din blocul finally se execută intotdeauna, indiferent dacă a fost prinsa o excepție sau nu, pentru cazul de la punctul anterior, excepția netratată se aruncă dupa ce se execută blocul finally. Blocul acesta este opțional și este folosit pentru acțiuni de “clean-up”, de exemplu închiderea fișierelor.

O excepție poate fi aruncată folosind instrucțiunea raise. Aceasta poate fi folosită și fară argumente în interiorul unui bloc except pentru a re-arunca exceptia prinsă de blocul respectiv.

  1. if (j>100):
  2. raise ValueError,j

O instrucțiune try poate avea mai multe clauze except. Ultima clauză except poate să nu aibă specificată nicio excepție de tratat fiind astfel folosită pentru a trata toate exceptiile netratate de celelalte clauze.

Ca și while și for, instructiunile try pot avea opțional și o clauză else. Instrucțiunile din blocul else sunt executate atunci când blocul try nu generează nicio excepție.

Python ofera un set de excepții predefinite (built-in), conținute în modulul exceptions (lista lor este în documentație). În afară de acestea, pentru a vă defini propriile excepții este necesar să creați o subclasă a clasei Exception.

Operații cu fișiere

Lucrul cu fisiere este, de asemenea, simplu, iar obiectele și metodele utilizate sunt oferite de modulul ''io''.

Pentru a obține un obiect de tip fișier, se apelează functia open, de obicei cu doi parametri:

  • numele (calea) fisierului
  • modul de acces
    • r - read only
    • w - write only și daca există va fi suprascris
    • a - append
    • r+ - citire si scriere
    • rb, wb, r+b - deschide fișierul în mod binar):
  1. import io
  2. f = open('input.txt','w')
  3. f.write("hello")
  4. f.close()

Odată obținut obiectul fișier f, se vor putea folosi funcțiile pentru lucrul cu fișiere: read, readline, readlines, write, seek sau close ca metode ale clasei file (exemplu: f.read()).

Main-ul

Construcția __main__ este opțională în scripturile Python, și rolul său este similar funcțiilor main din alte limbaje (C, Java etc).

Codul conținut într-un script Python este executat și fără prezența acestui mecanism, însa dezavantajul nefolosirii lui este că atunci când se include fișierul cu import se va executa și codul din el, ca în exemplul următor:

scriptul utilities.py

  1. def f1():
  2. print "hello1"
  3.  
  4. f1()

scriptul mymodule.py

  1. import utilities
  2. utilities.f1()
  1. $ python mymodule.py
  2. hello1
  3. hello1

Dacă in modulul utilities apelul funcției f1() se afla într-un __main__, aceasta nu se apela, deoarece __name__ este numele bibliotecii incluse și codul de după if __name__ == "__main__": nu se va executa.

  1. def f1():
  2. print __name__
  3. print "hello1"
  4.  
  5. if __name__ == "__main__":
  6. f1()
  1. $ python mymodule.py
  2. utilities
  3. hello1
  4. $ python utilities.py
  5. __main__
  6. hello1

Module utile

random

Generarea de numere pseudo-aleatoare se face la fel de ușor ca și în alte limbaje.
  • se include modulul random (import random)
  • se stabilește eventual seed-ul folosind random.seed
  • se apelează metodele oferite în modul, cum ar fi random.randint(a,b), ce va întoarce un întreg cuprins în intervalul închis [a,b].

pickle

În unele cazuri, pentru a scrie obiecte Python in fișiere, a le stoca în baze de date sau a le transmite pe sockets, acestea trebuie transformate într-un string, proces numit pickling (iar procesul invers: unpickling). Folosind modulul pickle cu funcțiile pickle.dump și pickle.load, acest lucru poate fi realizat cu usurință, ca în următorul exemplu:
  1. # Salvam un dictionar intr-un fisier folosind pickle
  2. import pickle
  3. culoare_favorita = { "caisa": "galbena", "portocala": "orange", "cireasa": "rosie" }
  4. print culoare_favorita
  5. pickle.dump(culoare_favorita, open("save.p", "w"))
  6.  
  7. # Incarcam dictionarul inapoi din fisier folosind pickle
  8. culoarea_mea_fav = pickle.load(open("save.p"))
  9. print culoarea_mea_fav
  10. # culoarea_mea_fav e acum { "caisa": "galbena", "portocala": "orange", "cireasa": "rosie" }

Exemple de programe rezolvate

Calculul sumelor parțiale a primelor N numere naturale

Iată un exemplu simplu de script Python, în care se definește o rutină și se apelează.

lab1-rez1.py
  1. #!/usr/bin/python
  2.  
  3. # definim o functie care afiseaza numerele de la 1 la n si calculeaza suma lor
  4. def calc_suma(n): # n este parametru al functiei
  5. # virgula de la print suprima aparitia lui \n dupa textul tiparit
  6. print 1,
  7. suma = 1
  8. i = 2
  9. # nu uitati de ':' de la sfarsitul liniilor care preced sub-blocuri!
  10. # adica dupa for, while, if, def etc.
  11. while i <= n:
  12. print "+", i,
  13. suma += i
  14. i += 1
  15. print "=", suma
  16.  
  17. # raw_input citeste un string de la tastatura afisand promptul dat
  18. # acest string se converteste la un intreg cu int(..). Daca nu se introduce un
  19. # numar valid, se va genera o exceptie.
  20.  
  21. n = int(raw_input("Dati n="))
  22.  
  23. # range(a, b) intoarce o lista ce contine [a, a+1, ..., b-1]
  24.  
  25. for i in range(1, n+1):
  26. calc_suma( i)

Exemplu de execuție:

  1. $ chmod +x sume_partiale.py
  2. $ ./sume_partiale.py
  3. Dati n=4
  4. 1 = 1
  5. 1 + 2 = 3
  6. 1 + 2 + 3 = 6
  7. 1 + 2 + 3 + 4 = 10

Calculul numerelor prime pana la un N dat

lab1-rez2.py
  1. import math # import modulul math
  2. from sys import argv # din modulul sys import lista argv (argumente in linia de comanda)
  3. def isPrime(x): # definesc o functie care decide daca x e prim
  4. for i in range(2, int(math.sqrt(x)+1)): # range(a, b) => lista [a, ..., b-1]
  5. if x % i == 0: # nu uita de ':' !
  6. return 0
  7. return 1
  8.  
  9. def buildPrimes(max = 100): # se poate da o valoare implicita pentru parametru
  10. result = [] # initializez lista
  11. for i in range(1, max+1):
  12. if isPrime(i):
  13. result.append(i) # adaug la sfarsitul ei un nou element
  14. return result
  15.  
  16. # pentru ca parametrul are o valoare implicita, vom putea apela si asa: buildPrimes()
  17. if len(argv) == 2: # argv[0]=nume script; len(argv)==2 inseamna un argument in plus
  18. n = int(argv[1])
  19. print buildPrimes( n)
  20. else: # daca nu am un parametru
  21. try:
  22. n=int(raw_input("Dati N= ")) # raw_input citeste un string de la tastatura
  23. # daca a fost "prinsa" o exceptie:
  24. except(ValueError):
  25. print "Asteptam un numar intreg."
  26. else:
  27. for k in buildPrimes(n): # tiparesc fiecare numar din lista
  28. print k,
  29. print # print simplu inseamna de fapt newline

Exemple de execuție:

  1. $ python prim.py 30
  2. [1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

sau

  1. $ python prim.py
  2. Dati N=50
  3. 1 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47

Pe Windows, pentru a da un argument din linia de comandă, sunt suficiente numele scriptului și argumentul:

c:\> prim.py 30

Exerciții

  1. Fișierul lab1.py conține un set de exemple simple în Python. Decomentați pe rând fiecare exemplu și rulați-l. Observați ce se întâmplă și explicați codul.
  2. Se dă o listă de numere intregi. Se cere să se ordoneze și afișeze elementele din listă, în ordine descrescătoare.
  3. Scrieți o funcție fibonacci(a) care să calculeze elementul de pe pozitia a din șirul lui Fibonacci (1,1,2,3,5,…), definit ca: F(n)=F(n-1)+F(n-2).
  4. O problemă interesantă este oferită în cartea Find the Bug: A Book of Incorrect Programs de Adam Barr: Assign Gift Givers este un program care folosește liste și dicționare iar găsirea bug-ului este un bun execițiu pentru aprofundarea acestora. Puteti porni cautarea de la urmatorul fisier.

Resurse

asc/lab1/index.txt · Last modified: 2013/02/22 17:49 by adriana.draghici
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0