Sunteți pe pagina 1din 114

Python 3 2012 memIQ

DV1.2 - 16042012
1












Python 3
Python 3 2012 memIQ
DV1.2 - 16042012
2

Cuprins
1 Introducere 4
1.1 Crearea i executarea programelor Python 4
1.2 Start... 5
2 Tipuri de date 12
2.1 Identificatori i cuvinte cheie 12
2.2 Tipuri ntregi 12
2.3 Tipuri n virgul mobil 13
2.4 iruri de caractere 14
2.5 Exemple 22
3 Colecii 24
3.1 Tipuri secven 24
3.2 Mulimi 28
3.3 Map-uri 29
3.4 Iterarea i copierea coleciilor 32
3.5 Exemple 35
4 Structuri de control i funcii 36
4.1 Structuri de control 36
4.2 Tratarea excepiilor 37
4.3 Funcii 40
4.4 Exemplu 46
5 Module 47
5.1 Module 47
5.2 Pachete 48
5.3 Exemplu 49
5.4 Biblioteca standard Python 50
6 Programare orientat pe obiecte 58
6.1 Concepte OO 58
6.2 Clase definite de utilizator 58
6.3 Clase colecie personalizate 64
7 Lucrul cu fiierele 71
7.1 Fiiere binare 72
Python 3 2012 memIQ
DV1.2 - 16042012
3

7.2 Fiiere text 74
7.3 Fiiere XML 77
7.4 Exerciii 84
8 Tehnici avansate 85
8.1 Programare procedural 85
8.2 OOP 93
8.3 Programare functionala 106
8.4 Exemplu 108
9 Procese i fire de execuie 110
9.1 Modulul subprocess 110
9.2 Modulul threading 110
9.3 Modulul multiprocessing 110
9.4 Exemplu 110
10 Lucrul n reea networking 111
10.1 Exemplu 111
11 Baze de date 112
11.1 Baze de date DBM 112
11.2 Baze de date SQL 112
12 Referine 114



Python 3 2012 memIQ
DV1.2 - 16042012
4

1 Introducere

Caracterizare: http://python.org/doc/essays/blurb.html

Python:
Limbaj foarte expresiv
Interpretat portabilitate peste platformele cele mai diverse
Biblioteca standard complet; biblioteci pentru cele mai diverse probleme -
http://pypi.python.org/pypi
Limbaj cu caracteristici procedurale, orientat pe obiecte, caliti de programare
funcional

Obiectivul limbajul Python.

Instalare test n consol: python V (python3, python3.1, etc.).

Kit instalare - www.python.org/download

IDE (Integrated Development Environment):
Orice editor text
PSPad
IDLE (Python Shell)
Eclipse + Pydev - http://pydev.org

1.1 Crearea i executarea programelor Python

- ASCII sau UTF-8 (implicit)
- Fiiere cu extensia py, pyw (GUI) sau fr extensie

Exemplu: hello.py

#!/usr/bin/env python

print("Hello", "World!")

- # - comentariu

- Execuia se face linie cu linie ncepnd de sus

- path drumul la python.exe (sau legturi simbolice)

- asociere n Windows a extensiei py cu python.exe

- prima linie:

#!/usr/bin/python3 - interpreter
Python 3 2012 memIQ
DV1.2 - 16042012
5

sau:
#!/usr/bin/env python3 - variabila de mediu conine interpreterul
1.2 Start...
a) Tipuri de date

- Tipuri de date incluse n limbaj, predefinite
- int limitat de memoria mainii
- str se folosesc sau
- [] acces la o secven (primul are index 0), inclusiv str casa[2]
- int si str sunt imutabile
- conversie cast: datatype(element) int(100) --> 100
- int() este tolerant la spaii (trim)
- se genereaz o excepie dac conversia nu reuete

b) Referine la obiecte

- Variabilele in referine la obiecte: x = casa
- Operatorul = leag un obiect de o referin
- Nu trebuie predeclarate, nu trebuie specificat tipul
- Dac un obiect nu mai este referit - va fi distrus de garbage collector
- Identificatorii trebuie s nceap cu liter sau _; case sensitive, orice lungime
- Dynamic typing o referin se poate lega dinamic de un alt tip, va permite
operaii valabile doar pentru acel tip

Exemplu:
X = 100
print(X, type(X)) # 100 <class int>

c) Colecii de date

- Tuple, liste pot ine orice numr de elemente de orice tip;
- Tuple imutabile (, ex: (1,)
- Liste mutabile [,
- n colecie se in referine
- Elemente n colecii pot fi alte colecii
- Tipuri cu mrime (sized) len()

len((1,5))
len(casa)

- Obiectele sunt instane de clase
- Obiectele au metode; apel prin calificare

x = [a, fost]
x.append(casa)

list.append(x, casa)

Python 3 2012 memIQ
DV1.2 - 16042012
6

- list: insert(), remove()
- Acces la elemente prin []; x[0] = masa doar pentru liste, nu tuple!

d) Operaii

Operatorul de identitate - is

- Test dac referinele indic spre acelai obiect (identitate):

Exemplu:
a = [casa, 1, None]
b = [casa, 1, None]
a is b
False
a = b
a is b
True

- Nu se testeaz egalitatea valorilor int sau str, se testeaz identitatea obiectelor
spre care indic referinele
- Rapid se testeaz adresele obiectelor n memorie

Testai: a = 1
b = 1
a is b

Exemplu:
a = None
b = 1
b is not a
True


Operatori de comparare

- < <= > >= == !=
- Se compar valorile obiectelor, nu identitatea lor
- Pentru compararea str se folosesc codurile UNICODE
- Se pot inlnui operatorii:

a = 3
0 <= a <= 5
True

- Se genereaz excepie dac operatorii nu se aplic corect:

casa < 1


Python 3 2012 memIQ
DV1.2 - 16042012
7

Operatorul de testare membru (membership)

- Se aplic pentru secvene sau colecii (str, liste, tuple, etc.)
- in, not in

Exemplu:
a = (1, 3, casa)
1 in a
True

- Pentru liste i tuple se face o cutare liniar lent
- Dictionar sau set rapid
- Se poate folosi pentru a cuta substringuri

Exemplu:
a = a fost odata
fost in a
True

Operatori logici

- Trei operatori: and or not
- nu returneaza Boolean, ci operandul care a determinat rezultatul

Exemplu:
a = 1
b = 2
a and b
2
b and a
1

- dac expresia este ntr-un context Boolean se evaluez la True sau False (de
exemplu n if)

Exemplu:
a or b
b or a

- not produce intotdeauna True sau False

Exemplu:
a = 0
not a

e) Instruciuni

- Ordinea n care se execut instruciunile
Python 3 2012 memIQ
DV1.2 - 16042012
8

- o expresie Boolean este orice se evalueaz la o valoare Boolean (True sau
False)
- convenie - se evalueaza la False: None, o secven sau colecie fr nici un
element, valoarea 0; orice altceva se considera ca fiind True.
- Suite o secven de instruciuni (bloc); instruciunea pass ine loc de suit

If

if expr_bool_1:
suite1
elif expr_bool_2:
suite2

else:
suite_else

- elif, else - opional
- Se folosete indentaia pentru a arta structura blocului
- Indentaie 4 spatii, fr tab

Exemplu:

if a:
print(a)


while

while expr_bool:
suite

- break, continue

Exemplu:

while True:
item = get_item()
if not item:
break
process(item)

for in

for variabila in iterabil:
suite
Exemplu:

for x in casa:
print(x)
Python 3 2012 memIQ
DV1.2 - 16042012
9

- break, continue

Tratarea excepiilor

try:
suita_try
except exceptie1 as var1:
suita_exceptie1

except exceptioN as varN:
suita_exceptieN

- varN este opional

Exemplu: - ncercai cu 5 si 3.14

s = input(introdu un intreg: )
try:
i = int(s)
print(i)
except ValueError as err:
print(err)

f) Operatori aritmetici

- 4 operaii aritmetice: + - * /
- Operatori compui: += -=
- mprire: 3/2 = 1.5 (!); operator mprire cu trunchiere //
- Not: la += - pentru obiectele imutabile se creeaz un alt obiect!
- + i += sunt suprancrcai pentru str i liste
- + concatenare
- += append

Exemplu:
item = masa
item + casa
item += casa

- Listele sunt mutabile, += extinde lista

l = [casa, masa]
l += [om]

- Se genereaz excepie dac operandul din dreapta nu este iterabil:
l += 5

- l += acolo # ... += [acolo]

g) Intrare/ieire
Python 3 2012 memIQ
DV1.2 - 16042012
10


- Funcia input() vezi exemplul sum1.py
- Redirectarea iesirii standard (ce genereaz print()):

>abc.py > out.txt

- Exemplul sum2.py < sum2.dat


h) Funcii

def numeFunctie(argumente):
suite

- Argumentele sunt opionale i sunt desprite prin virgule
- Orice funcie ntoarce o valoare, implicit None
- Return valoare sau un tuplu
- def obiect funcie, referina este numele funciei; se pot pune n colecii i
pasate ca parametrii

Exemplu:

def get_int(msg):
while True:
try:
i = int(input(msg))
return i
except ValueError as err:
print(err)
Folosire:
x = get_int(Introduceti un intreg: )

- module conin funcii, clase, variabile; vezi echoargs.py
Folosire:
import sys

print(sys.argv)

- module standard litere mici
- modulele se import la nceputul fiierului surs

Exemplu:

import random
x = random.randint(1,4)
y = random.choice([casa, masa, om])

Exemple: bigdigits.py, generate_grid.py
Python 3 2012 memIQ
DV1.2 - 16042012
11

Tem: construii un program care accept de la consol un ir de numere pe care le
afieaz apoi sortat (fr a folosi o funcie bibliotec), mpreun cu suma i media lor
aritmetic.


Python 3 2012 memIQ
DV1.2 - 16042012
12

2 Tipuri de date

Tipuri incluse n limbaj sau din modulele standard (caz n care se refer pe baza
numelui modulului, n plus modulul trebuie importat).

2.1 Identificatori i cuvinte cheie
- Reguli pentru nume
- Case sensitive, se folosesc caractere Unicode
- Cuvintele cheie sunt rezervate, nu se pot folosi ca i nume
- Cuvinte cheie:

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

- Nu se folosesc:
o identificatori folosii de Python (ex. NotImplemented)
o nume de tipuri incluse n limbaj int, float, list, str, tuple
o nume de funcii Python
o nume de excepii Python
- dir() listeaz atributele unui obiect
- dir() fr atribute listeaz atributele Python:

['__builtins__', '__doc__', '__name__', '__package__']

listeaz excepii (ncep cu liter mare), funcii i tipuri de date

dir(__builtins__)
- nu se folosesc nume care ncep i se termin cu __ (doi underscore) se
folosesc pentru metode i variabile speciale (ex. __lt__)
- numele care ncep cu unul sau dou caractere underscore au semnificaie
special
- identificatorul _ ine valoarea ultimei expresii evaluate doar n interpretorul
interactiv sau Python Shell:

for _ in (0,1,2):
print(_)

- dac se folosesc identificatori invalizi se genereaz excepia SyntaxError

2.2 Tipuri ntregi
- int i bool imutabile
- ntregii pot fi orict de mari, limitai doar de memorie
Python 3 2012 memIQ
DV1.2 - 16042012
13

- True (1), False (0) valori numerice

- Operaii:
o x // y mprire ntreag
o x % y modulo
o x ** y ridicare la putere
- Funcii:
o abs(x) valoarea absolut
o divmod(x,y) ct i rest ca i tuplu
o pow(x,y) ridicare la putere
o pow(x,y,z) (x**y) % z
o round(x,n) n pozitiv sau negativ; ex: round(1234, -2)
o bin(i) reprezentarea binar a lui i
o hex(i)
o oct(i)
o int(x)
o int(s, base)
- constante n baza 2 (0b), 8 (0o), 16 (0x)
- x = 1 se creeaz un obiect
- crearea unui obiect pe baza tipului:
o tip fr argument x = int() se folosete valoarea implicit
o un argument:
de acelai tip se creeaz un obiect prin shallow copy
alt tip se incearc conversie; se poate genera ValueError sau
TypeError
o mai multe argumente daca exist mod de a crea obiectul!
- Operatii pe biti - | ^ & ~ << >> ( |= ^= )
- int.bit_lenght() returneaz numtul de bii necesari pentru a reprezenta acel
ntreg; exemlu: (2231).bit_length()

Tipul Boolean bool
- True, False - obiecte

2.3 Tipuri n virgul mobil
- Built in: float i complex
- Biblioteca standard: decimal.Decimal pentru precizie (implicit precizie de 28
cifre)
- toate sunt imutabile
- aritmetica cu valori de tipuri diferite; float + complex = complex,

float
- x = float()
- x = float(2)

- test de egalitate ntre dou numere float

def equal_float(a,b):
return abs(a-b) <= sys.float_info.epsilon
Python 3 2012 memIQ
DV1.2 - 16042012
14


- funcii matematice n modulul math de vzut n documentaie!
o import math
o help(math.exp)
- float.is_integer(), float.as_integer_ratio()

complex

z = 2.1 1.43j

- modulul cmath - functii matematice; conjugate()

decimal.Decimal

- precizie mare, vitez mic

import decimal
x = decimal.Decimal(4567) # sau string


2.4 iruri de caractere

- str imutabil, caractere Unicode
- s = triplu quote este posibil
- \ - continuare pe urmtoarea linie
- Coduri escape:

\newline Escape (i.e., ignore) the newline (for ... )
\\ Backslash (\)
\' Single quote ()
\" Double quote (")
\a ASCII bell (BEL)
\b ASCII backspace (BS)
\f ASCII formfeed (FF)
\n ASCII linefeed (LF)
\N{name} Unicode character with the given name
\ooo Character with the given octal value
\r ASCII carriage return (CR)
\t ASCII tab (TAB)
\uhhhh Unicode character with the given 16-bit hexadecimal value
\Uhhhhhhhh Unicode character with the given 32-bit hexadecimal value
\v ASCII vertical tab (VT)
\xhh Character with the given 8-bit hexadecimal value


a fost odata ca \niciodata\

Python 3 2012 memIQ
DV1.2 - 16042012
15

- Raw strings pentru a nu interpreta secvenele escape (de ex. n expresii
regulate ): r este un \
- Pentru stringuri ce nu ncap pe o linie:

s = prima linie + \
a doua linie
sau:
t = (prima linie
a doua linie) # preferat pentru a extinde expresii pe mai multe linii!

euros = " \N{euro sign} \u20AC \U000020AC"

- ord() conversie caracter Unicode int
- chr() conversie int caracter Unicode
- ascii(s) ; ascii(euros) reprezentare ASCII a irului

- Compararea irurilor (dup cod) - operaii de comparare: == != < <= > >=

- Acces la caractere prin index pornete de la 0; negative -1 (ultimul), -2
(penultimul), etc.

- Excepie IndexError se genereaz cnd se folosete un index greit

- Operator slice:
o secventa[start]
o secventa[start:end] - include start, exclude end
o secventa[start:end:step]
- implicit start = 0, end = len(secventa)
- posibil i index negativ! ex: s[::-1]

- Operatori i metode str:
o len()
o + - concatenare
o join .join(lista) preferat n loc de +
o reversed()
o * - replicare: s = x * 10
o *= s *= 10
o in ac in acasa True
o find() cauta un substring in string
o index()
o vezi metode string

s.capitalize() Returns a copy of str s with the first letter capitalized;
see also the str.title() method
s.center(width,char) Returns a copy of s centered in a string of length width
padded with spaces or optionally with char (a string of
length 1); see str.ljust(), str.rjust(), and str.format()
s.count(t,start, end) Returns the number of occurrences of str t in str s (or in
the start:end slice of s)
Python 3 2012 memIQ
DV1.2 - 16042012
16

s.encode(encoding,err) Returns a bytes object bytestype
that represents the string using
the default encoding or using the specified encoding and
handling errors according to the optional err argument
s.endswith(x,start, end) Returns True if s (or the start:end slice of s) ends with str
x or with any of the strings in tuple x; otherwise, returns
False. See also str.startswith().
s.expandtabs(size) Returns a copy of s with tabs replaced with spaces in
multiples of 8 or of size if specified
s.find(t,start, end) Returns the leftmost position of t in s (or in the start:end
slice of s) or -1 if not found. Use str.rfind() to find the
rightmost position. See also str.index().
s.index(t,start, end) Returns the leftmost position of t in s (or in the
start:end slice of s) or raises ValueError if not found. Use
str.rindex() to search from the right. See str.find().
s.isalnum() Returns True if s is nonempty and every character in s
is alphanumeric
s.isalpha() Returns True if s is nonempty and every character in s
is alphabetic
s.isdecimal() Returns True if s is nonempty and every character in s is
a Unicode base 10 digit
s.isdigit() Returns True if s is nonempty and every character in s is
an ASCII digit
s.isidentifier() Returns True if s is nonempty and is a valid identifier
s.islower() Returns True if s has at least one lowercaseable character
and all its lowercaseable characters are lowercase; see also
str.isupper()
s.isnumeric() Returns True if s is nonempty and every character in s is
a numeric Unicode character such as a digit or fraction
s.isprintable() Returns True if s is empty or if every character in s is
considered to be printable, including space, but not newline
s.isspace() Returns True if s is nonempty and every character in s is
a whitespace character
s.istitle() Returns True if s is a nonempty title-cased string; see
also str.title()
s.isupper() Returns True if str s has at least one uppercaseable character
and all its uppercaseable characters are uppercase;
see also str.islower()
s.join(seq) Returns the concatenation of every item in the sequence
seq, with str s (which may be empty) between each one
s.ljust(width,char) Returns a copy of s left-aligned in a string of length width
padded with spaces or optionally with char (a string of
length 1). Use str.rjust() to right-align and str.center()
to center. See also str.format().
s.lower() Returns a lowercased copy of s; see also str.upper()
s.maketrans() Companion of str.translate(); see text for details
s.partition(t) Returns a tuple of three stringsthe part of str s before
the leftmost str t, t, and the part of s after t; or if t isnt in
s returns s and two empty strings. Use str.rpartition()
Python 3 2012 memIQ
DV1.2 - 16042012
17

to partition on the rightmost occurrence of t.
s.replace(t,u, n) Returns a copy of s with every (or a maximum of n if
given) occurrences of str t replaced with str u
s.split(t, n) Returns a list of strings splitting at most n times on str t;
if n isnt given, splits as many times as possible; if t isnt
given, splits on whitespace. Use str.rsplit() to split from
the rightthis makes a difference only if n is given and is
less than the maximum number of splits possible.
s.splitlines(f) Returns the list of lines produced by splitting s on line
terminators, stripping the terminators unless f is True
s.startswith(x, start,end) Returns True if s (or the start:end slice of s) starts with
str x or with any of the strings in tuple x; otherwise,
returns False. See also str.endswith().
s.strip(chars) Returns a copy of s with leading and trailing whitespace
(or the characters in str chars) removed;str.lstrip() strips
only at the start, and str.rstrip() strips only at the end
s.swapcase() Returns a copy of s with uppercase characters lowercased
and lowercase characters uppercased; see also str.lower()
and str.upper()
s.title() Returns a copy of s where the first letter of each word
is uppercased and all other letters are lowercased; see
str.istitle()
s.upper() Returns an uppercased copy of s; see also str.lower()
s.zfill(w) Returns a copy of s, which if shorter than w is padded with
leading zeros to make it w characters long

Exemplu:
def extract_from_tag(tag, line):
opener = "<" + tag + ">"
closer = "</" + tag + ">"
i = line.find(opener)
if i != -1:
start = i + len(opener)
j = line.find(closer, start)
if j != -1:
return line[start:j]
return None

- unele metode accepta 2 parametrii opionali pentru a desemna o parte din
string:

s.count("m", 6) == s[6:].count("m")
s.count("m", 5, -3) == s[5:-3].count("m")

- res = s.rpartition("/")
echivalent:
i = s.rfind("/")
if i == -1:
res = "", "", s
Python 3 2012 memIQ
DV1.2 - 16042012
18

else:
res = s[:i], s[i], s[i + 1:] # intoarce tuplu

aplicat pe /usr/local/bin /usr/local, /, bin

Exemplu:
if filename.lower().endswith((".jpg", ".jpeg")):
print(filename, "is a JPEG image")
- << casa.strip( <)

- split()

linie = nume/prenume/data
campuri = linie.split(/)

- str.maketrans(), str.translate()

table = "".maketrans("\N{bengali digit zero}"
"\N{bengali digit one}\N{bengali digit two}"
"\N{bengali digit three}\N{bengali digit four}"
"\N{bengali digit five}\N{bengali digit six}"
"\N{bengali digit seven}\N{bengali digit eight}"
"\N{bengali digit nine}", "0123456789")
print("12345".translate(table)) # 12345
print("\N{bengali digit one}23\N{bengali digit four}"
"\N{bengali digit five}".translate(table)) # 12345

- alte module ce ofer funcii de lucru cu str unicodedata, difflib, textwrap,
string, io.StringIO

Formatarea irurilor de caractere

str.format()

{0} a fost la {1}.format(El, teatru) # stil C#, poziie

{{{0}}} .format() - dublare acolade

Format:
{field_name}
{field_name!conversion}
{field_name:format_specification}
{field_name!conversion:format_specification}

{nume} are {varsta} ani.format(nume=Nelu, varsta=10)

{nume} are {0} ani.format(10, nume=Nelu)

Python 3 2012 memIQ
DV1.2 - 16042012
19

zile = [luni, marti, ..]
astazi este {0[0]}.format(zile)

- dictionare {0[nume]} valoarea asociat cheii
d = dict(nume="Mihai", greutate=72)
{0[nume]} are {0[greutate]} kg.format(d);

- math, sys - module
"math.pi=={0.pi} sys.maxunicode=={1.maxunicode}".format(math, sys)

"{} {} {}".format("Python", "can", "count")

element = "Silver"
number = 47
"Element {number} is {element}".format(**locals())

** - operator mapping unpacking
locals() returneaz un dicionar cu variabilele locale (nume=valoare)

- n loc de locals se poate folosi orice dicionar (ex. de mai sus):

{nume} are {greutate} kg.format(**d);


Conversii

>>> decimal.Decimal("3.4084")
Decimal('3.4084') # forma reprezentationala, poate fi interpretat i
# recrea obiectul

>>> print(decimal.Decimal("3.4084"))
3.4084 # forma string, pentru oameni

Nu toate obiectele au o form reprezentaional.

"{0} {0!s} {0!r} {0!a}".format(decimal.Decimal("93.4"))
"93.4 93.4 Decimal('93.4') Decimal('93.4')"

- s - forma string
- r - forma reprezentaional
- a - forma reprezentaional folosind doar ASCII


Specificaii de format

Format general:

: fill align sign # 0 width , . precision type

Python 3 2012 memIQ
DV1.2 - 16042012
20

- ncepe cu :
- fill - caracter de umplere, opional, nu poate fi carcterul }
- align - caracter de aliniere: < ^ > = (pad ntre semn i cifre pentru numere)
- sign - + forare semn, - semn doar dac este nevoie, spatiu sau
- # - ntregii sunt precedai de 0b, 0o sau 0x
- 0 pad cu 0 a numerelor
- width lime minim
- , - folosete , pentru grupare cifre
- .precision lime maxim pentru str; numrul de digii dup punct la numere
n virgul mobil
- Type int: b, c, d, n, o, x, X; float: e, E, f, g, G, n, %

a) Stringuri

s = Ana are mere

{0}.format(s)
{0:20}.format(s) # lime minim
{0:^20}.format(s) # + centrat
{0:-^20}.format(s) # + caracter de umplere
{0:.<20}.format(s)
{0:.10}.format(s) # lime maxim

maxwidth = 8
"{0}".format(s[:maxwidth])
"{0:.{1}}".format(s, maxwidth) # specificatorul de format!!

b) ntregi

- Caracter umplere
- Aliniere - < ^ < = - pad ntre semn i cifre!
- Semn:
o + foreaz afiarea semnului;
o (sau ) se afieaz semn doar dac este nevoie
- # - daca vrem ca ntregul s fie cu prefix 0b, 0o sau 0x
- 0 pad cu 0
- Width mrimea minim a cmpului
- , - grupare mii
- Tip b, d, o, x, X (c, n)

Exemple padding:
"{0:0=12}".format(8749203) # 0 fill, minimum width 12
"{0:0=12}".format(-8749203) # 0 fill, minimum width 12
"{0:012}".format(8749203) # 0-pad and minimum width 12
"{0:012}".format(-8749203) # 0-pad and minimum width 12

Exemple aliniere:
"{0:*<15}".format(18340427) # * fill, left align, min width 15
"{0:*>15}".format(18340427) # * fill, right align, min width 15
"{0:*^15}".format(18340427) # * fill, center align, min width 15
Python 3 2012 memIQ
DV1.2 - 16042012
21

"{0:*^15}".format(-18340427) # * fill, center align, min width 15

Exemple semn:
"[{0: }] [{1: }]".format(539802, -539802) # space or - sign
"[{0:+}] [{1:+}]".format(539802, -539802) # force sign
"[{0:-}] [{1:-}]".format(539802, -539802) # - sign if needed

Exemple tip ntreg:
"{0:b} {0:o} {0:x} {0:X}".format(14613198)
"{0:#b} {0:#o} {0:#x} {0:#X}".format(14613198)

Exemplu grupare mii:
"{0:,} {0:*>13,}".format(int(2.39432185e6))

- Tipul n echivalent cu d (ntreg) sau g (virgul mobil) respect locale
(conveniile legate de numere)

x, y = (1234567890, 1234.56)
locale.setlocale(locale.LC_ALL, "C")
c = "{0:n} {1:n}".format(x, y) # c == "1234567890 1234.56"

locale.setlocale(locale.LC_ALL, "en_US.UTF-8")
en = "{0:n} {1:n}".format(x, y) # en == "1,234,567,890 1,234.56"
locale.setlocale(locale.LC_ALL, "de_DE.UTF-8")
de = "{0:n} {1:n}".format(x, y) # de == "1.234.567.890 1.234,56"


c) Virgul mobil

- Analog cu ntregii; un cmp precizie numrul de cifre dup punctual zecimal
- Cmpul tip: e, E exponenial, f standard, g, G general (f pentru nr mic, e
pt nr foarte mari)

Exemple:
amount = (10 ** 3) * math.pi
"[{0:12.2e}] [{0:12.2f}]".format(amount)
"[{0:*>12.2e}] [{0:*>12.2f}]".format(amount)
"[{0:*>+12.2e}] [{0:*>+12.2f}]".format(amount)

- Decimal.Decimal sunt tratate din 3.1 ca i floats:

"{:,.6f}".format(decimal.Decimal("1234567890.1234567890"))

- Numerele complexe

"{0.real:.3f}{0.imag:+.3f}j".format(4.75917+1.2042j)
"{0.real:.3f}{0.imag:+.3f}j".format(4.75917-1.2042j)

De la 3.1 (folosirea aceluiai format pentru ambele pri):

Python 3 2012 memIQ
DV1.2 - 16042012
22

"{:,.4f}".format(3.59284e6 - 8.984327843e6j)


Exemplu: print_unicode.py


Encodarea caracterelor

- Seturi de caractere sunt reprezentate pe bytes
- ASCII
- Unicode 32 biti (100.000 caractere)
o UTF-8 1, 2, 3, mai multi bytes; compatibil cu ASCII (web, xml)
o UCS-2 (UTF-16) 2 sau 4 bytes; Java
o UCS-4 (UTF-32)
- Phyton folosete UCS-2 sau UCS-4 (depinde de compilare)
- sys.maxunicode codul maxim Unicode
- str.encode() ntoarce o secven de bytes (un obiect bytes) n encodarea
specificat:

x = \u1111
x.encode(latin1)
x.encode(utf8) # x.encode(utf-8)
x.encode(utf16) # primii doi bytes indic ordinea bytes
x.encode(utf32)
- literal byte b\xffXyZ\x00
- encodarea case insensitive, caracterele - si _ sunt interschimbabile (Latin-1,
latin1, latin_1)
- opiuni:
o ignore x.encode(asci, ignore) se elimina caracterele ce nu au
cod n codarea dorit
o replace se pune ?
o backslashreplace se pune codul n format \x..

- bytes.decode() (bytearray.decode())

b\abc\xc3\x90.decode(utf8)

Problem: detecia automat a encodrii folosite de un document

2.5 Exemple

1. quadratic.py rezolvare ecuaie de gradul doi

equation = ("{a}x\N{SUPERSCRIPT TWO} + {b}x + {c} = 0"
" \N{RIGHTWARDS ARROW} x = {x1}").format(**locals())

equation = ("{}x\N{SUPERSCRIPT TWO} + {}x + {} = 0"
" \N{RIGHTWARDS ARROW} x = {}").format(a, b, c, x1)
Python 3 2012 memIQ
DV1.2 - 16042012
23


2. cvs2html.py transformare fiier csv n html

cvs2html.py < a.cvs > b.html

- nu folosim modulul csv


Exerciii

- modificai programul print_unicode.py pentru a afia caracterele Unicode a
cror nume conin mai multe iruri de caractere, de ex. small letter
- modificai programul cvs2html.py astfel nct s permit folosirea a doi
parametrii opionali:

csv2html.py [maxwidth=int] [format=str] < infile.csv > outfile.html

o maxwidth specific mrimea maxim a elementului din tabel
o format - formatul folosit pentru afiarea numerelor, implicit este .0f


Python 3 2012 memIQ
DV1.2 - 16042012
24

3 Colecii
3.1 Tipuri secven
- Se definete prin atributele:
o Suport operatorul de apartenen (membership) in
o Funcia len()
o Slices []
o Sunt iterabile

- Python are 5 tipuri predefinite de tip secven: bytearray, bytes, list, str, tuple
- n biblioteca standard se definesc i alte tipuri secven important este
collections.namedtuple


Tuple

- Este o secven ordonat de zero sau mai multe referine de obiecte.
- Suport slicing ca i tipul str
- Imutabile nu se pot terge sau modifica elemente (listele permit!)
- Conversie la list list(tuplu)
- Creare: tuple(), tuple(tuplu), (), (x,y,z)
- Index: 0, 1 - -1, -2..
- t.count(x) de cte ori apare x n tuplul t
- t.index(x) indexul in t alui x sau ValueError dac nu exist
- + - concatenare
- * - replicare
- [] (slicing): z[-3:]
- in, not in
- +=
- *=
- < <= == != - membru cu membru

Exemple:
z = alb, rosu, verde, albastru

z[2:], galben, z[:2]

z[2:] + (galben,) + z[:2]

a, b = 1, 2

return z, y, z # folosit n funcii pentru a ntoarce mai multe valori

for x, y in ((1,1), (2,3), (4,5)):

things = (1, -7.5, ("mar", (5, "Xyz"), "queue"))
things[2][1][1][2]

Python 3 2012 memIQ
DV1.2 - 16042012
25

MANUFACTURER, MODEL, SEATING = (0, 1, 2)
MINIMUM, MAXIMUM = (0, 1)
aircraft = ("Airbus", "A320-200", (100, 220))
aircraft[SEATING][MAXIMUM]

a, b = b, a # interschimbare valori!


Tuple cu nume - collections.namedtuple

- Se comport la fel ca un tuplu obinuit, aceleai performane
- Adaug posibilitatea de a face referin la elemente prin nume i index

Sale = collections.namedtuple("Sale",
"productid customerid date quantity price")

- Sale numele tuplului cu nume = clas definit de utilizator
- nume pentru elementele tuplului (identificatori Python valizi) separai
prin spaiu
- Se pot crea obiecte de tip Sale:

sales = []
sales.append(Sale(432, 921, "2010-12-14", 3, 7.99))
sales.append(Sale(419, 874, "2010-12-15", 1, 18.49))

sales[0][-2] - cantitate din primul tuplu

total = 0
for sale in sales:
total += sale.quantity * sale.price
print("Total ${0:.2f}".format(total))


Aircraft = collections.namedtuple("Aircraft", "manufacturer model seating")
Seating = collections.namedtuple("Seating", "minimum maximum")
aircraft = Aircraft("Airbus", "A320-200", Seating(100, 220))
aircraft.seating.maximum

print("{0} {1}".format(aircraft.manufacturer, aircraft.model))

"{0.manufacturer} {0.model}".format(aircraft)

- Tuple cu nume au metode ce ncep cu _ (underscore);
- namedtuple._asdict() returneaza un map cu perechi nume valoare cu
elementele tuplu-lui (folosim ** - operatorul de despachetare a map-ului):

"{manufacturer} {model}".format(**aircraft._asdict())


Python 3 2012 memIQ
DV1.2 - 16042012
26

Liste

- similar cu tuplu, dar sunt mutabile se pot terge sau nlocui elementele din
list
- construcie lista cu list(), list(lista), lista(ref) se incearca conversia lui ref la o
lista
- [], [elem1, elem2, ]
- Elementele n list pot fi de orice tip, inclusiv colecii
- Operatori: in + += * *= len() del slice - [] - identic cu tuple
- Not: efect del; ex: del a
- funcii list:
o l.append(x)
o l.count(x)
o l.extend(iterabil) = l += m
o l.index(x, start, end)
o l.insert(i, x) = l[i:i] = x (insert in slice de lungime 0)
o l.pop()
o l.pop(i)
o l.remove(x)
o l.reverse() in place
o l.sort() in place

- operatorul de despachetare secven * se aplic la orice iterabil

first, *rest = [1, 2, 3, 4, 5]

first 1
rest [2, 3, 4, 5]

first, *mid, last = Charles Philip Arthur George Windsor.split()

*dirs, executabil = /usr/local/bin/abc.split(/)

*mid se numete starred expression; aplicat la argumente se numete
starred arguments:

func(a, b, c):
return a * b * c;

apel:
func(1, 2, 3)

lista = [1, 2, 3]
func(*lista)

func(1, lista[1:])



Python 3 2012 memIQ
DV1.2 - 16042012
27

Idiom pentru alterarea elementelor din list:
for i in range(len(lista)):
lista[i] = process(lista(i))

range() returneaz un iterator ce produce ntregi; cu argumentul n produce
valorile 0, 1, n-1

Exemplu:

for i in range(len(numere)):
numere[i] += 1

- stergere elemente din lists
o lista.pop(), lista.pop(i)
o lista.remove(x)
o del lista[2]
o lista[2:4] = []
o del lista[2:4]

- x[start:end:pas]; x[::2] = [x[0], x[2], ]

Exemplu: x[1::2] = [0]*len(x[1::2])

- lista.sort(key=str.lower) - argumentul key specific funcia ce se aplic
fiecrui element din list, valoarea returnat de aceasta se folosete n funcia
de sortare

- list(range(n)), list(range(n,m))


List comprehensions generare de liste

Form:
[expression for item in iterable]
[expression for item in iterable if condition]

Echivalent:
temp = []
for item in iterable:
if condition:
temp.append(expression)

Exemplu:

leaps = [y for y in range(1900, 1940)
if (y % 4 == 0 and y % 100 != 0) or (y % 400 == 0)]


Python 3 2012 memIQ
DV1.2 - 16042012
28

3.2 Mulimi

- Colecie ce suport operatorul in, size() si este iterabil.
- Built in :
o set mutabil
o frozenset imutabil
- n mulimi se pot aduga doar obiecte hash-abile, obiecte care au metod
__hash()__ ce returneaz aceeai valoare pe ntreaga durat de via a
obiectului;
- toate tipurile built-in imutabile (float, frozenset, int, str, tuple) se pot aduga
la mulimi; tipurile built-in mutabile (dict, list, set) nu se pot include n seturi,
valoarea lor hash se modific funcie de coninut.

Set-uri

- colecie neordonat de zero sau mai multe referinte ce indic spre obiecte
hash-abile.
- Mutabile: se pot aduga i scoate elemente

S = {4, casa, 1.2, (a, b), 6}

- Creare: set(), set(multime), set(ref), {} (literal set)
- Nu conine duplicate (!)
- Operaii cu mulimi (operatori):
o | - reuniune
o & - intersecie
o - - diferen
o ^ - diferena simetric

Mulimile se folosesc pentru:
- a testa apartenena (mai rapid ca listele)

if len(sys.argv) == 1 or sys.argv[1] in {"-h", "--help"}:

- a nu procesa duplicate de exemplu pentru a extrage IP-urile unice dintr-un
fiier de log

for ip in set(ips):
process_ips(ip)
Operaii:
- s.add(x)
- s.clear()
- s.copy()
- s.difference(t) s t
- s.difference_update(t) s -= t
- s.discard(x)
- s.intersection(t) s & t
- s.intersection_update(t) s &= t
- s.isdisjoint(t)
Python 3 2012 memIQ
DV1.2 - 16042012
29

- s.issubset(t) s <= t
- s.issuperset(t) s >= t
- s.pop() - scoaterea unui element random
- s.remove(x)
- s.symmetric_difference(t) s ^ t
- s.symmetric_difference_update(t) s ^= t
- s.union(t) s | t
- s.update(t) s |= t


Set Coprehensions

{expression for item in iterable}
{expression for item in iterable if condition}

Exemplu:

html = {x for x in files if x.lower().endswith((".htm", ".html"))}


Frozen Sets
- imutabile
- se creeaz doar cu frozenset()
- suport doar operaiile pe mulimi care nu modific mulimea
- un operator binar aplicat la un set si un frozenset duce la un rezultat de tipul
operandului din stnga


3.3 Map-uri

- suport in, len(), este iterabil
- colecie de perechi cheie valoare
- ofer metode de acces la chei i valori
- ca si chei se pot folosi doar obiecte hash-abile (imutabile); valorile asociate
pot fi orice tip

Dictionare
- dict o colecie neordonat de zero sau mai multe perechi cheie valoare
- cheia este unic
- mutabile se pot aduga i scoate elemente
- dict()

Creare:
d1 = dict({"id": 1948, "name": "Washer", "size": 3})
d2 = dict(id=1948, name="Washer", size=3)
d3 = dict([("id", 1948), ("name", "Washer"), ("size", 3)])
d4 = dict(zip(("id", "name", "size"), (1948, "Washer", 3)))
d5 = {"id": 1948, "name": "Washer", "size": 3}
Python 3 2012 memIQ
DV1.2 - 16042012
30

- funcia built-in zip() primete dou tuple i returneaz o list de tuple,
fiecare tuplu este o pereche cheie valoare
- acces prin [] - d[rosu] = 223
- tergere intrare - del d[rosu]
- dict.pop()
- iterare dict:

for item in d.items():
print(item[0], item[1])

for key, value in d.items():
print(key, value)

for value in d.values():
print(value)

for key in d:
print(key)

for key in d.keys():
print(key)

- idiom modificare dicionar:

for key in d:
d[key] += 1

- dict.items(), dict.keys(), dict.values() returneaz vederi ale dicionarelor
(iterabil read-only); view-ul reflect schimbrile dicionarului de care aparin

- funcii:
o d.clear()
o d.copy()
o d.fromkeys(s, v) returneaza un dict cu chei din secvena s i valori
None sau v daca este furnizat
o d.get(k) (None)
o d.get(k, v) returneaz v daca nu este valoare asociat lui k
o d.items()
o d.keys()
o d.pop(k) - KeyError dac nu este intrare de cheie k
o d.pop(k, v)
o d.popitem() - aleator sau KeyError dac nu exist nimic n dict
o d.setdefault(k, v) daca exist returneaz val asociat cu k, dac nu
asociaz valoarea v la cheia k
o d.update(a) - a este dict, iterabil cu perechi (cheie, valoare) sau
argumente cu nume
o d.values()
Exemple: contorizarea cuvintelor dintr-un fiier uniquewords1.py
- external_sites.py afiare site-uri incluse n fiiere html
Python 3 2012 memIQ
DV1.2 - 16042012
31

Citirea i scrierea fiierelor text

- funcie built-in open() returneaz un obiect file (io.TextIOWrapper)
- read sau write, text sau binary
- encodarea folosit

fin = open(filename, encoding="utf8") # citire text
fout = open(filename, "w", encoding="utf8") # scriere text

for line in open(filename, encoding="utf8"):
process(line)

- liniile conin \n
- write(string) - trebuie s se termine cu \n
- close()

greens = dict(green="#0080000", olive="#808000", lime="#00FF00")
print("{green} {olive} {lime}".format(**greens)) # mapping unpacking


Dictionary Comprehension

- este o expresie i un ciclu cu o condiie opional ntre acolade
- similar cu set comprehension

{keyexpression: valueexpression for key, value in iterable}
{keyexpression: valueexpression for key, value in iterable if condition}

Exemplu:

file_sizes = {name: os.path.getsize(name) for name in os.listdir(".")}

file_sizes = {name: os.path.getsize(name) for name in os.listdir(".")
if os.path.isfile(name)}

inverted_d = {v: k for k, v in d.items()} # valorile pot s nu fie unice, sau imutabile!


Dicionare implicite

- identic cu dicionarele obinuite, diferena este la tratarea cheilor inexistente
nu se genereaz excepia KeyError!

collections.defaultdict(int) # int factory function; se folosete s genereze
# o valoare dac nu exist niciuna asociata cheii!

Exemplu uniquewords2.py


Python 3 2012 memIQ
DV1.2 - 16042012
32

Dicionare ordonate

- collections.OrderedDict
- acelasi API ca i dict, ine minte ordinea de inserie

d = collections.OrderedDict([('z', -4), ('e', 19), ('k', 7)])

tasks = collections.OrderedDict() # adugare la fiecare asignare
tasks[8031] = "Backup"
tasks[4027] = "Scan Email"
tasks[5733] = "Build System"

- dac se modific o valoare asociat unei chei ea rmane pe aceeai poziie

- dicionare sortate (cheile se sorteaz):

d = collections.OrderedDict(sorted(d.items()))

3.4 Iterarea i copierea coleciilor

Iteratori, operaii i funcii iterabile

- Un tip de date este iterabil dac putem obine acces la elementele lui pe rnd:
o Are metoda __iter__() returneaz un iterator
o Sau este secven (are metoda _getitem_())
- Iterator ofer acces la elementele coleciei prin __next__(); se genereaz
excepia StopIteration dac nu mai exist elemente
- Ordinea n care se furnizeaz elementele depind de tipul coleciei
- Funcia built-in iter() furnizeaza un iterator pentru colecia dat ca parametru
sau genereaza excepia TypeError dac obiectul nu se poate itera.
- Implementare for ..in

product = 1
for i in [1, 2, 4, 8]:
product *= i
print(product) # 64

product = 1
i = iter([1, 2, 4, 8])
while True:
try:
product *= next(i)
except StopIteration:
break
print(product) # 64

- Orice iterabil i se poate converti: tuple(i), list(i)

Python 3 2012 memIQ
DV1.2 - 16042012
33

- Stil programare funcional funcii bazate pe iterator
x = [1, 2, 3, 4, 5, 6]
all(x), any(x), len(x), min(x), max(x), sum(x)

- Funcia built-in enumerate() primete ca parametru un iterabil sau iterator i
ntoarce un obiect enumerator; enumeratorul este tratat ca un iterator, la
fiecare iteraie returneaza un tuplu cu 2 elemente: numrul iteraiei (implicit
pornete de la 0) i urmtorul element furnizat de iterator

Exemplu: grepword.py DOM data/forenames.txt

- Funcia built-in range() ntoarce un iterator ce returneaz ntregi

list(range(5)), list(range(9, 14)), tuple(range(10, -11, -5))
([0, 1, 2, 3, 4], [9, 10, 11, 12, 13], (10, 5, 0, -5, -10))

Exemplu pe o list x:

for i in range(len(x)):
x[i] = abs(x[i])

echivalent:

i = 0
while i < len(x):
x[i] = abs(x[i])
i += 1

- Operatorul de despachetare *

calculate(1, 2, 3, 4)
t = (1, 2, 3, 4)
calculate(*t)
calculate(*range(1, 5))

Exemplu: generate_test_names1.py

- Pentru numele de fiiere se pot folosi conveniile Unix inclusiv pentru
Windows
- Conversia fisier.replace(/, os.sep) - os.sep este specific SO gazd

- Funcia built-in zip() combin elemente din dou sau mai multe iterabile;
returneaz un iterator ce returneaza tuple

for t in zip(range(4), range(0, 10, 2), range(1, 10, 2)):
print(t)
rezultat:
(0, 0, 1)
(1, 2, 3)
Python 3 2012 memIQ
DV1.2 - 16042012
34

(2, 4, 5)
(3, 6, 7)

Exemplu: generate_test_names2.py

- Funcia built-in reversed() primete o secven i returneaz un iterator ce
d acces la elemente n ordine invers celei normale

list(reversed(range(10)))

- Funcia built-in sorted()

x = []
for t in zip(range(-10, 0, 1), range(0, 10, 2), range(1, 10, 2)):
x += t
x
[-10, 0, 1, -9, 2, 3, -8, 4, 5, -7, 6, 7, -6, 8, 9]
sorted(x)
[-10, -9, -8, -7, -6, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
sorted(x, reverse=True)
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -6, -7, -8, -9, -10]
sorted(x, key=abs)
[0, 1, 2, 3, 4, 5, 6, -6, -7, 7, -8, 8, -9, 9, -10]

- Funciile sunt obiecte, se pot pasa ca argumente la alte funcii, se pot pune n
colecii; numele funciei este o referin la obiectul funciei:

x = sorted(x, key=str.lower)

echivalent cu:

temp = []
for item in x:
temp.append((item.lower(), item))
x = []
for key, value in sorted(temp):
x.append(value)

- Sort folosete operatorul <

Exemplu:
x = list(zip((1, 3, 1, 3), ("pram", "dorie", "kayak", "canoe")))
x
[(1, 'pram'), (3, 'dorie'), (1, 'kayak'), (3, 'canoe')]
sorted(x)
[(1, 'kayak'), (1, 'pram'), (3, 'canoe'), (3, 'dorie')]
def swap(t):
return t[1], t[0]
sorted(x, key=swap)
Python 3 2012 memIQ
DV1.2 - 16042012
35

- list.sort() - pentru in place sort

- sortarea se poate face pentru colecii n care elementele se pot compara

sorted([1, 1.2, -55, casa, 0]) # exceptie TypeError

- dac stringurile se pot converti la float:

sorted(["1.3", -7.5, "5", 4, "-2.4", 1], key=float) # se genereaz excepia ValueError
# dac nu se poate face conversia
# rezultatul conine stringurile originale!
Copierea coleciilor

a = b # se copiaz referine, orice tip ar avea b!

- dict.copy() set.copy()
- modulul copy ofer:
o copy.copy() - returneaza o copie shallow a obiectului furnizat
o copy.deepcopy()

- shallow copy se copiaz doar referinele (sunt OK pentru obiecte imutabile);
dac una din colecii se modific se va modifica i cealalta:

d1 = dict(d)
l1 = list(l)
s1 = set(s)

- deep copy:
import copy
y = copy.deepcopy(x)
3.5 Exemple

- generate_usernames.py genereaz usernames pe baza informaiilor din
fiierul users.txt

- statistics.py calculeaza statistici pe baza numerelor citite din fiierul
dat/statistics.dat

Exerciii

1. Modificai external_sites.py pentru a folosi un dicionar implicit.

2. Modificati uniquewords2.py astfel nct s raporteze cuvintele n ordinea
frecvenei lor de apariie, nu alfabetic

3. Modificai generate_usernames.py astfel nct s raporteze doi utilizatori
pe linie; limitai numele la 17 caractere.
Python 3 2012 memIQ
DV1.2 - 16042012
36

4 Structuri de control i funcii
4.1 Structuri de control

Structuri condiionale

if bool_expr1:
suite1
elif bool_expr2:
suite2
.
elif bool_exprN:
suiteN
else:
suiteElse

Variant:
expression1 if boolean_expression else expression2

Exemple:

offset = 20 if sys.platform.startswith("win") else 10
print({0} file{1}.format((count if count != 0 else no),
(s if count != 1 else )))

Cicluri

Cicluri while

while boolean_expression:
while_suite
else:
else_suite

- else se execut doar dac while se termin normal (nu se termin prin break,
return, excepie)
- continue, break

Exemplu:
def list_find(lst, target):
index = 0
while index < len(lst):
if lst[index] == target:
break
index += 1
else:
index = -1
return index
Python 3 2012 memIQ
DV1.2 - 16042012
37

Cicluri for

for expression in iterable:
for_suite
else:
else_suite

Exemplu:

def list_find(lst, target):
for index, x in enumerate(lst):
if x == target:
break
else:
index = -1
return index


4.2 Tratarea excepiilor

Prinderea excepiilor

try:
try_suite
except exception_group1 as variable1:
except_suite1

except exception_groupN as variableN:
except_suiteN
else:
else_suite
finally:
finally_suite

- Blocul else se execut doar dac blocul try s-a terminat normal
- Blocul finally se execut ntotdeauna la sfrit
- Grupul excepie poate conine o excepie sau un tuplu de excepie; variabila
este opional, ea se poate folosi n blocul de tratare a excepiei
- Excepia generat trebuie s se potriveasc cu excepiile pe care ateapt
handler-ele
- Handler-ele se ordoneaz incepnd cu cele mai specifice excepii vezi
hierarhia de excepii built-in n documentaie (search exception hierarchy)!
- except: (fr nici o excepie specificat) prinde orice excepie
(BaseException)!




Python 3 2012 memIQ
DV1.2 - 16042012
38

Exemplu:
def list_find(lst, target):
try:
index = lst.index(target)
except ValueError:
index = -1
return index

- acceptabil:
try:
try_suite
finally:
finally_suite

- exemplu pentru tratarea erorilor n lucrul cu fiierele:

def read_data(filename):
lines = []
fh = None
try:
fh = open(filename, encoding="utf8")
for line in fh:
if line.strip():
lines.append(line)
except (IOError, OSError) as err:
print(err)
return [] # nainte de return se execut finally!!
finally:
if fh is not None:
fh.close()
return lines

varianta:
except EnvironmentError as err: # clasa printe pentru
# excepiile anterioare!
print(err)
return []

Generarea excepiilor

- putem folosi excepii proprii derivate din Exception sau deja definite
- forme:

raise exception(args)
raise exception(args) from original_exception # inlantuirea excp
raise # se rearunca exceptia activa

- excepia trebuie s fie derivat din Exception

Python 3 2012 memIQ
DV1.2 - 16042012
39


Excepii definite de utilizator

- sunt clase definite de utilizator:
class exceptionName(baseException): pass

- clasa de baz trebuie s fie Exception sau derivate din Exception
- pass null operation, se folosete pentru clase sau funcii

Exemplu: iesirea din mai multe cicluri imbricate

found = False
for row, record in enumerate(table):
for column, field in enumerate(record):
for index, item in enumerate(field):
if item == target:
found = True
break
if found:
break
if found:
break
if found:
print("found at ({0}, {1}, {2})".format(row, column, index))
else:
print("not found")

Variant cu excepie definit de utilizator:

class FoundException(Exception): pass

try:
for row, record in enumerate(table):
for column, field in enumerate(record):
for index, item in enumerate(field):
if item == target:
raise FoundException()
except FoundException:
print("found at ({0}, {1}, {2})".format(row, column, index))
else:
print("not found")


Exemplu: checktags.py verific coninutul unui fiier HTML



Python 3 2012 memIQ
DV1.2 - 16042012
40

4.3 Funcii

Tipuri de funcii n Python:
- Globale - toate funciile de pn acum au fost globale accesibile pentru orice
cod din acelai modul (acelai fisier .py) sau din alte module;
- Locale (sau ncuibate) sunt definite n alte funcii; sunt vizibile doar n
funcia unde sunt definite
- Lambda sunt expresii
- Metode sunt asociate unui tip de date, pot fi folosite doar pe baza acelui tip

Nota: docs.python.org documentatie Pyton, inclusiv pentru toate functiile built-in
sau oferite de module Python; library reference, Global Module Index; help() in
interpretor; dir() de ex. dir(str)

Definire functie:

def functionName(parameters):
suite

Exemplu:
def heron(a, b, c):
s = (a + b + c) / 2
return math.sqrt(s * (s - a) * (s - b) * (s - c))

- Trebuie furnizat exact numarul definit de parametrii (altfel exceptie
TypeError)
- Argumente sunt poziionale
- Funciile ntorc o valoare una singur, un tuplu, o colecie
- return
- dac nu se ntoarce ceva explicit se intoarce None
- Valori implicite pentru parametrii (parametru=valoare_implicita), trebuie s
fie la coada parametrilor, sunt opionali (se numesc parametrii cheie):

def letter_count(text, letters=string.ascii_letters):
letters = frozenset(letters)
count = 0
for char in text:
if char in letters:
count += 1
return count

- Pasarea parametrilor dup nume:

def shorten(text, length=25, indicator="..."):
if len(text) > length:
text = text[:length - len(indicator)] + indicator
return text
apel:

Python 3 2012 memIQ
DV1.2 - 16042012
41

shorten("The Silkie")
shorten(length=7, text="The Silkie")
shorten("The Silkie", indicator="&", length=7)
shorten("The Silkie", 7, "&")
Exemplu:
open(filename, encoding=utf8)
Exemplu:
def append_if_even(x, lst=[]): # lst se creeaz la definirea funciei!
if x % 2 == 0:
lst.append(x)
return lst
soluie:
def append_if_even(x, lst=None):
if lst is None:
lst = [] # lst se creeaz la apel
I if x % 2 == 0:
lst.append(x)
return lst
sau:
def append_if_even(x, lst=None):
lst = [] if lst is None else lst
if x % 2 == 0:
lst.append(x)
return lst


Nume pentru funcii i docstrings

- Convenii pentru numele alese pentru funcii
- Documentarea funciilor prin docstrings:

def calculeazaArie(x, y):
Calc. aria unui dreptunghi

.


return a*b

afiare:
help(calculeazArie)


Despachetarea argumentelor i parametrilor

- * operatorul de despachetarea unei secvente
- * este folosit pentru despachetarea parametrilor n apelul unei funcii ce
calculeaz aria unui triunghi cu formula lui Heron:

Python 3 2012 memIQ
DV1.2 - 16042012
42

heron(sides[0], sides[1], sides[2])

heron(*sides)
- * se poate folosi i pentru argumente:

def product(*args): # args este un tuple
result = 1
for arg in args:
result *= arg
return result

apeluri cu orici parametrii:

product(1, 2, 3)
product(1, 2, 3, 5, 6, 7)

- Combinaie cu parametru cu nume:

def sum_of_powers(*args, power=1):
result = 0
for arg in args:
result += arg ** power
return result

apeluri:
sum_of_powers(1, 2, 3, 4, power=3)
sum_of_powers(1, 2, 3, 4, 6, 7, 8, power=2)

- * folosit ca si parametru indic c se termina parametrii poziionali:

def heron2(a, b, c, *, units="square meters"):
s = (a + b + c) / 2
area = math.sqrt(s * (s - a) * (s - b) * (s - c))
return "{0} {1}".format(area, units)
apeluri:
heron2(1, 2, 3)
heron2(2, 4, 7, units=cm2)
heron2(2, 4, 7, cm2) # TypeError! trebuie nume pt param.

Exemplu: apel doar cu parametrii cu nume

def print_setup(*, paper="Letter", copies=1, color=False):

- ** operatorul de despachetare dicionar (se genereaza TypeError dac se
apeleaz funcia cu o cheie ce nu este asteptat!):

options = dict(paper="A4", color=True)
print_setup(**options)

Python 3 2012 memIQ
DV1.2 - 16042012
43

- Se poate folosi ** i ca argument:

def add_person_details(ssn, surname, **kwargs):
print("SSN =", ssn)
print(" surname =", surname)
for key in sorted(kwargs):
print(" {0} = {1}".format(key, kwargs[key]))
apel:
add_person_details(2234566, Popescu)
add_person_details(2234566, Ionescu, age=33, forename=Petru)

- Combinaie * si **

def print_args(*args, **kwargs):
for i, arg in enumerate(args):
print("positional argument {0} = {1}".format(i, arg))
for key in kwargs:
print("keyword argument {0} = {1}".format(key,kwargs[key]))


Accesul variabilelor globale

- Exemplu: digit_names.py

Language = "en"
ENGLISH = {0: "zero", 1: "one", 2: "two", 3: "three", 4: "four",
5: "five", 6: "six", 7: "seven", 8: "eight", 9: "nine"}
FRENCH = {0: "zro", 1: "un", 2: "deux", 3: "trois", 4: "quatre",
5: "cinq", 6: "six", 7: "sept", 8: "huit", 9: "neuf"}

- Convenie literele mari sunt folosite pentru numele de constante;

def print_digits(digits):
dictionary = ENGLISH if Language == "en" else FRENCH
for digit in digits:
print(dictionary[int(digit)], end=" ")
print()

Nota: print() are i 3 parametrii keyword:
- sep separator, implicit este ; separ parametrii dai n print
- end sfritul liniei, implicit \n
- file implicit sys.stdout, se poate schimba (fiier)







Python 3 2012 memIQ
DV1.2 - 16042012
44

def main():
if len(sys.argv) == 1 or sys.argv[1] in {"-h", "--help"}:
print("usage: {0} [en|fr] number".format(sys.argv[0]))
sys.exit()
args = sys.argv[1:]
if args[0] in {"en", "fr"}:
global Language # Language este global
Language = args.pop(0) # nu se creeaza o variabila locala
print_digits(args.pop(0))


Funcii Lambda

- forma: lambda params: expresie
- params opional
- expresia nu poate conine cicluri, nu poate avea return
- este o funcie anonim (nu are nume!)
- la apelul funciei lambda se evalueaz expresia

Exemplu:
s = lambda x: "" if x == 1 else "s" # apel cu s()

print("{0} file{1} processed".format(count, s(count)))

- se folosesc ca funcie cheie n functia built-in sorted() sau list.sort()

Exemplu:
elements = [(2, 12, "Mg"), (1, 11, "Na"), (1, 3, "Li"), (2, 4, "Be")]

sorted(elements) # sortare naturala: primul el. din tuplu, daca sunt egale
# se compara al doilea elem din tuple, etc.
putem defini o funcie key:

def ignore0(e):
return e[1], e[2]

sorted(elements, key=ignore0)

putem folosi o expresie lambda ca i funcie key:

elements.sort(key=lambda e: (e[1], e[2]))

elements.sort(key=lambda e: e[1:3])

elements.sort(key=lambda e: (e[2].lower(), e[1]))


Exemplu: apel area(5, 8)

Python 3 2012 memIQ
DV1.2 - 16042012
45

area = lambda b, h: 0.5 * b * h

def area(b, h):
return 0.5 * b * h

Exemplu: pentru valori implicite asociate cheilor inexistente:

minus_one_dict = collections.defaultdict(lambda: -1)
point_zero_dict = collections.defaultdict(lambda: (0, 0))
message_dict = collections.defaultdict(lambda: "No message available")


Aserii

- forma: assert expresie_booleana, expresie_optionala

- funcionare: dac expresie_booleana se evalueaz la False se genereaz
excepia AssertionError la care se paseaz expresie_optionala dac exist

- se folosesc pentru a testa precondiii sau postcondiii, este pentru dezvoltare

- nu este folosit pentru tratarea erorilor obinuite!

Exemplu:

def product(*args): # pessimistic
assert all(args), "0 argument"
result = 1
for arg in args:
result *= arg
return result

def product(*args): # optimistic
result = 1
for arg in args:
result *= arg
assert result, "0 argument"
return result

- runtime se pot dezactiva aseriile: python -O program.py sau setarea variabilei
mediu PYTHONOPTIMIZE pe zero

- dezactivare docstrings: python -OO program.py

- alternativ: livrare surse care comenteaz aseriile


Python 3 2012 memIQ
DV1.2 - 16042012
46

4.4 Exemplu

make_html_skeleton.py


Exerciiu: scriei un program interactiv care ntreine liste de iruri de caractere n
fiiere. Pe fiecare rnd este un ir de caractere.

Se citesc elementele din fiier sau se raporteaz nimic n list dac fiierul este gol
sau este unul nou.
Daca nu sunt elemente se ofer doar opiunile Add, Quit
Daca sunt elemente se arat elementele numerotate de la 1, apoi opiunile Add,
Delete, Save (daca lista nu este salvat), Quit.
Lista se menine sortat cresctor (case insensitive).


Python 3 2012 memIQ
DV1.2 - 16042012
47

5 Module

- Module - grupare cod (funcii, clase) n fiiere n vederea reutilizrii
- Pachete seturi de module grupate din punct de vedere funcional

5.1 Module

- un modul este un fiier .py
- modulele sunt proiectate s fie importate i utilizate
- modulul sys este inclus n limbaj, alte module sunt scrise n alte limbaje de
programare
- import:

import importable
import importable1, importable2, ..., importableN
import importable as preferred_name

- importabil modul, pachet sau modul dintr-un pachet (de ex. import os.path)
- preferred_name se d un nume modulului importat; sub acelai nume se pot
folosi module diferite
- ordine import sugerat: standard, ale altora, proprii
- alte forme de import:

from importable import object as preferred_name
from importable import object1, object2, ..., objectN
from importable import (object1, object2, object3, object4, object5, object6,
..., objectN)
from importable import *

- object variabile, funcii, tipuri de date, module
- . import * - import tot ce nu este privat (se consider private variabilele a
cror nume ncep cu _); dac modulul are o variabil global __all__ ce ine o
list de nume se import aceaste nume

Exemple:

import os
print(os.path.basename(filename)) # safe fully qualified access

import os.path as path
print(path.basename(filename)) # risk of name collision with path

from os import path
print(path.basename(filename)) # risk of name collision with path

from os.path import basename
print(basename(filename)) # risk of name collision with basename
Python 3 2012 memIQ
DV1.2 - 16042012
48


from os.path import *
print(basename(filename)) # risk of many name collisions

- De obicei organizaiile impun reguli de a scrie import-urile (de exemplu se
folosete doar forma cea mai simpl)
- De unde se iau modulele i pachetele importate? sys.path conine o list de
directoare Python path: primul director este cel al programului.
- Variabila mediu PYTHONPATH enumera directoarele unde sunt situate
modulele
- Verificare import (exceptie ImportError dac nu exist): python c import
tst
- Modulele standard folosesc litere mici; ca i convenie modulele definite de
utilizatori se denumesc cu prima liter mare
- .pyo byte code optimizat; .pyc byte code neoptimizat
- Importul presupune compilarea dac nu este deja fcuta
- -O specificat la lansarea programului; generare byte code optimizat (.pyo)
- -B nu se salveaza fisierul .py[oc] (nu se mai poate reutiliza!)
- Variabile sistem care controleaz aceste aspecte: PYTHONOPTIZE,
PYTHONDONTWRITEBYTECOD


5.2 Pachete

Un pachet este un director ce conine module i un fiier numit __init__.py

Exemplu:
- presupunem c avem un set de module ce tiu formate grafice Bmp.py,
Jpeg.py, Tiff.py, Png.py,
- se pun toate fiierele ntr-un director Graphics (aflat n Python path)
- punem un fiier gol n acest director __init__.py
- folosire:
import Graphics.Bmp
image = Graphics.Bmp.load(ex.bmp)
sau
import Graphics.Bmp as Bmp
image = Bmp.load(ex.bmp)
sau
from Graphics import Bmp
image = Bmp.load(ex.bmp)
sau
from Graphics import Bmp as picture
image = picture.load(ex.bmp)

Putem ncrca mai multe module odat punnd n __init__.py

__all__ = [Bmp, Jpeg, Tiff, Png]

Python 3 2012 memIQ
DV1.2 - 16042012
49

Importul:
from Graphics import * # toate modulele specif in __all__
image = Jpeg.load(a.jpeg)

Se poate aplica acest mecanism i pentru module: se definete __all__ la nivelul
modulului cu tot ce se dorete exportat (mai puin numele ce ncep cu _).
Utilizatorii acelui modul pot folosi:

from NumeModul import *

- se vor importa acele nume coninute n lista __all__

Pachetele se pot ncuiba orict de mult; de ex. putem avea un pachet Vector n
pachetul Graphics ce conine Svg.py, Eps.py; Vector are un __init__.py

import Graphics.Vector.Eps
image = Graphics.Vector.Eps.load(x.eps)
sau
import Graphics.Vector.Eps as Eps
image = Eps.load(x.eps)

Din modulul Eps putem importa Png:

import Graphics.Png as Png

sau (import relativ la modulul curent):

from ..Graphics import Png


5.3 Exemplu

TextUtil.py

Import i folosire funcie definit n modul:

import TextUtil.py
.
text = TextUtil.simplify( a fost odata )

Pentru a putea fi disponibil pentru programe:
- Se poate pune n acelai director cu programul care l folosete
- Se poate pune n directorul Python site-packages (modulele din distribuia
Python, este n Python path); /Python31/Lib/site-packages (Windows)
- Se specific n variabila sistem PYTHONPATH directorul n care se afl
modulul
- Se pune n local site-packages (%AppData%/Python/Python31/site-packages)

Python 3 2012 memIQ
DV1.2 - 16042012
50


- Pentru testarea modulului, la sfritul lui:

if __name__ == "__main__":
import doctest
doctest.testmod()

- __name__ conine o valoare ce depinde de modul de utilizare a modulului:
o Conine numele modulului (numele fiierului fr .py) dac modulul
este importat i folosit de alte programe sau module
o Conine numele __main__ dac modulul a fost lansat ca un
program!; n acest caz se vor executa fragmentele de cod (doctests) din
docstrings ale modulului i ale funciilor:

>TestUtil.py -v - pentru a vedea ce se intampla

5.4 Biblioteca standard Python

Aproximativ 200 pachete i module; rezultatul dezvoltrii
Sunt module ntreinute de organizaii


Manipularea irurilor de caractere

Module:
- string
o Constante - string.ascii_letters, string.hexdigits
o Clasa string.Formatter
- textwrap
- struct funcii pentru mpachetare/despachetare numere, Boolean, string
bytes
- difflib compararea secvente
- re regular expression

Exemplu: clasa io.StringIO fiier n memorie

Modaliti de scriere la stdout:
print("Mesaj eroare", file=sys.stdout)
sys.stdout.write("Mesaj eroare\n")

Redirectarea scrierii n memorie:
sys.strdout = io.StringIO()

Obinerea irului din memorie:
io.StringIO.getvalue()

Restaurarea stdout:
sys.stdout = sys.__stdout__
Python 3 2012 memIQ
DV1.2 - 16042012
51

- fileinput pentru procesarea textului venit de la stdin sau fiierele date ca
parametrii n linia de comand; fileinput.input(), fileinput.filename(),
fileinput.lineno()

import fileinput
for line in fileinput.input():
process(line)

- optparse, getopt module pentru parsarea opiunilor de la linia de comand

Exemplu: modul optparse; stil Unix pentru opiuni (forma scurt i forma lung)

def main():
parser = optparse.OptionParser()
parser.add_option("-w", "--maxwidth", dest="maxwidth", type="int",
help=("the maximum number of characters that can be "
"output to string fields [default: %default]"))
parser.add_option("-f", "--format", dest="format",
help=("the format used for outputting numbers "
"[default: %default]"))
parser.set_defaults(maxwidth=100, format=".0f")
opts, args = parser.parse_args()

- -h, --help sunt tratate automat
- Forma scurt -w80 -w 80
- Forma lung --maxwidth=80 --maxwidth 80
- Dac apare o eroare la parsare se apeleaz sys.exit(2) usage error (0 - OK)

Numere i matematic

- Tipuri - decimal.Decimal, fractions.Fraction (pentru numere raionale)
- Module: math, cmath, random
- Modul numbers conine clase abstracte ce reprezint numere, folosite pentru
a testa tipul unui numar:

isinstance(x, numbers.Number)
isinstance(x, numbers.Integral)
isinstance(x, numbers.Complex)

- Modul third party NumPy tablouri n dimensionale, funcii algebrice,
transformri Fourier, unelte pentru integrare cu C/C++, Fortran
- Modulul SciPy extinde NumPy, ofer calcul statistic, procesare de semnale
i de imagini, algoritmi genetici (www.scipy.org)


Timp i data

- Module calendar, datetime
- datetime.datetime are suport pentru time zones
Python 3 2012 memIQ
DV1.2 - 16042012
52

- module third party:
o dateutil (www.labix.org/python-dateutil)
o mxDateTime
(www.egenix.com/products/python/mxBase/mxDateTime )

- modulul time pentru timestamps

Exemplu:

import calendar, datetime, time
moon_datetime_a = datetime.datetime(1969, 7, 20, 20, 17, 40)
moon_time = calendar.timegm(moon_datetime_a.utctimetuple())
moon_datetime_b = datetime.datetime.utcfromtimestamp(moon_time)
moon_datetime_a.isoformat() # returns: '1969-07-20T20:17:40'
moon_datetime_b.isoformat() # returns: '1969-07-20T20:17:40'
time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime(moon_time))

- datetime.datetime.utcnow()
- datetime.datetime.now()
- time.localtime()


Algoritmi i tipuri de date colectie

- modul bisect cutare n secvene sortate, inserare cu pstrarea sortrii
- modulul collections collections.defaultdict, collections.namedtuple,
collections.UserList, collections.UserDict, collections.deque,
collections.OrderedDict, collections.Counter
- modulul array array.array secvent, tipul este restricionat i este de
acelai fel
- modulul weakref referinte weak: dac un obiect este referit doar de o
asemenea referin atunci este distrus de garbage collection
- modul heapq transform o secven n heap/priority queue (elemental de
index 0 este ntotdeauna cel mai mic); operaii de adugare i scoatere

Exemplu:

import heapq
heap = []
heapq.heappush(heap, (5, "rest"))
heapq.heappush(heap, (2, "work"))
heapq.heappush(heap, (4, "study"))

- transformarea unei liste ntr-un heap: heapq.heapify(alist)

for x in heapq.merge([1, 3, 5, 8], [2, 4, 7], [0, 1, 6, 8, 9]):
print(x, end=" ") # prints: 0 1 1 2 3 4 5 6 7 8 8 9


Python 3 2012 memIQ
DV1.2 - 16042012
53

Formate fiier, encodare i persistena datelor

Formate i encodri:
- base64 pentru citire i scriere folosind encodrile Base16, Base32, Base32
(RFC 3548)

Exemplu: base64image.py

o citire fiier png i encodare ntr-un ir de caractere ASCII in BASE64
binary = open(left_align_png, "rb").read()
ascii_text = ""
for i, c in enumerate(base64.b64encode(binary)):
if i and i % 68 == 0:
ascii_text += "\\\n"
ascii_text += chr(c)

o scriere napoi n fiier
binary = base64.b64decode(ascii_text)
open(filename, wb).write(binary)

- quopri citire/scriere n format quoted-printable definit in RFC 1521,
folosit de MIME (Multipurpose Internet Mail Extension).
- uu citire/scriere de date uuencoded pentru transferul de date binare peste
conectii ASCII (7 biti)
- xdrlib citire/scriere a datelor n format External Data Representation
Standard (RFC 1832)


Lucrul cu fisiere arhiva, module:
- bz2
- gzip
- tarfile

Exemplu: untar.py

BZ2_AVAILABLE = True
try:
import bz2
except ImportError:
BZ2_AVAILABLE = False

- zipfile

Fiiere audio, module:
- aifc pentru formatul AIFC (Audio Interchange File Format)
- wave fisiere wav
- audioop
- sndhdr pentru detecia formatului fiierului audio
- configparser - fiiere de configurare (.ini files), RFC 822
Python 3 2012 memIQ
DV1.2 - 16042012
54

- csv fiiere csv

Persistena datelor:
- pickle serializare/deserializare obiecte Python; suporta fisiere DBM
(dicionare n fiiere); chei, valorile sunt bytes sau strings
- shelve fisiere DBM valorile pot fi de orice tip


Manipularea fisierelor, directoarelor si proceselor
- shutil operaii high level pentru manipularea fiierelor i directoarelor;
copy(), copytree(), move(), rmtree()
- tempfile crearea de fiiere temporare
- filecmp compararea de fiiere cmp(), cmpfiles()
- subprocess poate porni alte procese, comunicare cu ele prin pipes
- multiprocessing pentru multi procese
- os acces la funciile OS;
o os.environ map cu variabilele sistem
o os.getcwd() directorul curent de lucru
o os.chdir() schimbare director current
o os.access() test acces la fiier, dac exista
o os.listdir() coninutul unui director
o os.stat() info stare fisier
o os.mkdir(), os.makedirs()
o os.rmdir(), os.removedirs()
o os.remove()
o os.rename()
o os.walk() furnizeaz intrrile unui director
- os.path manipulare stringuri ce reprezint path-uri:
o abspath()
o split()
o basename(), dirname()
o splitext()
o join()
o exists()
o getsize()
o isfile(), isdir()

Exemplu: creare dictionary; cheie = nume fisier, valoare = timestamp ultima
modificare:

date_from_name = {}
for name in os.listdir(path): # pt recursiv walk()
fullname = os.path.join(path, name)
if os.path.isfile(fullname):
date_from_name[fullname] = os.path.getmtime(fullname)

vezi i finddup.py


Python 3 2012 memIQ
DV1.2 - 16042012
55

Programare networking si Internet

- socket nivel jos creare sockets, mapare nume cu DNS (Domain Name
System), folosire adrese IP (Internet Protocol)
- ssl sockets criptate i autentificare
- socketserver ofer servere TCP (Transmission Control Protocol) i UDP
(User Datagram Protocol)
- asyncore, asynchat tratarea asincron a socketurilor client i server

WSGI (Web Server Gateway Interface) interfaa standard ntre serverele
web i aplicaiile web scrise n Python

- pachetul wsgiref ofera o implementare de referinta a WSGI pentru un
framerwork sau server web
- http.server defineste clase pentru implementarea de servere http
- http.cookies, http.cookiejar gestiunea cookies
- cgi, cgitb suport pentru CGI (Common Gate Interface)
- cgi.client suport pentru implementare client HTTP
- pachetul urllib de nivel nalt cu module parse, request, response, error,
robotparser:

fh = urllib.request.urlopen("http://www.python.org/index.html")
html = fh.read().decode("utf8")
urllib.request.urlretrive() copiaz local un fiier remote

- html.parser parsare HTML si XHTML
- json date reprezentate folosind JSON (Javascript Object Notation)
- xmlrpc.server, xmlrpc.client suport pentru XML-RPC (Remote Procedure
Call)
- ftplib suport pentru FTP
- nntplib suport pentru NNTP (Network News Transfer Protocol)
- telnetlib suport TELNET
- smtpd SMTP (Simple Mail Transfer Protocol)
- imaplib IMAP4 (Internet Message Access Protocol)
- poplib POP3 (Post Office Protocol)
- mailbox tipuri de mailboxes
- email crearea i manipularea mesajelor de e-mail

Third party libraries:
- www.twistematrix.com networking
- www.djangoproject.com web programming
- www.turbogears.org web apps
- www.plone.org, www.zope.org web frameworks and content management
systems

XML
Abordari:
- DOM (Document Object Model)
o xml.dom
Python 3 2012 memIQ
DV1.2 - 16042012
56

o xml.dom.minidom
- SAX (Simple API for XML)
o xml.sax
o xml.sax.saxutils (am folosit deja functia escape() )

Alte parsere:
- xml.parsers.expat
- xml.etree.ElementTree

Third party module:
- lxml www.codespeak.net/lxml

Exemplu:

<station>
<station_id>KBOS</station_id>
<state>MA</state>
<station_name>Boston, Logan International Airport</station_name>
...
<xml_url>http://weather.gov/data/current_obs/KBOS.xml</xml_url>
</station>


tree = xml.etree.ElementTree.ElementTree()
root = tree.parse(fh) # fisier XML
stations = []
for element in tree.getiterator("station_name"):
stations.append(element.text)

Alte module

- unittest framework pentru unit testing (versiune Python a JUnit din Java)
- py.test codespeak.net/py/dist/test/test.html
- nose code.google.com/p/python-nose

- logging sistem de logging

- pprint preatty printing

- inspect introspect obiecte

- threading fire de execuie

- queue thread-safe queue

- tkinter folosete biblioteca Tk pentru GUI

- abc Abstract Base Class funcii pentru a crea clase de baz abstracte

Python 3 2012 memIQ
DV1.2 - 16042012
57

- copy fct copy(), deepcopy()

- ctype acces la funcii din dll-uri; C API crearea de tipuri i funcii n C


Exerciiu: scriei un program ce arat coninutul unui director (dir sau ls):

Usage: ls.py [options] [path1 [path2 [... pathN]]]
[] opional; dac nu se specific director se consider . (directorul curent)

Opiuni:
-h, --help arat un mesaj de help i iese
-H, --hidden arat fiierele ascunse [default: off]
-m, --modified arat data i ora ultimei modificri [default: off]
-o ORDER, --order=ORDER
Ordonare dup ('name', 'n', 'modified', 'm', 'size', 's') [default: name]
-r, --recursive parcurge recursiv subdirectoarele [default: off]
-s, --sizes arat lungimea fiierelor [default: off]

Apel:
ls.py -ms -os misc/

2008-02-11 14:17:03 12,184 misc/abstract.pdf
2008-02-05 14:22:38 109,788 misc/klmqtintro.lyx
2007-12-13 12:01: 14 1,359,950 misc/tracking.pdf
misc/phonelog/
3 files, 1 directory


- se va folosi modulul optparse pentru a parsa opiunile
- pentru recursivitate os.walk(), altfel os.listdir()



Python 3 2012 memIQ
DV1.2 - 16042012
58

6 Programare orientat pe obiecte

Python nu impune un stil anume de programare: procedural, orientat pe obiecte sau
funcional.
6.1 Concepte OO

Tip definit de utilizator clasa obiecte (instan).

Clasa ncapsuleaz date i metode

Se implementeaz metode speciale de forma __f__() pentru a oferi suport pentru
operaii cu obiecte; ex: __len__() pentru suport dat lui len(), __add__() pentru
operatorul +, etc.

Termene folosite: superclasa (sau clasa de baz), subclasa (sau clasa derivat)

Polimorfism

Clasa object printele oricrei clase Python

Excepii Python:
- Nu exist suprancrcarea numelor de funcii (funciile pot primi parametrii
diferii)
- Nu exist mecanism pentru a avea date private

6.2 Clase definite de utilizator

class className:
suite

class className(base_classes):
suite

Ca i la def func se va construi clasa dinamic, n momentul ntlnirii enunului

Exemplu: Shape.py clasa Point i Circle

Point subclas a lui object (nu se specific printele)
Folosire:

import Shape

a = Shape.Point()
repr(a) # returns: 'Point(0, 0)'
b = Shape.Point(3, 4)
Python 3 2012 memIQ
DV1.2 - 16042012
59

str(b) # returns: '(3, 4)'
b.distance_from_origin() # returns: 5.0
b.x = -19
str(b) # returns: '(-19, 4)'
a == b, a != b # returns: (False, True)

Point are:
- dou atribute: self.x, self.y; se pot accesa direct din afara obiectului
- 5 metode, 4 din ele sunt speciale (ncep cu __ )

Suport pentru operatorul de egalitate == , forma string

Python furnizeaz primul argument la apelul metodelor self

Creare obiect se face n 2 pai:
- se creeaz un obiect; se apleaz __new__(); de obicei metoda motenit din
object este suficient
- obiectul se initializeaz; se apeleaz __init__()

Se poate folosi n __init__():

super().__init__()

Metodele cu forma __func__() sunt predefinite, nu se folosesc pentru metode
obinuite; suport pentru evaluare expresii obj1 == obj2!

__lt__(self, other) x < y Returns True if x is less than y
__le__(self, other) x <= y Returns True if x is less than or equal to y
__eq__(self, other) x == y Returns True if x is equal to y
__ne__(self, other) x != y Returns True if x is not equal to y
__ge__(self, other) x >= y Returns True if x is greater than or equal to y
__gt__(self, other) x > y Returns True if x is greater than y

Daca furnizm __eq__(), dar nu se definete __ne__(), Python va genera unul

Cum se poate evita compararea unui Point cu orice altceva?
Metode:
1. assert isinstance(other, Point)
2. if not isinstance(other, Point): raise TypeError()
3. if not isinstance(other, Point): return NotImplemented
In acest caz Python va ncerca i other.__eq__(self) dac se ntoarce tot
NotImplemented Python va genera excepia TypeError

Funcia built-in repr() apeleaz __repr__(self); se returneaz un string care dac este
pasat funciei built-in eval() va recrea obiectul:

p = Shape.Point(3, 9)
repr(p) # returns: 'Point(3, 9)'
q = eval(p.__module__ + "." + repr(p))
Python 3 2012 memIQ
DV1.2 - 16042012
60

repr(q) # returns: 'Point(3, 9)'

Atributul __module__ ine numele modulului n care este definit clasa obiectului
Funcia built-in str() apeleaza __str__() returneaz un string destinat oamenilor


Motenire i polimorfism

Clasa Circle motenete clasa Point:
- adaug un atribut data radius
- 3 noi metode

__init__() iniializarea prii motenite cu super().__init__(x,y)


Proprieti

Vezi ShapeAlt.py

Folosire:
Circle = Shape.Circle(5, 7, 10)
Circle.radius
Circle.edge_distance_from_origin

Implementare proprieti:

@property # @ - decorator
def area(self):
return math.pi * (self.radius ** 2)

- getter, proprietate read-only

- decorator primete o funcie i returneaz o variant decorat - proprietate

- funcia decorator built-in: property(), primete 4 argumente:
o o funcie getter
o o funcie setter
o o funcie de tergere
o un docstring
- efectul lui @property este la fel ca apelul funciei property() la care se d doar
o funcie getter
- echivalentul sintaxei @property:

def area(self):
return math.pi * (self.radius ** 2)
area = property(area)

- transformare atribut n proprieti read/write (setter-ul se definete pentru
validare):
Python 3 2012 memIQ
DV1.2 - 16042012
61

@property
def radius(self):
"""
The circle's radius

>>> circle = Circle(-2)
Traceback (most recent call last):
...
AssertionError: radius must be nonzero and non-negative
>>> circle = Circle(4)
>>> circle.radius = -1
Traceback (most recent call last):
...
AssertionError: radius must be nonzero and non-negative
>>> circle.radius = 6
"""
return self.__radius

@radius.setter
def radius(self, radius):
assert radius > 0, "radius must be nonzero and non-negative"
self.__radius = radius

__radius este privat!

Se prefer atribute n loc de metode seter & geter ca n alte limbaje fiindc nu
afecteaz utilizatorul clasei.

n Circle init va apela atributul radius pentru iniializare!

def __init__(self, radius, x=0, y=0):
super().__init__(x, y)
self.radius = radius


Exemplu: clasa FuzzyBool (vezi FuzzyBool.py)
- False 0.0; True 1.00; 0.25 25% True
- Folosire:
a = FuzzyBool.FuzzyBool(.875)
b = FuzzyBool.FuzzyBool(.25)
a >= b # returns: True
bool(a), bool(b) # returns: (True, False)
~a # returns: FuzzyBool(0.125)
a & b # returns: FuzzyBool(0.25)
b |= FuzzyBool.FuzzyBool(.5) # b is now: FuzzyBool(0.5)
"a={0:.1%} b={1:.0%}".format(a, b) # returns: 'a=87.5% b=50%'

- Cerine:
o Suport pentru toi operatorii de comparare - < <= == != >= >
Python 3 2012 memIQ
DV1.2 - 16042012
62

o Operatori logici - ~ & |
o conjuction(), disjunction()
o conversii la bool, int, float, str
o s suporte specificatorul de format

- Implementare 1 from scratch (FuzzyBool.py):
o __value privat
o __invert__() ~ (not)
o __and__() & (and)
o __iand__() - &= (i in place) - return self !!
o __rand__() - r reflected ordinea operanzilor este inversata
o __repr__() forma reprezentaional
obj.__class__ - referin la obiectul clas a obiectului,
dictionar: __name_, __module__(modulul n care este
definit), __bases__(clasele de baza), __doc__ (docstring),
__dict__ (dicionar cu spaiul de nume al clasei)
o __str__() - conversii la string
o __bool__()
o __int__()
o __float__()
o __lt__() - comparaii; suficient < <= ==
o __eq__()
o __hash__()

Implicit clasele definite de utilizator ofer operatorul == (ce ntoarce
intotdeauna False) i sunt hashable (se pot folosi ca i chei n
dicionare sau include n mulimi). Dac se reimplementeaz __eq__()
instanele nu mai sunt hash-abile; Soluia este s reimplementm i
__hash__().

Python ofer funcii hash pentru strings, numere, frozen sets, alte clase.
Funcia hash() folosete __hash__() a obiectului pe care se aplic.

__hash__() trebuie s intoarc o valoare care nu se schimb, nu se
poate folosi self.__value; funcia built-in id() returneaz un ntreg unic
pentru obiectul dat ca parametru (adresa n memorie).

o __format__(self, format_spec) folosit de funcia built-in format()

Toate clasele built-in au deja __format__(), implementarea noastra
foloseste funcia format a lui float.

o @staticmethod - decorator

Functia built-in staticmethod() se folosete ca i decorator; nu
primete automat self ca i parametru.

Se apeleaz pe baza clasei sau a unui obiect.

Python 3 2012 memIQ
DV1.2 - 16042012
63

o Exist i date statice (la nivel de clas) dac sunt definite n afara
metodelor, n cadrul clasei.

Constantele se implementeaz de obicei la nivelul modulelor ca i globale private.

Implementare 2 - pe baza de motenire a float vezi FuzzyBoolAlt.py

o Metodele statice au devenit funcii modul

o __new__(cls, value=0.0) ; noile clase de obicei folosesc
object. __new__()

Este o metod static (nu primeste self, primete clasa)!

Crearea unui obiect presupune apel:
__new__(FyzzyBool, 0.3)
__init__(0.3)

Funcia built-in classmethod() este un decorator pentru metode,
specific c metoda primete referina la clas automat (nu referina la
obiect, self!); pentru __new__() nu trebuie spus @classmethod,
Python tie de aceast funcie

o Prin motenire din float se primesc o mulime de funcii ce nu au
sens; pentru a nu se folosi (undefined!) pentru acestea se folosete
stereotipul:

def __add__(self, other):
raise NotImplementedError()

Se poate genera si TypeError (stil Python):

def __add__(self, other):
raise TypeError("unsupported operand type(s) for +: "
"'{0}' and '{1}'".format(
self.__class__.__name__, other.__class__.__name__))

Pentru operatori de comparare (Python va ncerca s foloseasc ==
rotind operatorii, apoi genereaza TypeError):

def __eq__(self, other):
return NotImplemented

Tehnica pentru neimplementarea de metode motenite, de exemplu
pentru operaii unare (vezi FuzzyBoolalt.py):

for name, operator in (("__neg__", "-"), ("__index__", "index()")):
message = ("bad operand type for unary {0}: '{{self}}'"
.format(operator))
Python 3 2012 memIQ
DV1.2 - 16042012
64

exec("def {0}(self): raise TypeError(\"{1}\".format("
"self=self.__class__.__name__))".format(name, message))

- Funcia built-in exec() execut dinamic codul pasat prin obiectul primit ca
parametru (de obicei string).
- Codul se execut n contextual curent, n acest caz este n clasa FuzzyBool, se
vor crea dinamic funciile cu def; se execut o singur data, cnd se import
modulul; se genereaz:

def __neg__(self):
raise TypeError("bad operand type for unary -: '{self}'"
.format(self=self.__class__.__name__))

- Similar se trateaz metodele binare pe care dorim sa le unsupport; un
exemplu de funcie generate:

def __xor__(self, *args):
types = ["'" + arg.__class__.__name__ + "'" for arg in args]
raise TypeError("unsupported operand type(s) for ^: "
"'{self}'{join} {args}".format(
self=self.__class__.__name__,
join=(" and" if len(args) == 1 else ","),
args=", ".join(types)))

- Metodele nedorite vor genera excepie


6.3 Clase colecie personalizate

Clase ce folosesc colecii

Exemplu: Image.py
- Imagine 2D
- Culoare background
- Culorile punctelor diferite de background dictionar cu cheie (x, y), valoare
culoare
- Folosire:

border_color = "#FF0000" # red
square_color = "#0000FF" # blue
width, height = 240, 60
midx, midy = width // 2, height // 2
image = Image.Image(width, height, "square_eye.img")
for x in range(width):
for y in range(height):
if x < 5 or x >= width - 5 or y < 5 or y >= height - 5:
image[x, y] = border_color
elif midx - 20 < x < midx + 20 and midy - 20 < y < midy + 20:
Python 3 2012 memIQ
DV1.2 - 16042012
65

image[x, y] = square_color
image.save()
image.export("square_eye.xpm")

- Toate atributele dat sunt private (precedate prin __), mai puin filename
- Proprieti (get): background, width, height, colors
o Trebuie avut n vedere dac atributul este imutabil sau mutabil; pentru
cele mutabile se poate prefera s se furnizeze o copie pentru a nu se
modifica direct proprietatea vezi proprietatea colors
- Aplicarea operatorului [] la obiect:

def __getitem__(self, coordinate):
assert len(coordinate) == 2, "coordinate should be a 2-tuple"
if (not (0 <= coordinate[0] < self.width) or
not (0 <= coordinate[1] < self.height)):
raise CoordinateError(str(coordinate))
return self.__data.get(tuple(coordinate), self.__background)

def __setitem__(self, coordinate, color):
assert len(coordinate) == 2, "coordinate should be a 2-tuple"
if (not (0 <= coordinate[0] < self.width) or
not (0 <= coordinate[1] < self.height)):
raise CoordinateError(str(coordinate))
if color == self.__background:
self.__data.pop(tuple(coordinate), None)
else:
self.__data[tuple(coordinate)] = color
self.__colors.add(color)

def __delitem__(self, coordinate):
assert len(coordinate) == 2, "coordinate should be a 2-tuple"
if (not (0 <= coordinate[0] < self.width) or
not (0 <= coordinate[1] < self.height)):
raise CoordinateError(str(coordinate))
self.__data.pop(tuple(coordinate), None)

Metode speciale:

__contains__(self, x) x in y Returns True if x is in sequence y or if
x is a key in mapping y
__delitem__(self, k) del y[k] Deletes the k-th item of sequence y or
the item with key k in mapping y
__getitem__(self, k) y[k] Returns the k-th item of sequence y or
the value for key k in mapping y
__iter__(self) for x in y: Returns an iterator for sequence ys
pass items or mapping ys keys
__len__(self) len(y) Returns the number of items in y
__reversed__(self) reversed(y) Returns a backward iterator for sequence
ys items or mapping ys keys
Python 3 2012 memIQ
DV1.2 - 16042012
66

__setitem__(self, k, v) y[k] = v Sets the k-th item of sequence y or the
value for key k in mapping y, to v

reactualizare culori folosite:
self.__colors = (set(self.__data.values()) | {self.__background})

- Serializare pickling in Python; nu exist securitate
save(), load() vezi sursa
pickle.dump() - formate (protocol: 0 ASCII, 3 HIGHEST_PROTOCOL)
- export() - format XPM (X Pixmap)


Exemplu: SortedList

- similar cu list
- pentru sortare se folosete operatorul < ( __lt__() ) aplicat elementelor din list
sau o funcie key, dac este furnizat
- se vor furniza metodele oferite de list care au sens
- folosire:

letters = SortedList.SortedList(("H", "c", "B", "G", "e"), str.lower)
# str(letters) == "['B', 'c', 'e', 'G', 'H']"
letters.add("G") # modificare doar cu add
letters.add("f")
letters.add("A")
# str(letters) == "['A', 'B', 'c', 'e', 'f', 'G', 'G', 'H']"
letters[2] # returns: 'c' (__getitem__())
del letters[2] # tergere element (__delitem__())

- iniializare:

def __init__(self, sequence=None, key=None):
self.__key = key or _identity # self.__key = key if key
# is not None else _identity
assert hasattr(self.__key, "__call__")
if sequence is None:
self.__list = []
elif (isinstance(sequence, SortedList) and
sequence.key == self.__key):
self.__list = sequence.__list[:] # self.__list = seq.__list!!
else:
self.__list = sorted(list(sequence), key=self.__key)

- numele funciei este o referin la un obiect self.__key funcie exterioar
de ordonare; aceste obiecte funcie au un atribut __call__

- add(self, value); _bisect_left(self, value)

- remove(self, value); remove_every(self, value)
Python 3 2012 memIQ
DV1.2 - 16042012
67


- count(self, value), index(self, value)

- __delitem__(self, index); apelat la del L[index]

- __getitem__(self, index); apelat la L[index]

- __setitem__(self, index, value) excepie

- __iter__(self); apelat de iter(L) folosit pentru for value in iterable

- __reversed__(self); apelat de reversed(L)

- __contains__(self, value); support pentru operatorul in

- clear(self), pop(self, index=1), __len__(self), __str__(self)

- __copy__ = copy; __copy__ este apelat de copy.copy()


Exemplu: SortedDict un dict care ine cheile sortate; motenete dict!

Nota: collections.OrderedDict ine cheile n ordinea inserrii

- Folosire:

d = SortedDict.SortedDict(dict(s=1, A=2, y=6), str.lower)
d["z"] = 4
d["T"] = 5
del d["y"]
d["n"] = 3
d["A"] = 17
str(d) # returns: "{'A': 17, 'n': 3, 's': 1, 'T': 5, 'z': 4}"


- Definire:

class SortedDict(dict):

def __init__(self, dictionary=None, key=None, **kwargs):
dictionary = dictionary or {}
super().__init__(dictionary)
if kwargs:
super().update(kwargs)
self.__keys = SortedList.SortedList(super().keys(), key) # chei
# sortate

update(self, dictionary=None, **kwargs) - actualizare cu un dictionar i/sau
parametrii cu nume
Python 3 2012 memIQ
DV1.2 - 16042012
68


dict.fromkeys() crearea unui dict pe baza unui iterabil; metoda clas

d[key] = value - adugare intrare n dictionary:

def __setitem__(self, key, value):
if key not in self:
self.__keys.add(key)
return super().__setitem__(key, value)
__getitem__() -- nu se reimplementeaza fiindca este OK metoda motenit

def __delitem__(self, key): # del d[key]
try:
self.__keys.remove(key)
except ValueError:
raise KeyError(key)
return super().__delitem__(key)


def setdefault(self, key, value=None):
if key not in self:
self.__keys.add(key)
return super().setdefault(key, value)


def pop(self, key, *args):
if key not in self:
if len(args) == 0:
raise KeyError(key)
return args[0]
self.__keys.remove(key)
return super().pop(key, args)


popitem(), clear()

Iteratori:
def values(self): # functie generator
for key in self.__keys:
yield self[key]

def items(self): # functie generator
for key in self.__keys:
yield (key, self[key])

def __iter__(self):
return iter(self.__keys)

keys = __iter__
Python 3 2012 memIQ
DV1.2 - 16042012
69





Nota: funcii generator
funcii ce conin o expresie yield
Furnizeaz elementele pe rnd la cerere
Cod echivalent, folosit n for letter in letter_range(a, m):

# Build and return a list
def letter_range(a, z):
result = []
while ord(a) < ord(z):
result.append(a)
a = chr(ord(a) + 1)
return result

# Return each value on demand
def letter_range(a, z):
while ord(a) < ord(z):
yield a
a = chr(ord(a) + 1)


def __str__(self):
return ("{" + ", ".join(["{0!r}: {1!r}".format(k, v)
for k, v in self.items()]) + "}")
echivalent cu:

items = []
for key, value in self.items():
items.append("{0!r}: {1!r}".format(key, value))
return "{" + ", ".join(items) + "}"


- Rmn la fel: dict.get(), __getitem__(), __len__(), __contains__()

def copy(self):
d = SortedDict()
super(SortedDict, d).update(self) # echiv. dict.update(d, self)
d.__keys = self.__keys.copy()
return d

super() se refer la clasa printe i obiectul curent

- din cauz c avem cheile sortate putem accesa dicionarul dup index (get i
set):

def value_at(self, index):
Python 3 2012 memIQ
DV1.2 - 16042012
70

return self[self.__keys[index]]

def set_value_at(self, index, value):
self[self.__keys[index]] = value



Exercitii:
1. Modificai clasa Point (din Shape.py sau ShapeAlt.py) pentru a suporta
urmtoarele operaii; p, q, r sunt Point, n este numr:
p = q + r # Point.__add__()
p += q # Point.__iadd__()
p = q - r # Point.__sub__()
p -= q # Point.__isub__()
p = q * n # Point.__mul__()
p *= n # Point.__imul__()
p = q / n # Point.__truediv__()
p /= n # Point.__itruediv__()
p = q // n # Point.__floordiv__()
p //= n # Point.__ifloordiv__()

Adugai la fiecare funcie un doctest

2. Adugai la clasa Image o metod resize(width, height). Dac o dimensiune este
mai mic dect cea curenta imaginea se va tia, dac sunt mai mari se consider
c noua zon are culoarea background-ului, dac este None se va pstra
dimensiunea.
Metoda returneaz un Boolean dac Imaginea a suferit modificri.

3. Construii o clas Transaction ce reprezint o tranzacie pe un cont bancar.
Atribute: data, suma, moneda, rata conversie, descriere.

4. Construii clasa Account numar, nume, lista de Transactions
Metode:
o len numrul de tranzacii
o balance
o apply pentru a aduga o tranzacie
o save, load ntr-un fiier cu extensia .acc



Python 3 2012 memIQ
DV1.2 - 16042012
71

7 Lucrul cu fiierele

- Independent de platform
- Dou formate fiier de baz:
o Binar
o Text
- Se vor exemplifica mecanismele pe acelai exemplu salvarea i restaurarea
unei colecii; record:

Nume Data Note
report_id str Minimum length 8 and no whitespace
date datetime.date
airport str Nonempty and no newlines
aircraft_id str Nonempty and no newlines
aircraft_type str Nonempty and no newlines
pilot_percent_hours_on_type float Range 0.0 to 100.0
pilot_total_hours int Positive and nonzero
midair bool
narrative str Multiline

Exemplu: convert-incidents.py

- Folosire:

convert-incidents.py [options] infile outfile

Citeste fiierul cu incidente infile i scrie datele la outfile. Formatul de date
depinde de extensia fiierelor:
o aix XML
o ait - text (UTF-8 encoding)
o aib - binar
o aip pickle
o html HTML (permis doar pentru outfile)

Opiuni:
-h, --help arat mesajul de help
-f, --force - scrie outfile chiar dac exist [default: off]
-v, --verbose raporteaz rezultatele [default: off]
-r READER, --reader=READER
reader (XML): 'dom', 'd', 'etree', 'e', 'sax', 's'
reader (text): 'manual', 'm', 'regex', 'r'
[default: etree pentru XML, manual pentru text]
-w WRITER, --writer=WRITER
writer (XML): 'dom', 'd', 'etree', 'e',
'manual', 'm' [default: manual]
-z, --compress compress .aib/.aip outfile [default: off]
-t, --test executa doctests si termina (se folosete -v pentru verbose)

Python 3 2012 memIQ
DV1.2 - 16042012
72

- class IncidentError pentru excepii
- class Incident pentru un incident; proprieti RW, mai puin pentru report_id
- class IncidentCollection(dict); cheie report id; valoare asociat Incident


7.1 Fiiere binare
- Ocup cel mai puin spaiu, de obicei sunt cele mai rapide


Pickles cu compresie opional

Cea mai simpl soluie pentru salvarea i ncrcarea datelor din programele Python.
Nu exist securitate.

def export_pickle(self, filename, compress=False):
fh = None
try:
if compress:
fh = gzip.open(filename, "wb")
else:
fh = open(filename, "wb")
pickle.dump(self, fh, pickle.HIGHEST_PROTOCOL)
return True
except (EnvironmentError, pickle.PicklingError) as err:
print("{0}: export error: {1}".format(
os.path.basename(sys.argv[0]), err))
return False
finally:
if fh is not None:
fh.close()

Pentru citire:

def import_pickle(self, filename):
fh = None
try:
fh = open(filename, "rb")
magic = fh.read(len(GZIP_MAGIC))
if magic == GZIP_MAGIC:
fh.close()
fh = gzip.open(filename, "rb")
else:
fh.seek(0)
self.clear()
self.update(pickle.load(fh))
return True
except (EnvironmentError, pickle.UnpicklingError) as err:
print("{0}: import error: {1}".format(
Python 3 2012 memIQ
DV1.2 - 16042012
73

os.path.basename(sys.argv[0]), err))
return False
finally:
if fh is not None:
fh.close()


Not tipurile bytes si bytearray

- bytes imutabil
- secventa de intregi pe 8 biti fara semn (0..255)
- similar cu str
- slicing produce acelai tip
- accesul prin [] returneaz un int

word = b"Animal"
x = b"A"
word[0] == x # False # word[0] == 65; x == b"A"
word[:1] == x # True


Binar cu compresie opional

- control complet asupra scrierii/citirii
- magic number, pentru recunoaterea formatului:

MAGIC = b"AIB\x00"
FORMAT_VERSION = b"\x00\x01"

- conversia obiecte Python n reprezentare binar modulul struct:

o struct.pack() construiete un obiect de tip bytes din valorile pasate
o struct.unpack() extrage valorile mpachetate
o exemplu:

data = struct.pack("<2h", 11, -9) # data == b'\x0b\x00\xf7\xff'
items = struct.unpack("<2h", data) # items == (11, -9)

o caractere format:
b 8 bit signed integer
B 8 bit unsigned integer
H, h 16 bit integer
I, i 32 bit int
Q, q 64 bit int
f - 32 bit float
d 64 bit float
? Boolean
s bytes sau bytearray
Python 3 2012 memIQ
DV1.2 - 16042012
74

o endianess ordinea bytes; se poate allege < (little, Intel, AMD) sau >
(sau !)

TWO_SHORTS = struct.Struct("<2h")
data = TWO_SHORTS.pack(11, -9) # data == b'\x0b\x00\xf7\xff'
items = TWO_SHORTS.unpack(data) # items == (11, -9)

- export_binary() vezi sursa:

def export_binary(self, filename, compress=False):

def pack_string(string):
data = string.encode("utf8")
format = "<H{0}s".format(len(data))
return struct.pack(format, len(data), data)


NumbersStruct = struct.Struct("<Idi?")

- import_binary() vezi sursa:

def import_binary(self, filename):

def unpack_string(fh, eof_is_error=True):
uint16 = struct.Struct("<H")
length_data = fh.read(uint16.size)
if not length_data:
if eof_is_error:
raise ValueError("missing or corrupt string size")
return None
length = uint16.unpack(length_data)[0]
if length == 0:
return ""
data = fh.read(length)
if not data or len(data) != length:
raise ValueError("missing or corrupt string")
format = "<{0}s".format(length)
return struct.unpack(format, data)[0].decode("utf8")


7.2 Fiiere text

Format folosit (cheie=valoare; pentru cmpurile multilinie se folosesc markere):

[20070927022009C]
date=2007-09-27
aircraft_id=1675B
aircraft_type=DHC-2-MK1
Python 3 2012 memIQ
DV1.2 - 16042012
75

airport=MERLE K (MUDHOLE) SMITH
pilot_percent_hours_on_type=46.1538461538
pilot_total_hours=13000
midair=0
.NARRATIVE_START.
ACCORDING TO THE PILOT, THE DRAG LINK FAILED DUE
TO AN OVERSIZED TAIL WHEEL TIRE LANDING ON HARD
SURFACE.
.NARRATIVE_END.


Scriere text (vezi sursa):

def export_text(self, filename):
wrapper = textwrap.TextWrapper(initial_indent=" ",
subsequent_indent=" ")
fh = None
try:
fh = open(filename, "w", encoding="utf8")
for incident in self.values():
narrative = "\n".join(wrapper.wrap(
incident.narrative.strip()))
fh.write("[{0.report_id}]\n"
"date={0.date!s}\n"
"aircraft_id={0.aircraft_id}\n"
"aircraft_type={0.aircraft_type}\n"
"airport={airport}\n"
"pilot_percent_hours_on_type="
"{0.pilot_percent_hours_on_type}\n"
"pilot_total_hours={0.pilot_total_hours}\n"
"midair={0.midair:d}\n"
".NARRATIVE_START.\n{narrative}\n"
".NARRATIVE_END.\n\n".format(incident,
airport=incident.airport.strip(),
narrative=narrative))
return True


Citirea textului (vezi sursa):

def import_text_manual(self, filename):

fh = None
try:
fh = open(filename, encoding="utf8")
self.clear()
data = {}
narrative = None

for lino, line in enumerate(fh, start=1):
Python 3 2012 memIQ
DV1.2 - 16042012
76

line = line.rstrip()
if not line and narrative is None:
continue
if narrative is not None:
if line == ".NARRATIVE_END.":
data["narrative"] = textwrap.dedent(
narrative).strip()
if len(data) != 9:
raise IncidentError("missing data on "
"line {0}".format(lino))
incident = Incident(**data)
self[incident.report_id] = incident
data = {}
narrative = None
else:
narrative += line + "\n"
elif (not data and line[0] == "["
and line[-1] == "]"):
data["report_id"] = line[1:-1]
elif "=" in line:
key, value = line.split("=", 1)
if key == "date":
data[key] = datetime.datetime.strptime(value,
"%Y-%m-%d").date()
elif key == "pilot_percent_hours_on_type":
data[key] = float(value)
elif key == "pilot_total_hours":
data[key] = int(value)
elif key == "midair":
data[key] = bool(int(value))
else:
data[key] = value
elif line == ".NARRATIVE_START.":
narrative = ""
else:
raise KeyError("parsing error on line {0}".format(
lino))


Folosirea expresiilor regulate pentru citire text

r raw string

def import_text_regex(self, filename):

incident_re = re.compile(
r"\[(?P<id>[^]]+)\](?P<keyvalues>.+?)"
r"^\.NARRATIVE_START\.$(?P<narrative>.*?)"
r"^\.NARRATIVE_END\.$",
Python 3 2012 memIQ
DV1.2 - 16042012
77

re.DOTALL | re.MULTILINE)
key_value_re = re.compile(r"^\s*(?P<key>[^=]+?)\s*=\s*"
r"(?P<value>.+?)\s*$", re.MULTILINE)

fh = None
try:
fh = open(filename, encoding="utf8")
self.clear()
for incident_match in incident_re.finditer(fh.read()):
data = {}
data["report_id"] = incident_match.group("id")
data["narrative"] = textwrap.dedent(
incident_match.group("narrative")).strip()
keyvalues = incident_match.group("keyvalues")
for match in key_value_re.finditer(keyvalues):
data[match.group("key")] = match.group("value")
data["date"] = datetime.datetime.strptime(
data["date"], "%Y-%m-%d").date()
data["pilot_percent_hours_on_type"] = (
float(data["pilot_percent_hours_on_type"]))
data["pilot_total_hours"] =int(data["pilot_total_hours"])
data["midair"] = bool(int(data["midair"]))
if len(data) != 9:
raise IncidentError("missing data")
incident = Incident(**data)
self[incident.report_id] = incident
return True


7.3 Fiiere XML

Metode de a scrie XML:
- Manual
- Element Tree + write()
- DOM + write()

Citire XML:
- Manual
- Element Tree
- DOM
- SAX

Element Tree
Etape la scriere:
- Se creeaz un element tree ce reprezint data
- Element tree se scrie n fiier
def export_xml_etree(self, filename):
root = xml.etree.ElementTree.Element("incidents")
Python 3 2012 memIQ
DV1.2 - 16042012
78

for incident in self.values():
element = xml.etree.ElementTree.Element("incident",
report_id=incident.report_id,
date=incident.date.isoformat(),
aircraft_id=incident.aircraft_id,
aircraft_type=incident.aircraft_type,
pilot_percent_hours_on_type=str(
incident.pilot_percent_hours_on_type),
pilot_total_hours=str(incident.pilot_total_hours),
midair=str(int(incident.midair)))
airport = xml.etree.ElementTree.SubElement(element,
"airport")
airport.text = incident.airport.strip()
narrative = xml.etree.ElementTree.SubElement(element,
"narrative")
narrative.text = incident.narrative.strip()
root.append(element)
tree = xml.etree.ElementTree.ElementTree(root)

try:
tree.write(filename, "UTF-8")
except EnvironmentError as err:
print("{0}: import error: {1}".format(
os.path.basename(sys.argv[0]), err))
return False
return True

Etape la citire:
- Citirea i parsarea fiierului XML
- Traversarea element tree i popularea dicionarul de incidente

def import_xml_etree(self, filename):
try:
tree = xml.etree.ElementTree.parse(filename)
except (EnvironmentError, xml.parsers.expat.ExpatError) as err:
print("{0}: import error: {1}".format(
os.path.basename(sys.argv[0]), err))
return False
self.clear()
for element in tree.findall("incident"):
try:
data = {}
for attribute in ("report_id", "date", "aircraft_id",
"aircraft_type", "pilot_percent_hours_on_type",
"pilot_total_hours", "midair"):
data[attribute] = element.get(attribute)
data["date"] = datetime.datetime.strptime(
data["date"], "%Y-%m-%d").date()
data["pilot_percent_hours_on_type"] = (
Python 3 2012 memIQ
DV1.2 - 16042012
79

float(data["pilot_percent_hours_on_type"]))
data["pilot_total_hours"] = int(
data["pilot_total_hours"])
data["midair"] = bool(int(data["midair"]))
data["airport"] = element.find("airport").text.strip()

narrative = element.find("narrative").text
data["narrative"] = (narrative.strip()
if narrative is not None else "")
incident = Incident(**data)
self[incident.report_id] = incident
except (ValueError, LookupError, IncidentError) as err:
print("{0}: import error: {1}".format(
os.path.basename(sys.argv[0]), err))
return False
return True


DOM (Document Object Model)

API standard pentru reprezentarea i manipularea XML n memorie

Scriere cu DOM (similar cu document tree):
- Creare DOM
- Scrierea lui n fisier

def export_xml_dom(self, filename):
dom = xml.dom.minidom.getDOMImplementation()
tree = dom.createDocument(None, "incidents", None)
root = tree.documentElement
for incident in self.values():
element = tree.createElement("incident")
for attribute, value in (
("report_id", incident.report_id),
("date", incident.date.isoformat()),
("aircraft_id", incident.aircraft_id),
("aircraft_type", incident.aircraft_type),
("pilot_percent_hours_on_type",
str(incident.pilot_percent_hours_on_type)),
("pilot_total_hours",
str(incident.pilot_total_hours)),
("midair", str(int(incident.midair)))):
element.setAttribute(attribute, value)
for name, text in (("airport", incident.airport),
("narrative", incident.narrative)):
text_element = tree.createTextNode(text)
name_element = tree.createElement(name)
name_element.appendChild(text_element)
element.appendChild(name_element)
Python 3 2012 memIQ
DV1.2 - 16042012
80

root.appendChild(element)

fh = None
try:
fh = open(filename, "w", encoding="utf8")
tree.writexml(fh, encoding="UTF-8")
return True
except EnvironmentError as err:
print("{0}: export error: {1}".format(
os.path.basename(sys.argv[0]), err))
return False
finally:
if fh is not None:
fh.close()


Citire cu DOM

def import_xml_dom(self, filename):

def get_text(node_list):
text = []
for node in node_list:
if node.nodeType == node.TEXT_NODE:
text.append(node.data)
return "".join(text).strip()

try:
dom = xml.dom.minidom.parse(filename)
except (EnvironmentError, xml.parsers.expat.ExpatError) as err:
print("{0}: import error: {1}".format(os.path.basename(sys.argv[0]), err))
return False

self.clear()
for element in dom.getElementsByTagName("incident"):
try:
data = {}
for attribute in ("report_id", "date", "aircraft_id",
"aircraft_type",
"pilot_percent_hours_on_type",
"pilot_total_hours", "midair"):
data[attribute] = element.getAttribute(attribute)
data["date"] = datetime.datetime.strptime(
data["date"], "%Y-%m-%d").date()
data["pilot_percent_hours_on_type"] = (
float(data["pilot_percent_hours_on_type"]))
data["pilot_total_hours"] = int(
data["pilot_total_hours"])
data["midair"] = bool(int(data["midair"]))
Python 3 2012 memIQ
DV1.2 - 16042012
81

airport = element.getElementsByTagName("airport")[0]
data["airport"] = get_text(airport.childNodes)
narrative = element.getElementsByTagName("narrative")[0]
data["narrative"] = get_text(narrative.childNodes)
incident = Incident(**data)
self[incident.report_id] = incident
except (ValueError, LookupError, IncidentError) as err:
print("{0}: import error: {1}".format(
os.path.basename(sys.argv[0]), err))
return False
return True


Scriere manual XML

def export_xml_manual(self, filename):
fh = None
try:
fh = open(filename, "w", encoding="utf8")
fh.write('<?xml version="1.0" encoding="UTF-8"?>\n')
fh.write("<incidents>\n")
for incident in self.values():
fh.write('<incident report_id={report_id} '
'date="{0.date!s}" '
'aircraft_id={aircraft_id} '
'aircraft_type={aircraft_type} '
'pilot_percent_hours_on_type='
'"{0.pilot_percent_hours_on_type}" '
'pilot_total_hours="{0.pilot_total_hours}" '
'midair="{0.midair:d}">\n'
'<airport>{airport}</airport>\n'
'<narrative>\n{narrative}\n</narrative>\n'
'</incident>\n'.format(incident,
report_id=xml.sax.saxutils.quoteattr(
incident.report_id),
aircraft_id=xml.sax.saxutils.quoteattr(
incident.aircraft_id),
aircraft_type=xml.sax.saxutils.quoteattr(
incident.aircraft_type),
airport=xml.sax.saxutils.escape(incident.airport),
narrative="\n".join(textwrap.wrap(
xml.sax.saxutils.escape(
incident.narrative.strip()), 70))))
fh.write("</incidents>\n")
return True
except EnvironmentError as err:
print("{0}: export error: {1}".format(
os.path.basename(sys.argv[0]), err))
return False
Python 3 2012 memIQ
DV1.2 - 16042012
82

finally:
if fh is not None:
fh.close()


Parsare XML cu SAX (Simple API for XML)

Handler pe evenimente generate de parser

def import_xml_sax(self, filename):
fh = None
try:
handler = IncidentSaxHandler(self)
parser = xml.sax.make_parser()
parser.setContentHandler(handler)
parser.parse(filename)
return True
except (EnvironmentError, ValueError, IncidentError,
xml.sax.SAXParseException) as err:
print("{0}: import error: {1}".format(
os.path.basename(sys.argv[0]), err))
return False

Vezi clasa

class IncidentSaxHandler(xml.sax.handler.ContentHandler):


Acces random la fiiere binare

- Nu se ncarc toat structura de date n memorie; DBM, SQL DB
- Clasa BinaryRecordFile.BinaryRecordFile:
o Lista de nregistrri get, set, delete (logic)
o Compactare eliminare nregistrri terse logic

Contact = struct.Struct("<15si")
contacts = BinaryRecordFile.BinaryRecordFile(filename, Contact.size)

folosire:

contacts[4] = Contact.pack("Radu Albu".encode("utf8"), 762)
contacts[5] = Contact.pack("Mircea Toma".encode("utf8"), 987)

contact_data = Contact.unpack(contacts[5])
contact_data[0].decode("utf8").rstrip(chr(0)) # automat sunt 0 daca
# lung str este mai mica decat 15
Vezi clasa BinaryRecordFile: __init__(), proprietati, flush, close

def __setitem__(self, index, record):
Python 3 2012 memIQ
DV1.2 - 16042012
83


assert isinstance(record, (bytes, bytearray)), "binary data required"
assert len(record) == self.record_size, (
"record must be exactly {0} bytes".format(self.record_size))
self.__fh.seek(index * self.__record_size)
self.__fh.write(_OKAY)
self.__fh.write(record)
if self.auto_flush:
self.__fh.flush()

def __getitem__(self, index):

self.__seek_to_index(index)
state = self.__fh.read(1)
if state != _OKAY:
return None
return self.__fh.read(self.record_size)

def __seek_to_index(self, index):
if self.auto_flush:
self.__fh.flush()
self.__fh.seek(0, os.SEEK_END)
end = self.__fh.tell()
offset = index * self.__record_size
if offset >= end:
raise IndexError("no record at index position {0}".format(
index))
self.__fh.seek(offset)

def __delitem__(self, index):
self.__seek_to_index(index)
state = self.__fh.read(1)
if state != _OKAY:
return
self.__fh.seek(index * self.__record_size)
self.__fh.write(_DELETED)
if self.auto_flush:
self.__fh.flush()

def undelete(self, index):

self.__seek_to_index(index)
state = self.__fh.read(1)
if state == _DELETED:
self.__fh.seek(index * self.__record_size)
self.__fh.write(_OKAY)
if self.auto_flush:
self.__fh.flush()
return True
Python 3 2012 memIQ
DV1.2 - 16042012
84

return False

- inplace_compact()
- compact()

modulul BikeStock: clase Bike, BikeStock foloseste un BinaryRecordFile

- BikeStock dictionary bike identity --> index

7.4 Exerciii

1. Modificai clasa BinaryRecordFile s nu mai foloseasc byte-ul de stare;
tergerea s se fac doar fizic!

2. xdump:

Usage: xdump.py [options] file1

Options:
-h, --help show this help message and exit
-b BLOCKSIZE, --blocksize=BLOCKSIZE
block size (8..80) [default: 16]
-d, --decimal decimal block numbers [default: hexadecimal]
-e ENCODING, --encoding=ENCODING
encoding (ASCII..UTF-32) [default: UTF-8]

- 3 coloane:
o numrul blocului
o blocul n cifre hexa
o caractere

Python 3 2012 memIQ
DV1.2 - 16042012
85

8 Tehnici avansate
8.1 Programare procedural

8.1.1Execuie pe baza unui dicionar

- Functiile sunt obiecte; numele functiilor sunt referinte la acele obiecte
- In loc de test si apel de functie:

functions = dict(a=add_dvd, e=edit_dvd,
l=list_dvds, r=remove_dvd,
i=import_, x=export, q=quit)
functions[action](db)

- Exemplu din convert-incidents.py:

def import_(self, filename, reader=None):
extension = os.path.splitext(filename)[1].lower()
call = {(".aix", "dom"): self.import_xml_dom,
(".aix", "etree"): self.import_xml_etree,
(".aix", "sax"): self.import_xml_sax,
(".ait", "manual"): self.import_text_manual,
(".ait", "regex"): self.import_text_regex,
(".aib", None): self.import_binary,
(".aip", None): self.import_pickle}
result = call[extension, reader](filename)
if result == False:
self.clear()
return result


8.1.2 Expresii si functii generator

Am vazut functii generator (folosesc yield)

Sintaxa expresie generator (sintaxa similara cu list comprehension []):

(expression for item in iterable)
(expression for item in iterable if condition)

Echivalent - iteratori:
def items_in_key_order(d):
for key in sorted(d):
yield key, d[key]

def items_in_key_order(d):
return ((key, d[key]) for key in sorted(d))
Python 3 2012 memIQ
DV1.2 - 16042012
86

- Se pot folosi pentru a obtine valorile deodata argumente pentru list, tuple

def fu(d):
for x in sorted(d):
yield x

lista = [4, 7, 44, 2, 55, 88, 22, 1]
l1 = list(fu(lista))
l1
[1, 2, 4, 7, 22, 44, 55, 88]

- Se pot folosi pentru iterare:

for x in fu(lista):
print (x)

- Lazy evaluation (generare fara oprire!):

def quarters(next_quarter=0.0):
while True:
yield next_quarter
next_quarter += 0.25

folosire:

result = []
for x in quarters():
result.append(x)
if x >= 1.0:
break

- Variant care reseteaza valoare genratorului:

def quarters(next_quarter=0.0):
while True:
received = (yield next_quarter)
if received is None:
next_quarter += 0.25
else:
next_quarter = received
folosire:

result = []
generator = quarters()
while len(result) < 5:
x = next(generator)
if abs(x - 0.5) < sys.float_info.epsilon:
x = generator.send(1.0)
result.append(x)
Python 3 2012 memIQ
DV1.2 - 16042012
87

Exemplul magic-numbers.py

- Pentru specificarea fisierelor de intrare (nume, masca - *.txt):

if sys.platform.startswith("win"):
def get_files(names):
for name in names:
if os.path.isfile(name):
yield name
else:
for file in glob.iglob(name):
if not os.path.isfile(file):
continue
yield file
else:
def get_files(names):
return (file for file in names if os.path.isfile(file))


8.1.3 Executie dinamica de cod

- Cod introdus de utilizator, plug-ins

- Functia built-in eval():

x = eval(2345 78)

- Crearea si folosirea unei functii in mod dinamic:

import math
code = '''
def area_of_sphere(r):
return 4 * math.pi * r ** 2
'''
context = {}
context["math"] = math
exec(code, context)

o comunicarea cu functia se poate face doar printr-un dictionar context
dat ca parametru la exec()

o functia globals() intoarce o referinta la dictionarul global; obiectele
create de exec() vor fiadaugate la acest dict; o solutie este sa dam acces
la o copie a dict global: context = globals.copy()

o folosire functie definite dinamic:

area_of_sphere = context[area_of_sphere]
area = area_of_sphere(10)
Python 3 2012 memIQ
DV1.2 - 16042012
88

8.1.4 Importul dinamic de module

Exemplul magic-numbers.py: citeste primii 1000 bytes din fiecare fisier dat in linia de
comanda, pentru fiecare va raporta tipul lui pe baza unor semnaturi continute in
module aflate in acelasi director cu programul. Modulele au magic in nume, sunt
incarcate dinamic, ofera o punctie publica get_file_type().

def main():
modules = load_modules()
get_file_type_functions = []
for module in modules:
get_file_type = get_function(module, "get_file_type")
if get_file_type is not None:
get_file_type_functions.append(get_file_type)

for file in get_files(sys.argv[1:]):
fh = None
try:
fh = open(file, "rb")
magic = fh.read(1000)
for get_file_type in get_file_type_functions:
filetype = get_file_type(magic, os.path.splitext(file)[1])
if filetype is not None:
print("{0:.<20}{1}".format(filetype, file))
break
else:
print("{0:.<20}{1}".format("Unknown", file))
except EnvironmentError as err:
print(err)
finally:
if fh is not None:
fh.close()


Functii folosite in programare dinamica:

__import__(...) Imports a module by name; see text
compile(source,file,mode) Returns the code object that results from
compiling the source text; file should be the
filename, or "<string>"; mode must be single,
eval, or exec
delattr(obj,name) Deletes the attribute called name from object obj
dir(obj) Returns the list of names in the local scope, or if
obj is given then objs names (e.g., its attributes
and methods)
eval(source,globals,locals) Returns the result of evaluating the single
expression in source; if supplied, globals is the
global context and locals is the local context (as
dictionaries)
Python 3 2012 memIQ
DV1.2 - 16042012
89

exec(obj,globals,locals) Evaluates object obj, which can be a string or a
code object from compile(), and returns None; if
supplied, globals is the global context and locals
is the local context
getattr(obj,name, val) Returns the value of the attribute called name
from object obj, or val if given and there is no
such attribute
globals() Returns a dictionary of the current global
context
hasattr(obj,name) Returns True if object obj has an attribute called
name
locals() Returns a dictionary of the current local context
setattr(obj,name, val) Sets the attribute called name to the value val for
the object obj, creating the attribute if necessary
type(obj) Returns object objs type object
vars(obj) Returns object objs context as a dictionary; or
the local context if obj is not given


Vezi in magic-numbers.py cele 3 moduri de incarcare a modulelor in mod dynamic.

Pentru identificarea functiilor in modulele incarcate:

def get_function(module, function_name):
function = get_function.cache.get((module, function_name), None)
if function is None:
try:
function = getattr(module, function_name)
if not hasattr(function, "__call__"):
raise AttributeError()
get_function.cache[module, function_name] = function
except AttributeError:
function = None
return function
get_function.cache = {} # atribut a obiectului functie

- Tehnica de a tine intr-un cache a valorilor ce pot fi returnate de o functie se
numeste memoizing.


8.1.5 Functii locale si recursive

- Functii locale definite in alta functie

- Functii recursive: limitarea numarului de iteratii sys.getrecursionlimit(),
sys.setrecursionlimit()

- Exmplu:
def factorial(x):
Python 3 2012 memIQ
DV1.2 - 16042012
90

if x <= 1:
return 1
return x * factorial(x - 1)

Exemplu: IndentedList.py functia indented_list_sort() vezi sursa

Observatie: nonlocal level

8.1.6 Decoratori de functii si metode

Un decorator este o functie care ia ca argument o functie si returneaza o noua functie
ce incorporeaza functia decorate si adauga o functionalitate noua.

Decoratori predefiniti: @property, @classmethod

Exemplu:
@positive_result
def discriminant(a, b, c):
return (b ** 2) - (4 * a * c)

- Decoratorul:

def positive_result(function):
def wrapper(*args, **kwargs):
result = function(*args, **kwargs)
assert result >= 0, function.__name__ + "() result isn't >= 0"
return result
wrapper.__name__ = function.__name__
wrapper.__doc__ = function.__doc__
return wrapper

- Alta varianta echivalenta:

def positive_result(function):
@functools.wraps(function)
def wrapper(*args, **kwargs):
result = function(*args, **kwargs)
assert result >= 0, function.__name__ + "() result isn't >= 0"
return result
return wrapper


Decoratori cu parametrii

@bounded(0, 100)
def percent(amount, total):
return (amount / total) * 100

implementare:
Python 3 2012 memIQ
DV1.2 - 16042012
91


def bounded(minimum, maximum):
def decorator(function):
@functools.wraps(function)
def wrapper(*args, **kwargs):
result = function(*args, **kwargs)
if result < minimum:
return minimum
elif result > maximum:
return maximum
return result
return wrapper
return decorator


Logging function

Exemplu: functie de logging pentru a inregistra pentru o functie numele, argumentele
si rezultatul:

@logged
def discounted_price(price, percentage, make_integer=False):
result = price * ((100 - percentage) / 100)
if not (0 < result <= price):
raise ValueError("invalid price")
return result if not make_integer else int(round(result))

Daca Python ruleaza in mod debug (modul normal) se va inregistra un mesaj de log la
fiecare apel a functiei.

if __debug__:
logger = logging.getLogger("Logger")
logger.setLevel(logging.DEBUG)
handler = logging.FileHandler(os.path.join(tempfile.gettempdir(),
"logged.log"))
logger.addHandler(handler)

def logged(function):
@functools.wraps(function)
def wrapper(*args, **kwargs):
log = "called: " + function.__name__ + "("
log += ", ".join(["{0!r}".format(a) for a in args] +
["{0!s}={1!r}".format(k, v)
for k, v in kwargs.items()])
result = exception = None
try:
result = function(*args, **kwargs)
return result
except Exception as err:
Python 3 2012 memIQ
DV1.2 - 16042012
92

exception = err
finally:
log += ((") -> " + str(result)) if exception is None else ")
{0}: {1}".format(type(exception), exception))
logger.debug(log)
if exception is not None:
raise exception
return wrapper
else:
def logged(function):
return function


8.1.7 Annotarea functiilor

Sintaxa:
def functionName(par1 : exp1, par2 : exp2, ..., parN : expN) -> rexp:
suite

- Optionale; se pot annota toate, unele, niciun parametru
- Sunt adaugate la dictionarul __annotations__ asociat obiectului functie; cheile
sunt numele parametrilor, valorile sunt expresiile corespunzatoare.
- Nu au nici o semnificatie pentru Python, doar le pune acolo

Exemplu: vezi Util.py

def is_unicode_punctuation(s : str) -> bool:
for c in s:
if unicodedata.category(c)[0] != "P": # punctuation
return False
return True

Apel:
Util.is_unicode_punctuation("zebr\a") # returns: False
Util.is_unicode_punctuation(s="!@#?") # returns: True
Util.is_unicode_punctuation(("!", "@")) # returns: True

Putem folosi annotarea pentru verificarea de tip; decorator pentru verificarea de tip a
parametrilor si a valorii returnate:

def strictly_typed(function):
annotations = function.__annotations__
arg_spec = inspect.getfullargspec(function)
assert "return" in annotations, "missing type for return value"
for arg in arg_spec.args + arg_spec.kwonlyargs:
assert arg in annotations, ("missing type for parameter '" +
arg + "'")
@functools.wraps(function)

Python 3 2012 memIQ
DV1.2 - 16042012
93

def wrapper(*args, **kwargs):
for name, arg in (list(zip(arg_spec.args, args)) +
list(kwargs.items())):
assert isinstance(arg, annotations[name]), (
"expected argument '{0}' of {1} got {2}".format(
name, annotations[name], type(arg)))
result = function(*args, **kwargs)
assert isinstance(result, annotations["return"]), (
"expected return of {0} got {1}".format(
annotations["return"], type(result)))
return result
return wrapper

- Modul inspect

Acum aplelul:
is_unicode_punctuation(("!", "@")) # AssertionError!!

Alt motiv de anotare:

def func() -> "author=Popescu Ion":


8.2 OOP
8.2.1 Folosirea lui __slots__

class Point:
__slots__ = ("x", "y")
def __init__(self, x=0, y=0):
self.x = x
self.y = y

In mod obisnuit o instanta foloseste un dictionary privat __dict__ pentru a tine
atributele obiectului se pot adauga sau scoate attribute in mod dynamic.

Daca se foloseste __slots__ - obiectul nu mai are dictionarul atasat, au doar atributele
definite initial, nu se pot adauga/scoate dinamic attribute; sunt mai rapide

8.2.2 Controlul accesului la attribute

class Ord:
def __getattr__(self, char):
return ord(char)

ord = Ord()
ord.a 97
- Se foloseste builtins.ord(char); import builtins!
Python 3 2012 memIQ
DV1.2 - 16042012
94

Exemplu:
class Const:
def __setattr__(self, name, value):
if name in self.__dict__:
raise ValueError("cannot change a const attribute")
self.__dict__[name] = value

def __delattr__(self, name):
if name in self.__dict__:
raise ValueError("cannot delete a const attribute")
raise AttributeError("'{0}' object has no attribute '{1}'"
.format(self.__class__.__name__, name))

Folosire:
const = Const()
const.max = 100


Exemplu: echivalent pentru constant:

Const = collections.namedtuple("_", "min max")(191, 591)
Const.min, Const.max # returns: (191, 591)
Offset = collections.namedtuple("_", "id name description")(*range(3))
Offset.id, Offset.name, Offset.description # returns: (0, 1, 2)


Exemplu: din clasa Image

@property
def width(self):
return self.__width

Pentru a trata unitar atributele:

def __getattr__(self, name):
if name == "colors":
return set(self.__colors) # copie
classname = self.__class__.__name__
if name in frozenset({"background", "width", "height"}):
return self.__dict__["_{classname}__{name}".format(
**locals())] # acces direct la atribute
raise AttributeError("'{classname}' object has no "
"attribute '{name}'".format(**locals()))


8.2.3 Functori

Functor este un obiect care se poate apela ca o functie.
In Python este un obiect functie.
Python 3 2012 memIQ
DV1.2 - 16042012
95

O clasa care are metoda speciala __call__() este un functor.

Exemplu:

strip_punctuation = Strip(",;:.!?")
strip_punctuation("Buna ziua!")

class Strip:

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

def __call__(self, string):
return string.strip(self.characters)

- Putem crea oricate obiecte Strip dorim, fiecare cu lista de caractere de scos

Alternativa - folosirea unui closure o functie ce capteaza o stare (lista de caractere):

def make_strip_function(characters):
def strip_function(string):
return string.strip(characters)
return strip_function

strip_punctuation = make_strip_function(",;:.!?")
strip_punctuation("Buna ziua!")


Exemplu: SortKey.py

class SortKey:
def __init__(self, *attribute_names):
self.attribute_names = attribute_names

def __call__(self, instance):
values = []
for attribute_name in self.attribute_names:
values.append(getattr(instance, attribute_name))
return values

class Person:
def __init__(self, forename, surname, email):
self.forename = forename
self.surname = surname
self.email = email

Sortare lista de Person people.sort(key=SortKey(surname))


Python 3 2012 memIQ
DV1.2 - 16042012
96

In loc de functor se poate folosi operator.attrgetter(); exemplu:

people.sort(key=operator.attrgetter(surname, forename))

operator.attrgetter() returneaza o functie closure care cand este apelata pe un obiect
returneaza valoarea atributelor specificate la creare.


8.2.4 Manageri de context

Asigura ca un code este precedat si urmat de o actiune.
Definesc doua metode speciale - __enter__() si __exit__(), with statement

Sintaxa:
with expression as variable:
suite

- expression trebuie sa fie sau se evalueaza la un obiect de tip manager de
context
- as variable este optional va referi la ce intoarce __enter__()
- deoarece se garanteaza apelul lui __exit__() se poate elimina finally


Exemplu: unele tipuri Python sunt manager de context, de ex. obiectele retunate de
open():

fh = None
try:
fh = open(filename)
for line in fh:
process(line)
except EnvironmentError as err:
print(err)
finally:
if fh is not None:
fh.close()

Echivalent cu:

try:
with open(filename) as fh: # file object este context manager!
for line in fh:
process(line)
except EnvironmentError as err:
print(err)

- daca apare exceptia ea se propaga, dar se inchide fisierul


Python 3 2012 memIQ
DV1.2 - 16042012
97

Exemplu doua obiecte context manager:

try:
with open(source) as fin:
with open(target, "w") as fout:
for line in fin:
fout.write(process(line))
except EnvironmentError as err:
print(err)


- folosirea unui singur with:

try:
with open(source) as fin, open(target, "w") as fout:
for line in fin:


Crearea unui context manager: clasa cu 2 metode - __enter__() si __exit__()

Exemplu: operatii atomice; daca nu apare exceptie se aplica toate transformarile, altfel
nu se aplica niciuna; folosire:

try:
with AtomicList(items) as atomic:
atomic.append(58289)
del atomic[3]
atomic[8] = 81738
atomic[index] = 38172
except (AttributeError, IndexError, ValueError) as err:
print("no changes applied:", err)


class AtomicList:
def __init__(self, alist, shallow_copy=True):
self.original = alist
self.shallow_copy = shallow_copy

def __enter__(self): # val returnata se tine in as varibila!
self.modified = (self.original[:] if self.shallow_copy
else copy.deepcopy(self.original))
return self.modified

def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is None:
self.original[:] = self.modified

- exc_type exception_type;
Python 3 2012 memIQ
DV1.2 - 16042012
98

- daca exit returneaza True nu trebuie propagate exceptia, s-a tratat; False
(None) se propaga exceptia!


8.2.5 Descriptori

Sunt clase ce ofera controlul accesului pentru atributele altei clase.
Orice clasa ce implementeaza metodele special __get__(), __set__() si __delete__() se
numeste (si poate fi folosit ca un) descriptor.

Functiile builtin property() si classmethod() sunt implementate folosind descriptori.

Exemplu: XmlShadow.py clasa care tine string-uri. Accesul se face prin proprietati;
vrem sa putem obtine si versiuni XML escaped (sa foloseasca pentru caracterele
folosite de XML in mod special codificari: < &lt, & &amp, etc.).

class Product:
- Foloseste __slots__ pentru a nu se putea adauga attribute (__dict__)
- Attribute clasa name_as_xml si description_as_xml
- Folosire:

product = Product("Chisel <3cm>", "Chisel & cap", 45.25)
product.name, product.name_as_xml, product.description_as_xml
('Chisel <3cm>', 'Chisel &lt;3cm&gt;', 'Chisel &amp; cap')


class XmlShadow:
def __init__(self, attribute_name):
self.attribute_name = attribute_name
def __get__(self, instance, owner=None):
return xml.sax.saxutils.escape(getattr(instance,
self.attribute_name))

Folosire cache (nu prea are rost pentru description!):

class CachedXmlShadow:
def __init__(self, attribute_name):
self.attribute_name = attribute_name
self.cache = {}
def __get__(self, instance, owner=None):
xml_text = self.cache.get(id(instance))
if xml_text is not None:
return xml_text
return self.cache.setdefault(id(instance),
xml.sax.saxutils.escape(
getattr(instance, self.attribute_name)))


Python 3 2012 memIQ
DV1.2 - 16042012
99

Exemplu: folosirea descriptor pentru a tine toate proprietatile vezi
ExternalStorage.py

class Point:
__slots__ = ()
x = ExternalStorage("x")
y = ExternalStorage("y")

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

self.x = x descriptor cu numele x, se apeleaza __set__() pe el!

class ExternalStorage:
__slots__ = ("attribute_name",)
__storage = {}

def __init__(self, attribute_name):
self.attribute_name = attribute_name
def __set__(self, instance, value):
self.__storage[id(instance), self.attribute_name] = value
def __get__(self, instance, owner=None):
if instance is None:
return self # acces la x din Point
return self.__storage[id(instance), self.attribute_name]


Exemplu: descriptor Property ce se comporta ca fi functia builtin property() vezi
sursa Property.py

Aplicam la:

class NameAndExtension:
def __init__(self, name, extension):
self.__name = name
self.__extension = extension

@Property # Uses the custom Property descriptor
def name(self):
return self.__name

@Property # Uses the custom Property descriptor
def extension(self):
return self.__extension

@extension.setter # Uses the custom Property descriptor
def extension(self, extension):
self.__extension = extension
Python 3 2012 memIQ
DV1.2 - 16042012
100

class Property:

def __init__(self, getter, setter=None):
self.__getter = getter
self.__setter = setter
self.__name__ = getter.__name__

def __get__(self, instance, owner=None):
if instance is None:
return self
return self.__getter(instance)

def __set__(self, instance, value):
if self.__setter is None:
raise AttributeError("'{0}' is read-only".format(
self.__name__))
return self.__setter(instance, value)

def setter(self, setter):
self.__setter = setter
return self


8.2.6 Decoratori de clase

Similar cu decoratorii de functii sau metode.

Decoratorii de clase primesc un obiect clasa (rezultatul declaratiei class) si returneaza
o clasa - o versiune modificata.

Exemplu: SortedListDelegate.py (pleaca de la SortedList.py cap. 6)

@Util.delegate("__list", ("pop", "__delitem__", "__getitem__",
"__iter__", "__reversed__", "__len__", "__str__"))
class SortedList:

Implementare decoratorului clasei din Util.py:

def delegate(attribute_name, method_names):
def decorator(cls):
nonlocal attribute_name
if attribute_name.startswith("__"):
attribute_name = "_" + cls.__name__ + attribute_name
for name in method_names:
setattr(cls, name, eval("lambda self, *a, **kw: "
"self.{0}.{1}(*a, **kw)".format(
attribute_name, name)))
return cls
return decorator
Python 3 2012 memIQ
DV1.2 - 16042012
101

Exemplu: FuzzyBool din cap.6 am furnizat doar metodele special __lt__() si
__eq__() corespunzatoare operatorilor < si ==, celelate metode special s-au generat
automat.
Python produce > pe baza <, != pe baza == si >= pe baza <=.

@Util.complete_comparisons
class FuzzyBool:

Implementare:

def complete_comparisons(cls):
assert cls.__lt__ is not object.__lt__, (
"{0} must define < and ideally ==".format(cls.__name__))
if cls.__eq__ is object.__eq__:
cls.__eq__ = lambda self, other: (not
(cls.__lt__(self, other) or cls.__lt__(other, self)))
cls.__ne__ = lambda self, other: not cls.__eq__(self, other)
cls.__gt__ = lambda self, other: cls.__lt__(other, self)
cls.__le__ = lambda self, other: not cls.__lt__(other, self)
cls.__ge__ = lambda self, other: not cls.__lt__(self, other)
return cls


8.2.7 Clase de baza abstracte

Nu se poate instantia. ABC Abstract Base Class
Au cel putin o metoda sau proprietate abstracta.

Vezi http://www.python.org/dev/peps/pep-3119/

O metoda abstracta se poate defini:
- pass in loc de suite (corp)
- genereaza NotImplementedError()

Toate ABC trebuie sa aiba o metaclasa de tip abc.ABCMeta sau una din subclasele ei.

Python are cateva ABC in modulele:
collections Callable, Container, Hashable, Iterable, Iterator, sized, Mapping,
Mutable-Mapping, Sequence, Mutable-Sequence, set, MutableSet
number Number, Complex, Real, Rational, Integral
io.IOBase.

Se poate testa tipul:
isinstance(x, collections.MutableSequence)
isinstance(x, numbers.Integral)

Clasa SortedList (cap. 6) poate mosteni Sequence:

Class SortedList(collections.Sequence) vezi SortedListAbc.py
Python 3 2012 memIQ
DV1.2 - 16042012
102

Aceasta mostenire:
- obliga SortedList sa implementeze metodele __init__(), __getitem__(),
__len__()
- ofera implementari concrete pentru __contains__(), __iter__(),
__reversed__(), count(), index()

Exemplu: Appliance.py

class Appliance(metaclass=abc.ABCMeta): # cerinta pt ABC!!!

@abc.abstractmethod
def __init__(self, model, price):
self.__model = model
self.price = price

def get_price(self):
return self.__price

def set_price(self, price):
self.__price = price

price = abc.abstractproperty(get_price, set_price)

@property
def model(self):
return self.__model

Clasa abstracta trebuie ca metaclasa ei sa fie abc.ABCMeta sau orice alta subclasa a
ei.

Mostenirea clasei abstracte:

class Cooker(Appliance):

def __init__(self, model, price, fuel):
super().__init__(model, price)
self.fuel = fuel

price = property(lambda self: super().price,
lambda self, price: super().set_price(price))

Exemplu: TextFilter.py definirea unei interfete

class TextFilter(metaclass=abc.ABCMeta):

@abc.abstractproperty
def is_transformer(self):
raise NotImplementedError()

Python 3 2012 memIQ
DV1.2 - 16042012
103

@abc.abstractmethod
def __call__(self):
raise NotImplementedError()

Subclasare:

class CharCounter(TextFilter):

@property
def is_transformer(self):
return False

def __call__(self, text, chars):
count = 0
for c in text:
if c in chars:
count += 1
return count

Folosire:
vowel_counter = CharCounter()
vowel_counter("dog fish and cat fish", "aeiou")

Similar clasele RuLengthEncode si RunLengthDecode (codificare 0x00 count byte)

Exemplu: Abstract.py

class Undo(metaclass=abc.ABCMeta):

@abc.abstractmethod
def __init__(self):
self.__undos = []

@abc.abstractproperty
def can_undo(self):
return bool(self.__undos)

@abc.abstractmethod
def undo(self):
assert self.__undos, "nothing left to undo"
self.__undos.pop()(self)

def add_undo(self, undo):
self.__undos.append(undo)

def clear(self): # In class Undo
self.__undos = []


Python 3 2012 memIQ
DV1.2 - 16042012
104

Mostenire:
class Stack(Undo):

def __init__(self):
super().__init__()
self.__stack = []

@property
def can_undo(self):
return super().can_undo

def undo(self):
super().undo()

def push(self, item):
self.__stack.append(item)
self.add_undo(lambda self: self.__stack.pop())

def pop(self):
item = self.__stack.pop()
self.add_undo(lambda self: self.__stack.append(item))
return item

def top(self):
assert self.__stack, "Stack is empty"
return self.__stack[-1]

def __str__(self):
return str(self.__stack)


8.2.8 Mostenire multipla

- Problema mostenirii aceleiasi clase de mai multe ori (rezolvat in C++ cu clase
de baza virtuale)
- Se poate evita prin delegare

Exemplu: (Abstract.py)
- clasa LoadSave pentru a salva (pickle) atributele
- class FileStack(Undo, LoadSave):


8.2.9 Metaclase

Metaclasa clasa (issubclass()); clasa obiect (isinstance())

Folosire: am vazut deja mostenire class SortedList(Sequence) sau

Python 3 2012 memIQ
DV1.2 - 16042012
105

class SortedList:
.
collections.Sequence.register(SortedList)

Inregistrarea lui SortedList in acest el o face subclasa virtuala = raporteaza ca este
o subclasa a lui Sequence dar nu mosteneste nimic de la Sequence.
Este doar o promisiune ca implementeaza API-ul metaclasei; mostenirea este si o
garantie ca implementeaza API-ul metaclasei.

issubclass(x, Sequence) True

Exemplu: clasele ce vor fi metaclase trebuie sa mosteneasca type, sau una din
subclasele ei.

class LoadableSaveable(type):
def __init__(cls, classname, bases, dictionary):
super().__init__(classname, bases, dictionary)
assert hasattr(cls, "load") and isinstance(getattr(cls, "load"),
collections.Callable), ("class '" + classname +
"' must provide a load() method")
assert hasattr(cls, "save") and isinstance(getattr(cls, "save"),
collections.Callable), ("class '" + classname +
"' must provide a save() method")

- Aceasta clasa este apelata doar cand clasele care o folosesc sunt instantiate
- Apel:

>>>class Bad(metaclass=Meta.LoadableSaveable):
... def some_method(self): pass
Traceback (most recent call last):
...
AssertionError: class 'Bad' must provide a load() method

>>> class Good(metaclass=Meta.LoadableSaveable):
... def load(self): pass
... def save(self): pass
>>> g = Good()


Metaclasa poate sa modifice clasele ce o folosesc (nume, clasele parinte, dictionarul
clasei create); de ex. alternativa la decoratorii @property si @name.setter sunt
conventii de nume pentru a identifica proprietatile: daca clasa are metode de forma
get_name() si set_name() vom avea si o data private __name accesata prin
proprietatea instanta.name:

class Product(metaclass=AutoSlotProperties):
def __init__(self, barcode, description):
self.__barcode = barcode
self.description = description
Python 3 2012 memIQ
DV1.2 - 16042012
106

def get_barcode(self):
return self.__barcode
def get_description(self):
return self.__description
def set_description(self, description):
if description is None or len(description) < 3:
self.__description = "<Invalid Description>"
else:
self.__description = description

>>> product = Product("101110110", "8mm Stapler")
>>> product.barcode, product.description
('101110110', '8mm Stapler')

- dir(Product) barcode, description; au disparut get_name() si set_name()!

class AutoSlotProperties(type):
def __new__(mcl, classname, bases, dictionary):
slots = list(dictionary.get("__slots__", []))
for getter_name in [key for key in dictionary
if key.startswith("get_")]:
if isinstance(dictionary[getter_name],
collections.Callable):
name = getter_name[4:]
slots.append("__" + name)
getter = dictionary.pop(getter_name)
setter_name = "set_" + name
setter = dictionary.get(setter_name, None)
if (setter is not None and
isinstance(setter, collections.Callable)):
del dictionary[setter_name]
dictionary[name] = property(getter, setter)
dictionary["__slots__"] = tuple(slots)
return super().__new__(mcl, classname, bases, dictionary)

8.3 Programare functionala

Mapare

list(map(lambda x: x ** 2, [1, 2, 3, 4]))

- Returneaza un iterator

[x **2 for x in [1,2,3,4]] - list comprehension

(x **2 for x in [1,2,3,4]) - generator


Python 3 2012 memIQ
DV1.2 - 16042012
107

Filtrare

list(filter(lambda x: x > 0, [1, -3, 4, -6]))

[x for x in [1, -3, 4, -6] if x > 0]

(x for x in [1, -3, 4, -6] if x > 0)


Reducere produce o singura valoare

functools.reduce(lambda x, y: x * y, [1,2,3,4])

functools.reduce(operator.mul, [1,2,3,4])

Functii built-in ce primesc un iterabil:
- all()
- any()
- max()
- min()
- sum()

Exemple:

functools.reduce(operator.add, (os.path.getsize(x) for x in files))
functools.reduce(operator.add, map(os.path.getsize, files))


functools.reduce(operator.add, map(os.path.getsize,
filter(lambda x: x.endswith(".py"), files)))
functools.reduce(operator.add, map(os.path.getsize,
(x for x in files if x.endswith(".py"))))
functools.reduce(operator.add, (os.path.getsize(x)
for x in files if x.endswith(".py")))

sum(os.path.getsize(x) for x in files if x.endswith(".py"))


Modulul operator (pe langa operatori):
- operator.attrgetter()
- operator.itemgetter()
Returneaza functii (vezi documentatia) care pot fi folosite sa extraga atributele sau
elementele specificate

operator.itemgetter(1, 3, 5)(L) elementele din L de index 1, 3, 5

Functia returnata se poate folosi in map(), filter(), functools.reduce() sau in list, dict
sau set comprehension

L.sort(key = operator.attrgetter(priority))
Python 3 2012 memIQ
DV1.2 - 16042012
108

Key se poate folosi o functie, metoda, o functie lambda, sau operator.attrgetter()


Modulul itertools

for value in itertools.chain(data_list1, data_list2, data_list3):
total += value


8.3.1 Functii partiale

Crearea unei functii din una existent si argumente care face ce face functia originala
dar cu argumente fixe.

enumerate1 = functools.partial(enumerate, start=1)

for lino, line in enumerate1(lines):
process_line(i, line)

Exemplu:
reader = functools.partial(open, mode="rt", encoding="utf8")
writer = functools.partial(open, mode="wt", encoding="utf8")

reader(filename)
writer(filename)


loadButton = tkinter.Button(frame, text="Load",
command=functools.partial(doAction, "load"))
saveButton = tkinter.Button(frame, text="Save",
command=functools.partial(doAction, "save"))


8.4 Exemplu
Vezi Valid.py

Problema: validarea atributelor
Se poate face individual prin proprietati (sau functii getter si setter); se poate face o
validarea la nivel de clasa:

@valid_string("name", empty_allowed=False)
@valid_string("productid", empty_allowed=False,
regex=re.compile(r"[A-Z]{3}\d{4}"))
@valid_string("category", empty_allowed=False, acceptable=
frozenset(["Consumables", "Hardware", "Software", "Media"]))
@valid_number("price", minimum=0, maximum=1e6)
@valid_number("quantity", minimum=1, maximum=1000)

Python 3 2012 memIQ
DV1.2 - 16042012
109

class StockItem:
def __init__(self, name, productid, category, price, quantity):
self.name = name
self.productid = productid
self.category = category
self.price = price
self.quantity = quantity

Validarea se face combinand decoratorii de clasa cu descriptorii.

def valid_string(attr_name, empty_allowed=True, regex=None,
acceptable=None):
def decorator(cls):
name = "__" + attr_name
def getter(self):
return getattr(self, name)
def setter(self, value):
assert isinstance(value, str), (attr_name + " must be a string")
if not empty_allowed and not value:
raise ValueError("{0} may not be empty".format( attr_name))
if ((acceptable is not None and value not in acceptable) or
(regex is not None and not regex.match(value))):
raise ValueError("{attr_name} cannot be set to "
"{value}".format(**locals()))
setattr(self, name, value)
setattr(cls, attr_name, GenericDescriptor(getter, setter))
return cls
return decorator




class GenericDescriptor:

def __init__(self, getter, setter):
self.getter = getter
self.setter = setter

def __get__(self, instance, owner=None):
if instance is None:
return self
return self.getter(instance)

def __set__(self, instance, value):
return self.setter(instance, value)




Python 3 2012 memIQ
DV1.2 - 16042012
110

9 Procese i fire de execuie

Concuren la nivel de:
- Procese procesoare multicore
- Fire de execuie

9.1 Modulul subprocess

Este folositor cnd dorim sa lansm programe existente (la care putem pasa parametrii
n linia de comand), cu care eventual comunicm prin pipes.

Exemplu: grep care cauta un cuvnt n fiierele specificate n linia de comand; se
caut recursiv i n subdirectori; cutarea se deleag la oricte procese dorim.
Vezi exemplele: grepword-p.py, grepword-p-child.py

Documentaie modul: http://docs.python.org/py3k/library/subprocess.html

9.2 Modulul threading
- Problema accesului la resurse comune race condition
- mecanism de acces exclusiv
- deadlock
- crearea thread-urilor similar Java:
o subclasarea threading.Thread
o parsarea unui obiect callable la threading.Thread

Exemplu: similar cu exemplul anterior, folosete thread-uri n loc de lansarea de
procese vezi grepword-t.py
- queue.Queue este thread safe (vezi modulul queue: LifoQueue,
PriorityQueue)

9.3 Modulul multiprocessing

Varianta ce folosete modulul multiprocessing: grepword-m.py

9.4 Exemplu
Gsirea de fiiere duplicat: se compar numele i mrimea fiierelor, pentru m vezi
findduplicates-t.py

Pachet threading: Lock, RLock, Semaphore, Condition

Tem: modificai programul findduplicates-t.py pentru a afia n ordine
descresctoare fiierele duplicat gsite.

Python 3 2012 memIQ
DV1.2 - 16042012
111

10 Lucrul n reea networking

Comunicare ntre programe; soluii client server.

Clientul trebuie tie s s gseasc serverul adresa IP (Internet Protocol) i numrul
portului + protocol de comunicare comun.

Modulul sockets:
- suport adrese IPv4 i IPv6
- UDP (User Datagram Protocol)
- TCP (Transmission Control Protocol) orientat stream
- FTP (File Transfer Protocol) i HTTP (Hypertext Transfer Protocol) sunt
bazate pe TCP

10.1 Exemplu
Aplicaie de gestiune maini.
Client car_registration.py
Server car_registration_server.py

Note:
Context manager - SocketManager
struct.Struct("!I") vezi modulul struct
o ! - byte order = big-endian (nework)
o I unsigned int
Modulul socketserver bazat pe sockets
contextlib.closing context manager, se apeleaza close()
socketserver.ForkingMixIn multi procese
socketserver.ThreadingMixIn multi threading
TCPServer, UDPServer, UnixStreamServer, UnixDatagramServer
RequestHandler.Cars variabil clas (la fel ca i Call)


Tem: modificai exemplul (client + server) pentru a include o nou operaie:
GET_LICENSES_STARTING_WITH ce afieaz toate plcuele de nmatriculare ce
ncep cu stringul dat.



Python 3 2012 memIQ
DV1.2 - 16042012
112

11 Baze de date

SQL Structured Query Language API pentru lucrul cu baze de date relaionale
SQLite 3 standard pentru Python

Tipuri de Database Manager (DBM)
ine informaia n form de perechi cheie valoare
Python ofer interfee pentru DBM standard
Funcioneaz ca dicionare ce sunt inute pe disc
Modulul shelve permite chei de tip string i valori orice obiect (pickable)

Pachete pentru interfaare cu orice baz de date vezi http://pypi.python.org/pypi/

ORM Object Relational Mapper layer ntre o baz de date relaional i obiecte
Python:
- SQLAlchemy www.sqlalchemy.org
- SQLObject www.sqlobject.org

Exemplu: aplicaie pentru gestiunea unei colecii de DVD-uri

11.1 Baze de date DBM
Modul shelve
- ofer un wrapper pentru a lucra cu un DBM ca i cu un dicionar
- cheile sunt stringuri, valorile obiecte pickable; acestea se transform n bytes
- Fiierele DBM pot s nu fie compatibile ntre sisteme diferite; se poate folisi
formatul XML pentru transfer de date ntre fiiere DBM diferite
- Lucrul similar cu un dicionar; open() i sync()

Vezi: dvds-dbm.py

11.2 Baze de date SQL
Modul sqlite3

Vezi dvds-sql.py

Tabele:
- dvds id, title, year, duration, director_id
- directors: id, name
API:
- db.close()
- db.commit()
- db.cursor() returneaz un obiect cursor prin care executm operaii asupra db
- db.rollback()

Python 3 2012 memIQ
DV1.2 - 16042012
113

Tem: oferii suport pentru serverul din cap. Anterior, informaia s fie inut ntr-o
BD, fie folosind modulul shelve, fie modulul sqlite3.






Python 3 2012 memIQ
DV1.2 - 16042012
114

12 Referine

http://code.google.com/edu/languages/google-python-class/

http://www.itmaybeahack.com/homepage/books/python.html