-
Notifications
You must be signed in to change notification settings - Fork 2
Noțiuni specifice Python
Python este un limbaj ce oferă o serie de artificii pentru o scriere mai ușoară a codului. Cursul prezintă o trecere în revistă a principalelor moduri în care putem exprima mai ușor diferite construcții în Python.
- Vrem să constrim o funcție care primește o listă cu numere și întoarce o listă cu acestea triplate
Modul clasic
def triple_list(l):
result = []
for elem in l:
result.append(elem * 3)
return result
Putem scrie și mai simplu
Dacă puteam construi o listă cu elementele 4, 5 și 6 astfel: [4, 5, 6]
, mecanismul de list comprehension ne lasă să construim liste într-un mod descriptiv. Notația se bazează pe cea clasică din
matematică și pune accent pe descrierea proprietaților pe care le au elementele din noua listă.
def triple_list(l):
return [x * 3 for x in l]
În limbaj natural: pune x * 3
în listă, pentru fiecare x
din l
.
O definire asemănătoare cu cea din matematică. Scrierea este echivalentă cu {x * 3 | x aparține l}
- Vrem ca dintr-o listă să păstrăm doar elementele pare
Varianta clasică
def filter_even(l):
result = []
for elem in l:
if elem % 2 == 0:
result.append(elem)
return result
Sau cu list comprehensions
def filter_even(l):
return [x for x in l if x % 2 == 0]
În limbaj natural: pune x
în listă, pentru fiecare x
din l
, dacă acesta e par.
- Vrem toate perechile de numere
i, j
mai mari sau egale cu0
și mai mici decâtn
>>> n = 3
>>> [(i, j) for i in range(n) for j in range(n)]
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
- Vrem toate perechile de numere
i, j
mai mari sau egale cu0
și mai mici decatn
cu proprietatea căi <= j
>>> n = 3
>>> [(i, j) for i in range(n) for j in range(n) if i <= j]
[(0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2)]
>>> # sau
>>> n = 3
>>> [(j, i) for i in range(n) for j in range(i + 1)]
[(0, 0), (0, 1), (1, 1), (0, 2), (1, 2), (2, 2)]
Într-un mod asemănător putem defini și dicționare.
- Inițializăm cu
0
scorurile pentru o listă de persoane.
>>> nume = ["Ion", "Maria", "Gigel"]
>>> score = {n: 0 for n in nume}
>>> score
{'Ion': 0, 'Gigel': 0, 'Maria': 0}
>>> # Mai puțin pentru Ion
>>> nume = ["Ion", "Maria", "Gigel"]
>>> score = {n: 0 for n in nume if n != "Ion"}
>>> score
{'Gigel': 0, 'Maria': 0}
- Putem transforma dintr-o listă de tuple într-un dicționar, sau invers.
>>> score = [('Gigel', 0), ('Maria', 10)]
>>> {n: s + 1 for n, s in score}
{'Gigel': 1, 'Maria': 11}
Observați construcția:
>>> score = [('Gigel', 0), ('Maria', 10)]
>>> for nume, scor in score:
... print nume, scor
...
Gigel 0
Maria 10
- Vrem să inversăm operația anterioară.
>>> score = {'Gigel': 1, 'Maria': 11}
>>> [(s, n - 1) for s, n in score.items()]
[('Gigel', 0), ('Maria', 10)]
Observați metoda default de dicționar items
>>> score.items()
[('Gigel', 1), ('Maria', 11)]
După aceleași reguli putem forma set
-uri (structuri cu elemente unice) folosind construcția:
>>> dupplicates = [1, 1, 2, 2, 3, 3]
>>> {d for d in dupplicates}
set([1, 2, 3])
>>> # echivalenta cu
...
>>> set(dupplicates)
set([1, 2, 3])
În Python o funcție este, de asemenea, și o valoare. De exemplu, putem atribui unei variabile valoarea unei funcții.
>>> def plus_one(x):
... return x + 1
...
>>> # valoarea lui plus_one este
...
>>> plus_one
<function plus_one at 0x7f7b8c662e60>
>>> # o atribuim lui f
...
>>> f = plus_one
>>> f
<function plus_one at 0x7f7b8c662e60>
>>> f(12)
13
De asemena, putem construi clase ale căror instanță se comportă precum o funcție. Aceste obiecte se numesc callable
și se creează implementând metoda call. Generalizând exemplul de mai sus:
>>> class PlusN(object):
... def __init__(self, plus_what):
... self.plus_what = plus_what
... def __call__(self, x):
... return x + self.plus_what
...
>>> plus_one = PlusN(1)
>>> plus_one(12)
13
În unele cazuri, funcțiile pot fi destul de scurte și ar fi inutil să poluăm spațiul de nume cu o funcție scurtă pe care o folosim doar de câteva ori.
Din acest motiv există funcții anonime sau lambda. O astfel de funcție se creează în felul următor:
>>> plus_one = lambda x: x + 1
>>> plus_one
<function <lambda> at 0x7f7b8c662e60>
>>> plus_one(12)
13
>>> # Sau cu mai multe argumente
...
>>> f = lambda x, y: x + y
>>> f(1, 2)
3
Funcțiile lambda sunt folosite, de obicei, în funcții care au ca parametru obiecte ce pot fi apelate.
>>> def apply_in_dict_vals(d, f):
... return {key: f(value) for key, value in d.items()}
...
>>> score = {'Gigel': 1, 'Maria': 11}
>>> apply_in_dict_vals(score, lambda x: x - 1)
{'Gigel': 0, 'Maria': 10}
>>> # Sau cu obiect callable
...
>>> apply_in_dict_vals(score, PlusN(-1))
{'Gigel': 0, 'Maria': 10}
>>> # Sau cu o functie definita anterior
...
>>> apply_in_dict_vals(score, plus_one)
{'Gigel': 2, 'Maria': 12}
Pentru detecția erorilor într-un program apelăm la debugging, care în Python se face printr-un modul dedicat: pdb
. Cea mai comună utilizare a acestui modul este amplasarea unui breakpoint în cod, înainte de linia care generează o eroare:
import pdb; pdb.set_trace()
Execuția programului se va opri la această linie, permițând inspecția obiectelor curente, prin deschiderea unui interpretor interactiv. Comenzile ce pot fi folosite în debugger sunt:
-
h(elp)
- printează lista de comenzi disponibile; -
l(ist)
- afișează un bloc de cod (11 linii) în jurul liniei curente; -
n(ext)
- trece la următoarea instrucțiune; -
c(ontinue)
- contină execuția codului până la sfârșit/următorul breakpoint; -
s(tep)
- intră în corpul funcției; -
b(reak) linenum
- setează un nou breakpoint la linialinenum
; -
q(uit)
- oprește execuția programului;
Foarte utile în debugging sunt și următoarele funcții built-in:
dir
type
vars
Funcția dir(obj)
returnează o listă cu toate atributele (date sau metode) unui obiect.
>>> s = 'hello'
>>> dir(s)
['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_formatter_field_name_split', '_formatter_parser', 'capitalize', 'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
Aceasta indică tipul unui obiect.
>>> class X(object):
... pass
...
>>> x = X()
>>> type(x)
<class '__main__.X'>
vars
întoarce valoarea atributului __dict__
pentru orice modul, clasă sau instanță care are acest atribut.
>>> class X(object):
... def __init__(self):
... self.greeting = 'Hello'
... self.name = 'John'
...
>>> x = X()
>>> vars(x)
{'greeting': 'Hello', 'name': 'John'}