Skip to content

Noțiuni specifice Python

Andreea Dima edited this page Sep 21, 2017 · 4 revisions

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.

List Comprehensions - Definire de liste

  • 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 cu 0 și mai mici decât n
>>> 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 cu 0 și mai mici decat n 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)]

Dict Comprehensions

Î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)]

Set comprehension

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])

Obiecte callable

Î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

Funcții anonime

Î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}

Debugging (pdb)

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 linia linenum;
  • q(uit) - oprește execuția programului;

Funcții de inspecție în interpretor

Foarte utile în debugging sunt și următoarele funcții built-in:

  • dir
  • type
  • vars

dir

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']

type

Aceasta indică tipul unui obiect.

>>> class X(object):
...     pass
... 
>>> x = X()
>>> type(x)
<class '__main__.X'>

vars

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'}
Clone this wiki locally