post

Python ro:Module

Contents

Introducere

Aţi văzut cum se poate refolosi o porţiune de cod în program prin definirea funcţiilor. Dar dacă vreţi să refolosiţi un număr mai mare de funcţii în alte programe decât cel pe care îl scrieţi? Aşa cum aţi ghicit, răspunsul este folosirea modulelor.

Există variate metode de a scrie module, dar cea mai simplă cale este de a crea un fişier cu extensia .py care conţine funcţii şi variabile.

Altă metodă este scrierea modulelor în limbajul în care chiar interpretorul Python a fost scris. De exemplu, puteţi scrie module în limbajul de programare C şi dupa compilare, ele pot fi folosite din codul Python când se foloseşte interpretorul Python standard.

Un modul poate fi importat de un alt program pentru a folosi funcţionalitatea acestuia. Aşa putem şi noi să folosim biblioteca standard Python. Întâi vom vedea cum se folosesc modulele bibliotecii standard.

Exemplu:

#!/usr/bin/python
# Fişier: using_sys.py

import sys

print('Argumentele la linia de comandă sunt:')
for i in sys.argv:
    print(i)

print('nnPYTHONPATH este', sys.path, 'n')

Rezultat:

   $ python using_sys.py noi suntem argumente
   Argumentele la linia de comandă sunt:
   using_sys.py
   noi
   suntem
   argumente

   PYTHONPATH este ['', 'C:\tmp', 'C:\Python30\python30.zip',
   'C:\Python30\DLLs', 'C:\Python30\lib', 'C:\Python30\lib\plat-win',
   'C:\Python30', 'C:\Python30\lib\site-packages']

Cum funcţionează:

La început importăm modulul sys folosind declaraţia import. În esenţă, asta îi spune lui Python că vrem să folosim acest modul. Modulul sys conţine funcţionalitate legată de interpretorul Python şi mediul său, system.

Când Python execută declaraţia import sys, el caută modulul sys. În acest caz, este vorba de un modul preinstalat şi de aceea Python ştie unde să-l găsească.

Dacă nu ar fi fost un modul compilat, ci un modul scris în Python, interpretorul ar fi căutat în directoarele listate în variabila sys.path. Dacă modulul este găsit, declaraţiile din interiorul modului sunt executate. Observaţi că această iniţializare este făcută numai prima dată când importăm un modul.

Variabila argv din modulul sys este accesată folosind notaţia cu puncte, adică sys.argv. Ea arată clar că acest nume este parte a modulului sys. Alt avantaj al acestei abordări este că numele nu dă conflict cu nici o variabilă argv folosită în program.

Variabila sys.argv este o listă de şiruri (listele sunt explicate în detaliu în capitolul despre liste. În special, variabila sys.argv conţine lista argumentelor din linia de comandă adică acele argumente transmise programului prin adăugarea lor la linia de comandă care lansează programul.

Daca folosiţi un IDE pentru a scrie şi rula aceste programe, căutaţi în meniuri o cale de a specifica argumente la linia de comandă.

Aici, când se execută python using_sys.py noi suntem argumente, rulăm modulul using_sys.py cu comanda python şi celelalte lucruri care îl urmează sunt transmise programului. Python păstrează linia de comandă în variabila sys.argv ca să le putem folosi.

Reţineţi, numele scriptului care rulează este întotdeauna primul argument din lista sys.argv. Deci în acest caz vom avea 'using_sys.py' în poziţia sys.argv[0], 'noi' în poziţia sys.argv[1], 'suntem' în poziţia sys.argv[2] şi 'argumente' în poziţia sys.argv[3]. Observaţi că Python începe numerotarea cu 0 nu cu 1.

Variabila sys.path conţine lista numelor de director de unde pot fi importate module. Observaţi că primul sir din sys.path este vid – asta arată că directorul curent este parte a variabilei sys.path ceea ce este totuna cu variabila de mediu PYTHONPATH. Acest comportament este prevăzut pentru a permite importul direct al modulelor aflate în directorul curent. În caz contrar modulele care trebuie importate trebuie poziţionate într-unul din directoarele listate în sys.path.

Fisiere .pyc compilate in octeti

Importul unui modul este relativ costisitor, astfel că Python face nişte smecherii ca să îl accelereze. O cale este să creeze fişiere compilate în octeţi (engl. byte-compiled) cu extensia .pyc care sunt nişte forme intermediare în care Python transformă programul (vă amintiţi din capitolul introductiv cum lucrează Python?). Acest fişier .pyc este util când importaţi un modul a doua oară din alte programe – ele vor fi mult mai rapide întrucât partea de procesare legată de importul modulului este deja realizată. De asemenea, aceste fişiere compilate în octeţi sunt independente de platformă.

Notă
Fişierele .pyc sunt create de obicei în acelaşi director ca şi fişierul .py corespondent. Dacă Python nu are permisiunea de a scrie fişiere în acel director, fişierele .pyc nu vor fi create.

Declaraţia from … import …

Dacă vreţi să importaţi direct variabila argv în programul vostru (pentru a evita scrierea numelui sys. de fiecare dată), puteţi folosi declaraţia from sys import argv. Dacă vreţi să importaţi toate numele folosite în modulul sys atunci puteţi folosi declaraţia from sys import *. Funcţionează pentru orice modul.

În general, trebuie să evitaţi folosirea acestor declaraţii şi în schimb să folosiţi declaraţia import. Ca să fie evitate orice conflicte de nume şi programele să fie mai lizibile.

Atributul __name__ al modulului

Orice modul are un nume, iar declaraţiile din modul pot găsi numele modulului. Este comod aşa, mai ales în situaţia particulară în care se doreşte aflarea regimului modulului (autonom sau importat). Cum am menţionat anterior, când un modul este importat pentru prima dată, codul din modul este executat. Putem folosi acest concept pentru a altera comportamentul modulului dacă programul este executat autonom şi îl putem lăsa neschimbat dacă modulul este importat din alt modul. Acestea sunt posibile folosind atributul __name__ al modulului.

Exemplu:

#!/usr/bin/python
# Fişier: using_name.py

if __name__ == '__main__':
    print('Acest program rulează autonom')
else:
    print('Acest program a fost importat din alt modul')

Rezultat:

   $ python using_name.py
   Acest program rulează autonom

   $ python
   >>> import using_name
   Acest program a fost importat din alt modul
   >>>

Cum funcţionează:

Orice modul Python are propriul atribut __name__ definit şi dacăş acesta este '__main__', rezultă că acel modul este rulat de sine stătător de către utilizator şi putem lua măsurile adecvate.

Crearea propriilor module

Crearea propriilor noastre module este uşoară, aţi făcut asta tot timpul! Asta din cauză că orice program Python este un modul. Trebuie doar să ne asigurăm că fişierul are extensia .py. Următorul exemplu ar trebui să clarifice situaţia.

Exemplu:

#!/usr/bin/python
# Fişier: meu.py

def zisalut():
    print('Salut, aici este modulul meu.')

__versiune__ = '0.1'

# Sfârşitul modulului meu.py

Mai sus a fost un model de modul. Aşa cum vedeţi, nu este nimic deosebit în legătură cu modulele în comparaţie cu programele Python obişnuite. Vom vedea în continuare cum putem să folosim acest modul în programele noastre Python.

Amintiţi-vă că modulul ar trebui plasat în acelaşi director cu programul care îl importă sau într-un director listat în variabila sys.path.

#!/usr/bin/python
# Fişier: meu_demo.py

import meu

meu.zisalut()
print ('Versiunea', meu.__versiune__)

Rezultat:

   $ python meu_demo.py
   Salut, aici este modulul meu.
   Versiunea 0.1

Cum funcţionează:

Observaţi că folosim aceeaşi notaţie cu punct pentru a accesa membrii modulului. Python refoloseşte cu spor aceeaşi notaţie pentru a da un sentiment distinctiv ‘Pythonic’ programelor, astfel încât să nu fim nevoiţi să învăţăm noi moduri de a face lucrurile.

Iată o nouă variantă folosind sintaxa declaraţiei from..import:

#!/usr/bin/python
# Fişier: meu_demo2.py

from meu import zisalut, __versiune__

zisalut()
print('Versiunea', __versiune__)

Rezultatul programului meu_demo2.py este acelaşi ca şi rezultatul programului meu_demo.py.

Observaţi că dacă ar fi existat un nume __versiune__ declarat în modulul care importă modulul meu, ar fi apărut un conflict. Şi asta este probabil, întrucât este o practică uzuală pentru fiecare modul să se declare versiunea sa folosind acest nume. De aceea este întotdeauna recomandabil să se folosească declaraţia import deşi ar putea face programul un pic mai lung.

S-ar mai putea folosi:

from meu import *

Astfel ar fi importate toate numele publice, precum zisalut dar nu s-ar importa __versiune__ pentru ca începe cu dublu underscore.

Calea (Zen) în Python
Un principiu director în Python este “Explicit este mai bine decât implicit”. Rulaţi import this pentru a afla mai multe şi urmăriţi această discuţie care enumeră exemple pentru fiecare din principii.

Funcţia dir

Puteţi folosi funcţia predefinită dir pentru a lista identificatorii pe care îi defineşte un obiect. De exemplu, pentru un modul, clasele şi variabilele definite în acel modul.

Când furnizaţi un nume funcţiei dir(), ea întoarce lista numelor definite în acel modul. Dacă se lansează funcţia fără argumente, ea întoarce lista numelor definite în modulul curent.

Exemplu:

$ python

>>> import sys # obţine lista atributelor, în acest caz, pentru modulul sys

>>> dir(sys)
['__displayhook__', '__doc__', '__excepthook__', '__name__', '__package__', '__s
tderr__', '__stdin__', '__stdout__', '_clear_type_cache', '_compact_freelists',
'_current_frames', '_getframe', 'api_version', 'argv', 'builtin_module_names', '
byteorder', 'call_tracing', 'callstats', 'copyright', 'displayhook', 'dllhandle'
, 'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix', 'executable',
'exit', 'flags', 'float_info', 'getcheckinterval', 'getdefaultencoding', 'getfil
esystemencoding', 'getprofile', 'getrecursionlimit', 'getrefcount', 'getsizeof',
 'gettrace', 'getwindowsversion', 'hexversion', 'intern', 'maxsize', 'maxunicode
', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 'platfor
m', 'prefix', 'ps1', 'ps2', 'setcheckinterval', 'setprofile', 'setrecursionlimit
', 'settrace', 'stderr', 'stdin', 'stdout', 'subversion', 'version', 'version_in
fo', 'warnoptions', 'winver']

>>> dir() # obţine lista atributelor pentru modulul curent['__builtins__', '__doc__', '__name__', '__package__', 'sys']

>>> a = 5 # crează o nouă variabilă, 'a'

>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'a', 'sys']

>>> del a # şterge (engl. delete) un nume

>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'sys']

>>>

Cum funcţionează:

Pentru început, vedem folosirea funcţiei dir asupra modulului importat sys. Putem vedea lista uriaşă de atribute pe care o conţine.

Apoi folosim dir fără parametri. Implicit, ea întoarce lista atributelor modulului curent. Observaţi că lista modulelor importate este inclusă în lista modulului listat.

Pentru a vedea funcţia dir în acţiune, definim o nouă variabilă, a, şi îi atribuim o valoare, apoi testăm cu dir dacă a apărut încă o valoare în lista de atribute a aceluiaşi nume. Eliminăm variabila/atributul modulului curent folosind declaraţia del şi din nou schimbarea este reflectată în rezultatul funcţiei dir.

O notă asupra declaraţiei del – această declaraţie este folosită pentru a şterge un nume de variabila şi după ce a fost executată (del a), nu mai puteţi accesa variabila a – este ca şi cum nu a existat niciodată.

Reţineţi că funcţia dir() lucrează pe orice obiect. De exemplu, rulaţi dir(print) pentru a descoperi atributele funcţiei print sau dir(str) pentru atributele clasei str.

Pachete

La acest nivel, aţi început probabil să observaţi o ierarhie în organizare a programelor. Variabilele sunt de obicei în interiorul funcţiilor. Funcţiile şi variabilele globale intră în module. Dar modulele cum se organizează? Aici intervin pachetele.

Pachetele sunt nişte foldere de module cu un fişier special __init__.py care indică lui Python că acel folder este special, deoarece conţine module Python.

Să zicem că vreţi să creaţi un pachet numit ‘mapamond’ cu subpachetele ‘asia’, ‘africa’, etc. şi aceste pachete conţin la rândul lor module precum ‘india’, ‘madagascar’, ‘românia’ etc.

Iată cum aţi structura folderele:

   - <un folder prezent în sys.path>/
       - mapamond/
           - __init__.py
           - asia/
               - __init__.py
               - india/
                   - __init__.py
                   - foo.py
           - africa/
               - __init__.py
               - madagascar/
                   - __init__.py
                   - bar.py
           - europa/
               - __init__.py
               - românia/
                   - __init__.py
                   - foo_bar.py

Pachetele sunt doar un mod convenabil de a organiza ierarhic modulele. Veţi vedea de multe ori asta în biblioteca Python standard.

Rezumat

Aşa cum funcţiile sunt părţi reutilizabile de program, modulele sunt programe (întregi) reutilizabile. O altă ierarhie de organizare a modulelor o reprezintă pachetele. Biblioteca standard care vine cu Python este un exemplu de set de pachete şi module.

Am văzut cum se folosesc modulele şi cum se creeaza module proprii.

În continuare vom învăţa despre câteva concepte interesante numite ‘structuri de date’.


Advertisements