a byte of python-ro

April 3, 2017 | Author: Marius Eduard Cîrstea | Category: N/A
Share Embed Donate


Short Description

Download a byte of python-ro...

Description

Python ro:Prefaţă Python este probabil singurul limbaj de programare care este şi simplu şi puternic. Asta e bine şi  pentru începători şi pentru experţi şi, cel mai important, este distractiv să programezi cu el. Această  carte îşi propune să ajute la învăţarea acestui limbaj minunat şi să arate cum se fac lucrurile repede  şi fără probleme ­ ca urmare 'antivenin'­ul perfect pentru problemele tale de programare. 

Pentru cine este această carte  Aceasta carte serveşte ca ghid sau tutorial pentru limbajul de programare Python. Este orientată în  principal spre începători, dar este folositor şi pentru programatori avansaţi.  Obiectivul este ca dacă tot ceea ce ştii despre calculatoare este cum să salvezi fişiere text, atunci să  poţi învăţa Python din aceasta carte. Şi dacă ai experienţă prealabilă de programare, de asemenea  poţi învăţa din aceasta carte.  Dacă ai experienţă anterioară, vei fi preocupat de diferenţele între Python şi limbajul tău de  programare favorit ­ am evidenţiat multe asemenea diferenţe. Un mic avertisment, totuşi: Python va  ajunge în curând limbajul tău de programare favorit! 

Lecţie de istorie  Am început lucrul cu Python când aveam nevoie să scriu un installer pentru un program pe care l­ am scris, numit 'Diamond' ca să fac instalarea uşoară. A trebuit să aleg între legăturile Python şi Perl  pentru biblioteca Qt. Am căutat un pic pe net şi am găsit un articol unde Eric S. Raymond, faimosul  şi respectatul hacker, vorbea despre cum a ajuns Python să devină limbajul său favorit. Am mai  descoperit că legăturile PyQt erau mai mature comparativ cu legăturile Perl­Qt. Astfel am decis că  Python era limbajul care îmi trebuie.  Astea fiind făcute, am trecut la căutarea unei cărţi bune de Python. N­am găsit nici una! Am găsit  nişte cărţi O'Reilly, dar erau fie prea scumpe fie erau mai mult manual de referinţe decât ghid.  Aşadar m­am hotărât să folosesc documentaţia inclusă în limbaj. Totuşi, era prea scurtă şi concisă.  Dădea o idee destul de bună despre Python, dar incompletă. M­am descurcat, fiindcă aveam  experienţă anterioară, dar era neadecvată pentru începători.  La circa şase luni după primul meu contact cu Python, am instalat (pe atunci) ultima versiune de  Linux ­ Red Hat 9.0 ­ şi mă jucam cu KWord. M­a entuziasmat şi dintr­o dată mi­a venit ideea de a  scrie ceva despre Python. Am început să scriu şi am ajuns repede la 30 de pagini. Pe urmă am căutat  creşterea utilităţii documentaţiei mele în forma unei cărţi. După o mulţime de rescrieri, aceasta a  atins un stadiu la care putea fi folosită ca ghid util pentru învăţarea limbajului Python. Consider  această carte mica mea contribuţie la comunitatea open source.  Cartea mea a început ca nişte note personale despre Python şi eu o consider aşa în continuare, deşi  am făcut mari eforturi pentru a o face mai plăcută celorlalţi :)  În adevăratul spirit open source, am primit o mulţime de sugestii, critici constructive şi reacţii de la  cititori entuziaşti care m­au ajutat mult să îmbunătăţesc această carte. 

1

Starea cărţii  Modificările de după ultima revizie majoră din martie 2005 sunt actualizari ale lansării Python 3.0  (data de lansare estimată în August/Septembrie 2008). Începând cu Python 3.0, limbajul însuşi nu  este încă finalizat/lansat, deci această carte va suferi constant modificări. Totuşi, în spiritul filosofiei  open source "Lansează în devans, lansează frecvent", cartea actualizată a fost lansată şi va fi  actualizată constant.  Cartea necesită ajutorul cititorilor ei care sa indice orice părţi ale cărţii care nu sunt bune, nu sunt  inteligibile sau sunt greşite. Vă rog scrieţi autorului principal sau traducătorilor comentariile şi  sugestiile voastre.  Este o luptă permanentă să cântăreşti între nevoile începătorului şi tendinţa spre 'completitudinea'  informării. Ar fi folositor dacă cititorii ar lăsa şi reacţia lor în mesaje privind adâncimea până la care  ar trebui să pătrundem în subiect. 

Website oficial  Website­ul oficial al acestei cărţi este acesta, unde se poate citi întreaga carte online, descărca  ultima versiune a cărţii, cumpăra o copie tipărită şi mi se pot trimite reacţiile faţă de carte. 

Licenţă  1. Această carte este licenţiată sub licenţaCreative Commons Attribution­Share Alike 3.0  Unported.  • Ce înseamnă acest lucru:  • Poţi copia, distribui şi transmite această carte mai departe  • Poţi remixa conţinutul ­­ să­l adaptezi cum vrei  • Sub următoarele condiţii:  • Atribuire. Trebuie să specifici cui i se atribuie materialul original dar nu în  aşa fel încât să se înţeleagă că autorul original îţi oferă suport.  • Share Alike. Dacă modifici sau foloseşti această lucrare pentru a crea ceva pe  baza acesteia, trebuie să distribui noul conţinut sub o licenţă similară şi  compatibilă sau sub licenţa originală.  • Pentru orice folosire sau distributie, trebuie să faci clară licenţa sub care se află acest  material  • Oricare dintre condiţiile de mai sus pot fi anulate doar cu permisiunea deţinătorului  de copyright.  • Nimic prevăzut în aceasta licenţă nu atacă drepturile morale ale autorului  2. Atribuirea trebuie arătată prin adaugărea unui link înapoi la autor şi indicarea clară că textul  original se poate downloada de la acea locaţie  3. Întreg codul sursă din această carte este licenţiat sub licenţa BSD cu 3 menţiuni dacă nu se  specifică altă licenţă  4. Contribuţiile de voluntariat la materialul original trebuie să fie sub aceaşi licenţă iar  copyrightul trebuie să rămână al autorului original al acestui material. 

2

Reacţii  Am depus mult efort pentru a face cartea cât mai interesantă şi exactă. Totuşi, dacă apreciaţi unele  părţi că sunt inconsistente sau incorecte sau pur şi simplu consideraţi că necesită îmbunătăţiri, vă  rog să mă informaţi, ca să pot face modificările adecvate. Pot fi contactat prin intermediul paginii  mele de utilizator. 

Cumpăraţi cartea  Dacă vreţi să susţineţi dezvoltarea continuă a acestei cărţi, vă rog să luaţi în calcul posibilitatea de a  cumpăra o copie tipărită sau de a face o donaţie. 

Subiect de gândire  Există două căi de a face un design de software: una este de a­l face atât de simplu încât  în mod evident nu are deficienţe; celălalt este de a­l face atât de complicat încât să nu­i  fie evidente deficienţele.  ­­ C. A. R. Hoare  Succesul în viaţă nu este atât o chestiune de talent şi oportunitate cât de concentrare şi  perseverenţă.  ­­ C. W. Wendte 

3

Python ro:Introducere Introducere  Python este unul dintre puţinele limbaje de programare care pot susţine că sunt în acelaşi timp şi  simple şi puternice. Vei realiza că vei fi în mod plăcut surprins de cât de uşor este să te concentrezi  pe soluţia problemei şi nu pe sintaxa şi structura limbajului în care programezi.  Textul de introducere oficial pentru Python este:  Python este un limbaj uşor de învăţat şi puternic. Deţine structuri de date de nivel înalt  eficiente şi o abordare simplă dar efectivă asupra programării orientate pe obiecte.  Sintaxa elegantă a lui Python şi modul dinamic de selecţie a tipului de date, împreună cu  natura sa de limbaj interpretat, îl face un limbaj ideal pentru scriptare şi pentru  dezvoltare rapidă de aplicaţii în multe domenii şi pe majoritatea platformelor existente.  Majoritatea facilităţilor sale vor fi discutate mai în detaliu în capitolul următor.  Notă  Guido van Rossum, creatorul limbajului Python, şi­a botezat limbajul dupa spectacolul BBC  "Monty Python's Flying Circus" (Circul zburător al lui Monty Python). De fapt el nu prea  agreează şerpii constrictori, care ucid animale pentru hrană strivindu­le. 

Facilităţile lui Python  Simplu  Python este un limbaj simplu şi minimalistic. Citirea unui program bine scris în Python dă  aceeaşi senzaţie ca şi citirea unei nuvele în engleză, deşi cu o gramatică foarte strictă! Această  natură de pseudocod a lui Python este una din marile sale puteri. Ea îţi permite să te  concentrezi asupra soluţiei problemei mai degraba decât asupra limbajului însuşi.  Uşor de învăţat  Aşa cum vei vedea, cu Python este extrem de uşor de început. Python are o sintaxă  extraordinar de simplă.  Gratis şi open source  Python este un exemplu de FLOSS (Free/Libre and Open Source Software). În termeni simpli,  poţi distribui liber copii ale acestui software, citi codul sursă, modifica, folosi părţi din el în  alte programe free. FLOSS se bazează pe conceptul de comunitate care pune cunoştinţe în  comun. Acesta este unul din motivele pentru care Python este aşa de bun ­ el a fost creat şi  îmbunătăţit constant de o comunitate care pur şi simplu îşi doreşte să vadă un Python tot mai  bun.  Limbaj de nivel înalt  Când scrii programe în Python, nu ai nevoie să te preocupi de detalii de nivel scăzut precum  4

managementul memoriei folosite de program etc...  Portabil  Prin natura sa open source, Python a fost portat (modificat ca să funcţioneze) pe multe  platforme. Toate programele tale Python pot funcţiona pe oricare din aceste platforme, fără a  necesita vreo modificare, dacă programezi cu grija de a evita facilităţile dependente de sistem  ale limbajului.  Poţi folosi Python pe Linux, Windows, FreeBSD, Macintosh, Solaris, OS/2, Amiga, AROS,  AS/400, BeOS, OS/390, z/OS, Palm OS, QNX, VMS, Psion, Acorn RISC OS, VxWorks,  PlayStation, Sharp Zaurus, Windows CE şi chiar pe PocketPC !  Limbaj interpretat  Aici sunt necesare câteva explicaţii.  Un program scris întrun limbaj compilat, precum C sau C++ este convertit din limbajul sursă  întrun format acceptat de calculator (codul binar, cu 1 şi 0) folosind un compilator cu diverse  comutatoare şi opţiuni. Când rulezi programul link­editat, software­ul copiază programul de  pe harddisc şi începe să îl execute.  Python, pe de altă parte, nu necesită compilare în binar. Pur şi simplu se lansează programul  direct din codul sursă. Intern, Python converteşte codul sursă întrun format intermediar numit  bytecodes (rom. şir de octeţi), apoi pe acesta îl transformă în limbajul nativ al computerului  (cod maşină) şi apoi îl rulează. În fapt toate acestea fac utilizarea limbajului Python mult mai  uşoară fiindcă nu mai trebuie să porţi grija compilării programului, a verificării alegerii link­ editarii şi încărcării corecte a bibliotecilor etc, etc. Din acelaşi motiv programele scrise în  Python sunt mult mai portabile, doar le copiezi pe alt calculator şi imediat merg!  Limbaj orientat pe obiecte  Python suportă şi programarea procedurală, pe lângă programarea orientată pe obiecte. În  limbajele orientate pe proceduri programele sunt construite în jurul procedurilor şi funcţiilor  acestea nefiind altceva decât porţiuni de program reutilizabile. În limbajele orientate pe  obiecte programul este construit În jurul obiectelor, care combină datele şi funcţionalitatea.  Python are o metodă foarte puternică, dar simplă de a face programare orientată pe obiecte  (OOP), în special în comparaţie cu marile limbaje precum Java sau C++.  Extensibil  Dacă ai nevoie ca o porţiune din codul programului să ruleze foarte rapid sau vrei ca unele  soluţii de algoritm să nu fie open, poţi coda partea aceea în C sau C++ şi poţi apela acea parte  direct din programul Python.  Implantabil  Se poate implanta cod Python în programe C/C++ pentru a le oferi facilităţi de 'scripting'  utilizatorilor programelor.  Biblioteci extinse  Biblioteca standard Python este cu adevărat uriaşă. Te poate ajuta să rezolvi diverse probleme  referitoare la expresii regulare, generare de documentaţie, testare de părţi, gestiune de fire de  execuţie, baze de date, browsere web, CGI, ftp, email, XML, XML­RPC, HTML, fişiere  .WAV, criptografie, GUI (graphical user interfaces), Tk şi alte lucruri dependente de sistem.  Reţineţi, toate acestea sunt prezente unde este instalat Python. Acest lucru este aşa­numita  5

filozofie 'cu baterii incluse' a limbajului Python.  Pe lângă biblioteca standard există diferite alte biblioteci de foarte bună calitate, precum  wxPython, Twisted, Python Imaging Library şi multe altele.  Python este întradevăr un limbaj puternic şi antrenant. Are combinaţia corectă de performanţă şi  facilităţi care fac scrierea de programe în Python şi distractivă şi uşoară. 

De ce nu Perl?  Dacă nu ştiaţi deja, Perl este un alt limbaj de programare open­source interpretat.  Dacă aţi fi încercat vreodată să scrieţi un program mare în Perl, v­aţi fi răspuns singuri la întrebare!  Cu alte cuvinte programele în Perl sunt uşoare când sunt mici şi excelează la mici găselniţe şi  scripturi de 'făcut treaba'. Oricum, ele devin rapid prea complexe îndată ce încep să crească şi vă  spun asta din propria experienţă de autor de programe în Perl la Yahoo!  Comparativ cu Perl, programele Python sunt clar mai simple, mai curate, mai uşor de scris şi astfel  mai uşor de înţeles şi întreţinut. Eu admir Perl­ul şi îl folosesc zilnic pentru diverse lucruri, dar când  încep să scriu un program încep prin a­l gândi în termenii de Python pentru că mie îmi vine mai  natural aşa. Perl a suferit aşa de multe perfecţionări şi schimbări încât el pare a fi o mare (dar foarte  utilă)găselniţă. Regretabil, dar aşteptatul Perl 6 nu pare a face progrese din acest punct de vedere.  Singurul avantaj foarte semnificativ pentru Perl este reţeaua sa de arhive de module CPAN (the  Comprehensive Perl Archive Network). Aşa cum sugerează şi numele ei, CPAN este o colecţie  uriaşă de module Perl care impresionează prin extindere şi profunzime ­ folosind aceste module poţi  face virtual orice. Unul din motivele pentru care Perl are mai multe module ca Python este acela că  el a apărut mai demult decât Python. În orice caz, situaţia asta pare a se schimba datorită indexului  Python Package Index de pachete Python. 

De ce nu Ruby?  Dacă nu stiaţi deja, Ruby este un alt limbaj de programare open­source interpretat.  Dacă deja apreciaţi şi folositi Ruby, atunci în mod cert vă recomand să continuaţi să­l folosiţi.  Pentru ceilalti, care nu l­au folosit şi încearcă să judece dacă să înveţe Ruby sau Python, as  recomanda Python, pe baza criteriului uşurinţei de învătare. Personal, l­am găsit greu de asimilat,  dar cei ce înteleg Ruby propovăduiesc frumuseţea sa. Din nefericire nu sunt atât de norocos. 

Ce spun programatorii  Poate vă interesează să citiţi părerea unor mari hackeri, precum ESR despre Python:  • Eric S. Raymond este autorul lucrării 'Catedrala şi bazarul' fiind de asemenea părintele  termenului 'Open Source'. El spune că Python a devenit limbajul său de programare favorit.  Acel articol a fost o adevărată inspiraţie pentru abordarea primelor mele programe în  Python.  • Bruce Eckel este autorul faimoaselor cărţi 'Gândire în Java' şi 'Gândire în C++'. El spune că  nici un limbaj de programare nu i­a adus o productivitate mai mare ca Python. În plus  Python este probabil singurul limbaj focalizat pe a uşura munca programatorului. Citeşte  6

interviul complet pentru alte detalii.  • Peter Norvig este un binecunoscut autor de programe LISP, director de calitatea căutării la  Google (mulţumiri lui Guido van Rossum pentru acest pont). El spune ca Python a fost  întotdeauna parte integrantă din Google. Îi poţi verifica declaraţia pe pagina Google Jobs  care arată cerinţa obligatorie de cunoştinţe de Python pentru inginerii de software. 

Despre Python 3.0  Python 3.0 este noua versiune în devenire a limbajului. I se mai spune 'Python 3000' sau 'Py3K'.  Motivul principal pentru o nouă versiune majoră a limbajului Python este eliminarea tuturor micilor  probleme şi critici acumulate peste ani şi a face limbajul chiar mai curat.  Daca ai deja mult cod Python versiunea 2.x, există un utilitar pentru a te ajuta să converteşti codul  sursă din versiunea 2.x în versiunea 3.x.  Mai multe detalii în:  •  Introducerea lui Guido van Rossum   •  Ce e nou în Python 2.6  (facilităţi sensibil diferite de versiunile 2.x precedente care probabil  vor fi incluse în Python 3.0)  •  Ce e nou în Python 3.0   •  Python 2.6 şi graficul de lansare al versiunii 3.0   •  Python 3000 (lista oficială definitivă a schimbărilor propuse)   •  Diverse planuri Python 3.0   •  Noutăţi Python (lista detaliată a modificărilor)  

7

Python ro:Instalare Dacă aveţi deja instalat Python 2.x, nu aveţi nevoie să­l eliminaţi înainte de instalarea versiunii  Python 3.0. Le puteţi avea pe ambele în acelaşi timp. 

Pentru utilizatorii Linux şi BSD  Dacă folosiţi o distribuţie de Linux precum Ubuntu, Fedora, OpenSUSE sau {puneţi aici opţiunea  voastră} sau un sistem BSD precum FreeBSD, atunci foarte probabil aveţi deja instalat Python în  sistem.  Pentru a verifica dacă aveţi Python deja instalat în sistemul Linux, deschideţi un program shell  (precum konsole sau gnome-terminal) şi daţi comanda python -V cum este arătat mai  jos.  $ python -V Python 3.0b1

Notă 

$ este promptul shellului. Acesta poate fi diferit pentru voi, în funcţie de setările sistemului de  operare, de aceea eu îl voi arăta restrâns la doar simbolul $. 

Dacă se afişează informaţii despre versiune, înseamnă că aveţi deja instalat Python.  Totuşi, dacă va da un răspuns ca mai jos:  $ python -V bash: Python: command not found

înseamnă că nu aveţi Python instalat. Asta este foarte atipic, dar posibil.  În acest caz aveţi două căi de a instala Python în sistem.  • Puteţi compila şi instala Python din codul sursă. Instrucţiunile de compilare sunt date în  acelaşi website.  • [Aceasta opţiune va fi disponibilă după lansarea finală a versiunii Python 3.0]. Instalaţi  pachetele binare folosind programele de management de pachete specifice sistemului de  operare (apt-get pentru Ubuntu/Debian şi altele bazate pe Debian, yum în Fedora,  pkg_add în FreeBSD, etc.) Reţineţi că va trebui să aveţi acces internet pentru a folosi  această opţiune. Alternativ, puteţi descărca executabilele binare precompilate pentru  platforma voastră din altă parte şi le puteţi copia şi instala în PC. 

Pentru utilizatorii Windows  Vizitaţi http://www.python.org/download/releases/3.0/ şi descarcaţi ultima versiune, care era 3.0  beta 1 la momentul acestei scrieri. Sunt doar 12.8 MB ceea ce este foarte compact in comparaţie cu  majoritatea altor limbaje şi softuri. Instalarea este la fel ca la orice software pentru Windows.  Atenţionare  8

Daca vi de da opţiunea de a debifa componente optionale, NU DEBIFAŢI NIMIC! Unele vă  pot fi foarte folositoare, în special IDLE.  Un fapt interesant este că majoritatea descărcărilor de Python sunt făcute de utilizatori Windows.  Desigur, asta nu dă o imagine completă întrucât majoritatea utilizatorilor de Linux au Python  preinstalat. 

DOS Prompt  Daca vreţi să puteţi folosi Python de la linia de comandă Windows (sau DOS prompt), trebuie să  setaţi corespunzator variabila %PATH%.  În Windows 2000, XP, 2003, click pe Control Panel ­> System ­> Advanced ­>  Environment Variables. Click pe variabila numită PATH în secţiunea 'System Variables',  apoi selectaţi Edit şi adăugaţi ;C:\Python30 la sfârşitul a ceea ce există deja acolo. Desigur,  folosiţi numele corect al directorului.  Pentru versiuni mai vechi de Windows, adăugaţi în fişierul C:\AUTOEXEC.BAT urmatoarea linie:  'PATH=%PATH%;C:\Python30' (fără ghilimele) şi restartaţi sistemul. În Windows NT, folosiţi  fişierul AUTOEXEC.NT. 

Pentru utilizatorii de Mac OS X  Utilizatorii de Mac OS X vor găsi Python preinstalat în sistem. Deschideţi Terminal.app, rulaţi  python -V şi urmaţi recomandarea pentru utilizatorii de Linux. 

Rezumat  Pe un sistem Linux, foarte probabil că deja aveţi Python instalat în sistem. În caz contrar, îl puteţi  instala folosind programul de management de pachete specific distribuţiei de Linux respective. În  cazul unui sistem Windows, instalarea lui Python este la fel de uşoară ca şi descărcarea installerului  şi lansarea lui. De acum încolo vom presupune că aveţi Python instalat pe sistem.  În continuare vom scrie primul nostru program în Python. 

9

Python ro:Primii paşi Introducere  Vom afla acum ce trebuie făcut pentru a rula tradiţionalul program 'Hello World' în Python. Astfel  vom învăţa cum să scriem, salvăm şi rulăm programe Python.  Sunt doua căi de a folosi Python pentru a rula un program ­ folosind promptul interactiv al  interpretorului sau folosind fişierul sursă. Vom afla cum se folosesc ambele metode. 

Folosind promptul interpretorului  Porniţi interpretorul de la linia de comandă introducând python la prompt.  Pentru utilizatorii de Windows, puteţi rula interpretorul din linia de comandă dacă aveţi setată corect  variabila PATH.  Dacă folosiţi IDLE (de la Integrated Developpement Linux Environment), dati clic pe Start →  Programs → Python 3.0 → IDLE (Python GUI).  Acum introduceţi print('Hello World') urmat de tasta Enter. Ar trebui să vedeţi ca  rezultat cuvintele Hello World.  $ python Python 3.0b2 (r30b2:65106, Jul 18 2008, 18:44:17) [MSC v.1500 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> print('Hello World') Hello World >>>

Observaţi că Python va da rezultatul comenzii imediat! Ceea ce tocmai aţi introdus este o declaraţie  Python singulară. Folosim print pentru (nesurprinzator) a tipări orice valoare pe care i­o  furnizăm. Aici îi furnizăm textul Hello World şi acesta este tipărit rapid pe ecran.  Cum să părăsiţi interpretorul  Ca să părăsiţi prompt­ul, tastaţi Ctrl-D dacă folosiţi IDLE sau un shell Linux/BSD. În cazul  consolei Windows (Command prompt), tastaţi Ctrl-Z urmat de tasta ENTER. 

Alegerea unui editor  Înainte de a trece la scrierea de programe Python În fişiere sursă avem nevoie de un editor pentru a  crea aceste fişiere. Alegerea editorului este crucială. Trebuie ales la fel ca şi maşinile. Un editor bun  vă va ajuta să scrieţi programe Python uşor, făcând timpul petrecut o călătorie confortabilă şi vă va  ajuta să ajungeţi la destinaţie (să vă atingeţi obiectivul) întro maniera rapidă şi sigură.  O cerinţă de bază este evidenţierea sintaxei [1] în care diferitele componente ale sintaxei sunt  colorate de aşa natură încât să poţi vizualiza programul şi rularea lui.  10

Dacă utilizaţi Windows, vă recomand să folosiţi IDLE. IDLE face syntax highlighting şi multe  altele printre care faptul că vă permite să rulaţi programele tot în IDLE. O notă specială: Nu folosiţi  Notepad ­ este o opţiune rea fiindcă nu face syntax highlighting şi nu suportă indentarea textului,  ceea ce este foarte important în cazul nostru, aşa cum veţi vedea în continuare. Editoarele bune  precum IDLE (şi VIM) vă vor ajuta automat să indentaţi textul.  Dacă utilizaţi Linux/FreeBSD, atunci aveţi o mulţime de opţiuni pentru editor. Dacă sunteţi chiar la  începutul carierei de programator, poate o să preferaţi 'geany'. Are interfaţă grafică cu utilizatorul şi  butoane speciale pentru compilat şi rulat programele Python fără complicaţii.  Dacă sunteţi programator experimentat, atunci probabil că folosiţi deja Vim sau Emacs. Nu mai e  nevoie să precizăm că acestea două sunt cele mai puternice editoare şi veţi avea nenumărate avantaje  din folosirea lor la scrierea de programe Python. Eu personal folosesc Vim pentru majoritatea  programelor. Dacă sunteţi programator începător, puteţi folosi Kate care este unul din favoritele  mele. În cazul în care doriţi să alocaţi timpul necesar învăţării lucrului cu Vim sau Emacs, vă  recomand să le învăţaţi pe amândouă, întrucât pe termen lung veţi culege foloase mult mai mari.  În această carte vom folosi IDLE, editorul nostru IDE cel mai recomandat. IDLE este instalat în  mod implicit de către installerele Python pentru Windows şi Mac OS X. Este disponibil şi pentru  Linux şi BSD în colecţiile ('engl. repositories') respective.  Vom explora folosirea mediului IDLE în capitolul următor. Pentru mai multe detalii, vă rog să  vizitaţi documentaţia IDLE .  Dacă tot mai doriţi să vedeţi şi alte opţiuni pentru editor, recomand cuprinzătoarea listă de editoare  pentru Python şi să optaţi. Puteţi alege şi un IDE (Integrated Development Environment) pentru  Python. A se vedea lista de medii integrate (IDE) care suportă Python pentru detalii suplimentare.  Imediat ce veţi începe să scrieţi programe Python mari, IDE­urile pot fi cu adevărat foarte  folositoare.  Repet, vă rog să alegeţi un editor adecvat ­ el poate face scrierea de programe Python mai distractivă  şi uşoară.  Pentru utilizatorii de Vim  Există o introducere bună despre 'Cum să faci Vim un IDE puternic pentru Python' de John M  Anderson.  Pentru utilizatorii de Emacs  Există o introducere bună despre 'Cum să faci Emacs un IDE puternic pentru Python' de Ryan  McGuire. 

Folosind un fişier sursă  Să ne întoarcem la programare. Există o tradiţie ca de câte ori înveţi un nou limbaj de programare,  primul program pe care îl scrii să fie programul 'Hello World' ­ tot ce face el este să afişeze 'Hello  World' când îl rulezi. După expimarea lui Simon Cozens [2], este 'incantaţia tradiţională către zeii  programării ca sa te ajute să înveţi limbajul mai bine' :) .  Porniţi editorul ales, introduceţi programul următor şi salvaţi­l sub numele helloworld.py  Dacă folosiţi IDLE, daţi clic pe File → New Window şi introduceţi programul de mai jos. Apoi  clic pe File → Save.  #!/usr/bin/python

11

#Fisier: helloworld.py print('Hello World')

Rulaţi programul deschizând un shell [3] şi introducând comanda python helloworld.py.  Daca folosiţi IDLE, deschideţi meniul Run → Run Module sau direct F5 de pe tastatură.  Rezultatul este afişat astfel:  $ python helloworld.py Hello World

Daca aţi obţinut rezultatul afişat mai sus, felicitări! ­ aţi rulat cu succes primul program în Python.  În caz ca aţi obţinut un mesaj de eroare, vă rog, tastaţi programul anterior exact ca în imagine şi  rulaţi programul din nou. De reţinut că Python este case­sensitive [4] aşadar print nu este acelaşi  lucru cu Print ­ observaţi p minuscul în primul exemplu şi P majuscul în al doilea exemplu. De  asemenea, asiguraţi­vă că nu există spaţii sau TAB înaintea primului caracter din fiecare linie ­ vom  vedea mai târziu de ce este atât de important. 

Cum funcţionează  Să considerăm primele două linii din program. Acestea sunt numite comentarii ­ orice s­ar afla la  dreapta caracterului # devine comentariu şi este util în special pentru documentarea cititorului  programului.  Python foloseşte comentarii numai pentru acest caz. Prima linie este numita linie shebang ­ de  fiecare dată când începe cu #! urmată de locaţia unui program; asta spune sistemului nostru  Linux/Unix că fişierul trebuie înteles prin acest interpretor atunci când este executat. O explicaţie  mai detaliată va fi prezentată în capitolele următoare. De reţinut că puteţi rula oricând programul pe  orice platformă specificând interpretorul în linia de comandă, ca în exemplul python helloworld.py .  Important  Folosiţi cu grijă comentarii în programe pentru a explica detalii importante ale unor  instrucţiuni ­ Asta va ajuta cititorul să înţeleagă mai uşor ce 'face' programul. Acel cititor  puteţi fi dumneavoastră, peste şase luni!  Comentariile sunt urmate de o declaraţie Python. În cazul nostru apelăm funcţia print care pur şi  simplu tipăreşte pe ecran textul 'Hello World'. Vom învăţa despre funcţii într­un alt capitol; ce  trebuie reţinut acum este că orice am fi pus în paranteze ar fi aparut pe ecran. În acest caz punem  'Hello World', ceea ce se poate numi string ­ fiţi fără grijă, vom explora mai târziu  terminologia aceasta în detaliu. 

Programe Python executabile  Partea aceasta se aplică numai utilizatorilor de Linux/Unix, dar utilizatorii de Windows ar putea fi  curioşi în legătură cu prima linie din program. Pentru început, va trebui să dăm fişierului  permisiunea de a fi executabil folosind comanda chmod şi apoi să rulăm programul sursă.  $ chmod a+x helloworld.py $ ./helloworld.py Hello World

12

Comanda chmod este folosită aici pentru a schimba [5] mod­ul fişierului dându­i drept de execuţie  pentru toţi [6] utilizatorii sistemului. Pe urmă executăm programul direct, specificând locaţia  programului sursă. Folosim ./ pentru a indica localizarea programului executabil în directorul  curent.  Pentru a face lucrurile şi mai distractive, puteţi redenumi fişierul cu numele helloworld şi îl  puteţi rula cu ./helloworld şi tot va merge, folosind interpretorul de la locaţia specificată pe  primul rând din fişier..  Ce e de făcut dacă nu ştim unde este localizat Python? Atunci puteţi folosi programul env specific  sistemelor Linux. Modificaţi primul rând astfel:  #!/usr/bin/env python

Programul env la rândul lui va căuta interpretorul Python care va rula programul.  Până acum am putut să executăm programele noastre doar dacă ştiam calea exactă. Dar dacă dorim  să rulăm programul din orice director? Putem să facem asta dacă memorăm programul întrunul din  directoarele listate în variabila de mediu PATH. Oridecâte ori rulaţi vreun program, sistemul caută  acel program în directoarele listate în variabila PATH şi apoi rulează programul. Putem face  programul nostru disponibil în orice director prin copierea programului întrunul din directoarele din  PATH.  $ echo $PATH /usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/home/swaroop/bin $ cp helloworld.py /home/swaroop/bin/helloworld $ helloworld Hello World

Putem afişa conţinutul variabilei PATH folosind comanda echo şi prefixând numele variabilei cu  caracterul $ pentru a­i transmite shell­ului că avem nevoie de valoarea acestei variabile. Observăm  că /home/swaroop/bin este printre directoarele din PATH, unde swaroop este numele de  utilizator [7] pe care eu îl folosesc în sistemul meu. Există unul similar pentru numele de utilizator  al fiecaruia pe sistemul său. Ca alternativă, puteţi adăuga un director anume la variabila PATH ­ se  face executând PATH=$PATH:/home/swaroop/mydir unde '/home/swaroop/mydir' este directorul pe care eu vreau sa­l adaug la variabila PATH. Această metodă este foarte utilă dacă  vreţi să scrieţi scripturi utile pe care vreţi să le rulaţi oricând din orice locaţie a sistemului. Seamănă  cu a­ţi crea propriile comenzi, precum cd sau orice altă comandă pe care o execuţi în terminalul  Linux sau DOS prompt.  Atenţie  Din punctul de vedere al Python­ului, program sau script sau software înseamnă acelaşi lucru! 

Cum obţinem ajutor  Dacă aveţi nevoie repede de informaţii despre vreo funcţie sau declaraţie din Python, atunci puteţi  apela la functionalitatea inclusă [8] help. Este foarte folositor, mai ales la promptul interpretorului.  De exemplu rulaţi help(print) ­ se va afişa documentaţia de asistenţă pentru funcţia print folosită pentru afişarea pe ecran.  Notă  Tastaţi q pentru a ieşi din help.  13

Similar, puteţi obţine informaţii despre aproape orice din Python. Folosiţi help() pentru a afla  mai multe despre însuşi help!  În cazul în care aveţi nevoie de ajutor în legătură cu operatori precum return, atunci va trebui să­i  puneţi în ghilimele (ca în help('return')) pentru ca Python să inţeleagă fără confuzie ce  încercaţi să faceţi. 

Rezumat  Acum ar trebui să puteţi scrie, salva şi rula cu uşurinţă programe Python. Pentru ca aţi devenit  utilizator de Python, să mai învăţăm câteva concepte din Python. 

Referinţe:  1. 2. 3. 4. 5. 6. 7. 8.

 ↑  engl. syntax highlighting   ↑  autorul minunatei cărţi 'Beginning Perl'   ↑  terminal Linux sau DOS prompt   ↑  sensibil faţă de cazul caracterelor n.tr. minuscule/majuscule   ↑  engl. change   ↑  engl. all   ↑  engl. username   ↑  engl. built­in

14

Python ro:Elemente Simpla tipărire a textului 'Hello World' nu ajunge, aşa­i? Vreţi să faceţi mai mult de atât ­ vreţi să  preluaţi ceva intrări, să le prelucraţi şi să obţineţi un rezultat. Putem face asta în Python folosind  constante şi variabile. 

Constante literale  O constanta literală este un număr precum 5, 1.23, 9.25e-3 sau un şir [1] precum 'Acesta este un şir' sau "E string!". Se numeşte literal fiindcă este folosit literal ­ îi folosim  valoarea literalmente. Numărul 2 se reprezintă întotdeauna pe sine şi nimic altceva ­ este o  constantă deoarece valoarea sa nu poate fi schimbată. De aici denumirea de constante literale. 

Numere  Numerele în Python sunt de trei tipuri ­ integer, float şi complex.  • Un exemplu de integer (rom. întreg) este 2 care este un număr întreg.  • Exemple de float sau floating point [2] sunt 3.23 şi 52.3E-4. Notaţia E indică puterile lui  10. În acest caz, 52.3E-4 înseamnă 52.3 * 10-4.  • Exemple de numere complexe sunt (-5+4j) şi (2.3 - 4.6j)  Notă pentru programatorii experimentaţi  Nu există un tip separat 'long int'. Tipul implicit integer poate fi orice valoare mare. 

Şiruri  Un şir (engl. string) este o secvenţă de caractere. Şirurile sunt în esenţă doar o succesiune de  cuvinte. Cuvintele pot fi în limba engleză sau în orice altă limbă suportată de standardul Unicode,  ceea ce înseamnă aproape orice limbă din lume.  Notă pentru programatorii experimentaţi  Nu există şiruri "ASCII" pure pentru că Unicode este un superset al ASCII. Dacă se impune în  program un flux de octeţi codat ASCII, atunci folosiţi str.encode("ascii"). Pentru  detalii, urmăriţi discuţia pe acest subiect de la StackOverflow.  Implicit, toate şirurile sunt în Unicode.  Aproape pot garanta că veţi folosi şiruri în aproape toate programele Python pe care le scrieţi, aşa că  acordaţi atenţie părţii următoare despre cum se folosesc şirurile în Python. 

Ghilimele simple  Puteţi specifica şiruri folosind ghilimele simple [3] precum 'Citeaza-ma referitor la acest subiect'. Tot spaţiul alb precum SPACE şi TAB sunt păstrate ca atare [4]. 

15

Ghilimele duble  Şirurile în ghilimele duble [5] funcţioneaza la fel ca şi cele în ghilimele simple. De exemplu "Cum te cheamă?" 

Ghilimele triple  Puteţi specifica şiruri care se întind pe mai multe linii folosind ghilimele triple (engl. triple quotes) ­  (""" sau '''). Puteţi folosi liber ghilimele simple dau duble în interiorul ghilimelelor triple. Iată un  exemplu:  '''Acesta este un şir multi-linie. Aceasta este prima linie. Aceasta este a doua linie. 'Cum te numeşti?', l-a intrebat. El a zis "Bond, James Bond". '''

Secvenţe de evadare  Să presupunem că vrem să utilizăm un şir care conţine un apostrof (una din ghilimele simple) '.  Cum o să specificăm şirul What's your name?. Nu­l putem specifica 'What's your name?' pentru că Python va confunda apostroful cu sfârşitul şirului. Într­un fel sau altul va trebui  să specificăm că acel apostrof face parte din şir, nu este un delimitator. Pentru aceasta se foloseşte o  secvenţă de evadare [6]. Specificăm apostroful \' ­ observaţi backslash­ul. Astfel putem specifica  şirul 'What\'s your name?'.  Altă cale de a specifica acest şir este utilizarea ghilimelelor duble pentru delimitarea sirului.  Problema apare şi la includerea unei ghilimele duble într­un şir delimitat cu ghilimele duble. Şi  pentru evadarea backslash­ului trebuie tot backslash \\.  Dar dacă am vrea să specificăm un şir pe două rânduri? O soluţie este să folosim ghilimele triple  cum am văzut mai devreme, dar putem să folosim o secvenţă de evadare pentru sfârşitul liniei ­ \n pentru a indica trecerea pe o linie nouă. Un exemplu ar fi Aceasta este prima linie\nAceasta este a doua linie. Alt exemplu util de secvenţă de evadare este  pentru TAB ­ \t. Există mult mai multe, dar le­am prezentat aici pe cele mai folosite de noi.  Un lucru notabil este că într­un şir un backslash la sfârşitul liniei arată continuarea şirului pe linia  următoare, fără să se adauge caracterul newline. De exemplu:  "Aceasta este prima propoziţie. \ Aceasta este a doua propoziţie".

este echivalent cu "Aceasta este prima propoziţie. Aceasta este a doua propoziţie". 

Şiruri brute  Dacă aveţi nevoie să specificaţi şiruri în care să nu fie procesate secvenţe de evadare trebuie să  folosiţi şiruri brute [7] prefixând şirul cu r sau R. De exemplu r"Caracterul newline este indicat de \n". 

16

Şirurile sunt imuabile  Asta înseamnă că odată create, nu mai pot fi modificate. Deşi pare un lucru rău, nu este. Vom vedea  în diferitele programe prezentate de ce asta nu este o limitare. 

Concatenarea literalilor şir  Dacă se alătura doi literali, eu sunt concatenaţi de Python automat. De exemplu 'What\'s ' 'your name?' este convertit automat în "What's your name?".  Notă pentru programatorii C/C++  Nu există în Python un tip de date separat char. Nu există nici o nevoie reală de aşa ceva,  deci sunt sigur că n­o să­i duceţi dorul.  Notă pentru programatorii Perl/PHP  Reţineţi ca şirurile delimitate de gihilimele simple sau duble sunt la fel, nu diferă prin nimic.  Notă pentru utilizatorii de expresii regulare  Folosiţi întotdeauna şiruri brute cand aveţi de­a face cu expresii regulare, altfel o să fie nevoie  de multe căutări în urmă pentru a găsi ce nu merge. De exemplu referinţele retroactive [8] pot  fi utilizate ca '\\1' sau r'\1'. 

Metoda format  Uneori vrem să construim şiruri din alte informaţii. Aici este folositoare metoda format().  #!/usr/bin/python # Fişier: str_format.py vârstă = 25 nume = 'Swaroop' print('{0} are {1} de ani.'.format(nume, vârstă)) print('De ce se joacă {0} cu python-ul ăla?'.format(nume))

Rezultat:  $ python str_format.py Swaroop are 25 de ani. De ce se joacă Swaroop cu python-ul ăla?

Cum funcţionează:  Un şir poate folosi anumite specificaţii şi apoi poate apela metoda format pentru a substitui acele  specificaţii care corespund argumentelor metodei format.  Observaţi prima folosire, unde folosim {0} şi asta corespunde cu varibila nume care este primul  argument al metodei format. Similar, a doua specificaţie este {1} corespunzatoare variabilei  vârstă care este al doilea argument pentru metoda format.  Observaţi că puteam obţine acelaşi lucru prin concatenare: nume + ' are ' + str(vârstă) + ' de ani', dar uite ce urâtă şi predispusă la erori este această cale. În al  doilea rând, conversia în şir este făcută automat de metoda format în locul unei conversii  explicite. În al treilea rând, folosind metoda format putem schimba mesajul fără să avem de­a face  17

cu variabilele şi reciproc.  Ce face Python în metoda format este că înlocuieşte valoarea fiecărui argument în locurile  specificate. Pot exista şi specificări mai detaliate, cum ar fi:  >>> '{0:.3}'.format(1./3) # zecimal (.) precizie de 3 zecimale pentru float '0.333' >>> '{0:_^11}'.format('hello') # umple până la 11 caractere cu textul centrat şi bordat cu underscore (_) '___hello___' >>> '{nume} a scris {carte}.'.format(nume='Swaroop', carte='Un pic de Python') # pe bază de cuvinte-cheie 'Swaroop a scris Un pic de Python.'

Detalii despre aceste specificaţii de formatare sunt date în PEP 3101 (PEP=Python Enhancement  Proposal). 

Variabile  Folosirea exclusiv a literalilor poate deveni rapid plictisitoare ­ avem nevoie să stocăm orice  informaţie şi să o prelucrăm. Aici este locul variabilelor. Variabilele sunt exact ceea ce spune  numele lor ­ valoarea lor poate fi modificată, va să zică se poate stoca orice întro variabilă.  Variabilele sunt nişte mici zone din memoria calculatorului unde se stochează nişte informaţie. Spre  deosebire de constante, e nevoie de a accesa această informaţie, din acest motiv variabilele au nume. 

Nume de identificatori  Variabilele sunt exemple de identificatori. Identificatorii sunt nume date pentru a identifica ceva.  Există câteva reguli care trebuie să fie urmate la stabilirea identificatorilor:  • Primul caracter al numelui trebui să fie o litera a alfabetului (majusculă ASCII, minusculă  ASCII, caracter Unicode) sau underscore ('_').  • Restul numelui identificatorului poate include şi cifre (de la 0 la 9).  • Pentru numele de identificatori majusculele si minusculele sunt considerate diferite (engl.  case­sensitive). De exemplu, myname şi myName nu desemnează aceeaşi variabilă.  Observaţi minuscula n în primul caz şi majuscula N în al doilea.  • Exemple de nume valide de identificator sunt i, __chiar_aşa, nume_23, a1b2_c3 şi  resumé_count.  • Exemple de nume invalide de identificator sunt 2chestii, asta contine spaţii şi  cal-breaz. 

Tipuri de date  Variabilele pot lua valori de diferite tipuri numite tipuri de date. Tipurile de bază sunt numere şi  şiruri, despre care am discutat deja. În ultimele capitole vom învăţa cum să creăm propriile noastre  tipuri de date, folosind clase. 

Obiecte  Reţineţi, Python consideră că tot ce se foloseşte în program este obiect, în sens generic. În loc de a  18

spune ceva­ul, spunem obiectul.  Notă pentru utilizatorii de POO Python este puternic orientat pe obiecte în sensul că toate sunt obiecte, inclusiv numerele, şirurile şi  funcţiile.  Acum vom vedea cum se folosesc variabilele împreună cu literalii. Salvaţi următorul program şi  rulaţi­l.  Cum se scriu programele Python  De acum încolo, procedura standard de a salva şi rula programele Python este astfel:  1. Deschideţi editorul preferat.  2. Introduceţi codul programului dat în exemplu.  3. Salvaţi­l întrun fişier cu numele menţionat în comentariu. Eu urmez convenţia de a  salva toate programele Python în fişiere cu extensia .py.  4. Rulaţi­l folosind interpretorul cu comanda python program.py sau folosiţi IDLE  pentru a rula programe. De asemenea puteţi folosi metoda executabilă cum am explicat  mai devreme. 

Exemplu: Folosirea variabilelor şi a literalilor  # Fişier : var.py i = 5 print(i) i = i + 1 print(i) s = '''Acesta este un şir multi-linie. Aceasta este linia a doua.''' print(s)

Rezultat:  $ python var.py 5 6 Acesta este un şir multi-linie. Aceasta este linia a doua.

Cum funcţionează:  Iată cum lucrează programul: întâi, atribuim valoarea constantei literale 5 variabilei i folosind  operatorul de atribuire (=). Aceasta linie este o declaraţie deoarece susţine că trebuie făcut ceva, în  acest caz, conectăm variabila i la valoarea 5. În continuare, tipărim valoarea lui i folosind  declaraţia print care, previzibil, tipăreste valoarea variabilei pe ecran.  Apoi adăugăm 1 la valoarea stocată în i şi păstrăm noul rezultat. Tipărim valoarea variabilei şi  obţinem ce am prevăzut, valoarea 6.  Similar, atribuim literalul şir variabilei s şi o tipărim.  Notă pentru programatorii în limbaje cu tipuri statice  Variabilele sunt folosite prin simpla atribuire a unei valori. Nu este necesară nici o declaraţie  19

sau definiţie de tip de date. 

Linii logice şi linii fizice  O linie fizică este ceea ce vedeţi când scrieţi programul. O linie logică este ceea ce vede Python ca o  singură declaraţie. Python presupune implicit că fiecare linie fizică corespunde unei linii logice.  Un exemplu de linie logică este o declaraţie precum print('Hello World') ­ dacă aceasta  este singură pe linie (cum se vede în editor), atunci ea corespunde şi unei linii fizice.  Implicit, Python încurajează folosirea unei singure linii logice pe linia fizică (rând), ceea ce face  codul mult mai lizibil.  Dacă vreţi să specificaţi mai mult de o linie logică pe linie fizică, va trebui să specificaţi explicit  încheierea liniei logice cu (;). De exemplu,  i = 5 print(i)

este efectiv la fel ca  i = 5; print(i);

şi acelaşi lucru poate fi scris  i = 5; print(i);

sau chiar  i = 5; print(i)

Totuşi, recomand cu tărie să rămâneţi la scrierea cel mult a unei singure linii logice pe fiecare  linie fizică. Prin folosirea mai multor linii logice pe o linie fizică se obţine realmente cod mai lung.  Ideea este să se evite semnul punct şi virgulă la maxim posibil pentru a obţine un cod cât mai lizibil.  De fapt, eu n­am folosit niciodată şi nici n­am văzut punct şi virgulă într­un program Python.  Să dăm un exemplu de linie logică întinsă pe mai multe linii fizice, care se numeşte reunire  explicită a liniilor.  s = 'Acesta este un şir \ care continuă pe a doua linie.' print(s)

Se obţine rezultatul:  Acesta este un şir care continuă pe a doua linie.

Similar,  print\ (i)

este la fel ca  print(i)

20

Există şi reunire implicită a liniilor, conform unei prezumţii care elimină nevoia de backslash. Este  cazul în care linia logică foloseşte paranteze rotunde, paranteze drepte sau acolade. Le veţi vedea în  acţiune când vom scrie programe folosind liste în capitolele finale. 

Indentarea  Spaţiul alb este important în Python. De fapt, spaţiul alb la începutul liniei este important. Acesta  se numeşte indentare. Spaţiul alb (spaţii şi taburi) de la începutul liniei logice este folosit pentru a  determina nivelul de indentare al liniei logice, care la rândul lui este folosit pentru a determina  gruparea declaraţiilor.  Asta înseamnă că declaraţiile care merg împreună trebuie să aibă aceeaşi indentare. Fiecare astfel  de set de declaraţii se numeşte bloc. Vom vedea exemple despre importanţa blocurilor în capitolele  următoare.  Un lucru demn de reţinut este că indentarea greşită poate produce erori. De exemplu:  i = 5 print('Valoarea este ', i) # Eroare! Observaţi un spaţiu la începutul liniei. print('Repet, valoarea este ', i)

Când rulaţi asta, obţineţi următoarea eroare:  File "whitespace.py", line 4 print('Valoarea este ', i) # Eroare! Observaţi un singur spaţiu la începutul liniei. ^ IndentationError: unexpected indent

Observaţi că există un spaţiu la începutul liniei a doua. Eroarea indicată de Python ne spune că  sintaxa este greşită, adică programul nu a fost scris corespunzător. Asta înseamnă că nu poţi începe  în mod arbitrar noi blocuri de declaraţii ­ cu excepţia blocului principal[9] implicit pe care l­aţi  folosit tot timpul. Cazurile în care puteţi folosi un nou bloc de declaraţii vor fi detaliate în capitolele  finale, cum ar fi capitolul despre controlul execuţiei.  Cum se indentează  Nu folosiţi un amestec de SPACE şi TAB fiindcă programele nu vor lucra corect pe toate  platformele. Vă recomand călduros să folosiţi un singur TAB sau patru spaţii pentru fiecare  nivel de indentare.  Alegeţi oricare din aceste stiluri de indentare. Şi mai important, alegeţi un stil şi folosiţi­l în  mod consistent şi exclusiv.  Notă pentru programatorii în limbaje cu tipuri statice  Python va folosi mereu indentarea pentru blocuri şi niciodată acolade. Rulaţi from __future__ import braces pentru a afla mai multe detalii. 

Rezumat  Acum că am trecut prin multe detalii esenţiale, putem continua cu lucruri mai interesante cum ar fi  declaraţii pentru controlul execuţiei. Asiguraţi­vă că aţi înţeles ce aţi învatat în acest capitol. 

21

22

Python ro:Operatori şi expresii Introducere  Majoritatea declaraţiilor (linii logice) pe care le scrieţi conţin expresii. Un exemplu de expresie  simplă este 2 + 3. O expresie poate fi descompusă în operatori şi operanzi.  Operatorii sunt functionalităţi care execută ceva şi pot fi reprezentaţi prin simboluri precum + sau  prin cuvinte cheie speciale. Operatorii au nevoie de nişte date asupra cărora să opereze, numite  operanzi. În acest caz, 2 şi 3 sunt operanzii. 

Operatori  Vom arunca o privire rapidă asupra operatorilor şi a folosirii lor:  Reţineţi că puteţi evalua expresiile date în exemple folosind interactiv interpretorul. De exemplu,  pentru a testa expresia 2 + 3, folosind interactiv interpretorul Python:  >>> 2 + 3 5 >>> 3 * 5 15 >>>

Operatori şi folosirea lor Operator 



­ 



Nume 

Explicaţie 

Exemple 

Plus 

adună două obiecte 

3 + 5 fac 8 'a' + 'b' fac 'ab'. 

Minus 

fie face un număr să  fie negativ fie dă  diferenţa între două  numere 

-5.2 face negativ numărul 5.2 50 - 24 fac 26. 

Inmulţire 

dă produsul a două  numere sau repetarea  unui şir de numărul  specificat de ori 

2 * 3 fac 6 'la' * 3 dă 'lalala'. 

23

** 

Putere 

dă x la puterea y 

3 ** 4 dă 81 (adică 3 * 3 * 3 * 3) 



Împărţire 

împarte x la y 

4 / 3 dă 1.3333333333333333. 

// 

Împărţire  întreagă 

dă partea întreagă a  câtului 

4 // 3 fac 1. 



Modulo 

dă restul împărţirii 

8 % 3 fac 2 -25.5 % 2.25 fac 1.5. 

Translaţie la  stânga 

Translateaza biţii unui  număr la stânga cu  numărul specificat de  biţi. (Orice număr  este reprezentat în  memorie sub forma  de biţi ­ cifre binare 0  şi 1) 

2 > 

Translaţie la  dreapta 

Translateaza biţii  numărului la dreapta  cu numărul specificat  de biţi. 

11 >> 1 dă 5 11 este reprezentat în biţi prin 1011 care translatat la dreapta cu un bit dă  101 ceea ce reprezintă numărul 5. 



AND 

ŞI binar între numere 

5 & 3 da 1. 



OR 

SAU binar între  numere 

5 | 3 dă 7 



XOR 

SAU exclusiv binar  între numere 

5 ^ 3 fac 6 



Complement  binar 

complementul lui x  este ­(x+1) 

~5 dă -6. 

număr print('Gata') # Aceasta ultimă declaraţie este executată întotdeauna, după declaraţia if

Rezultat:  $ python if.py Introduceţi un întreg : 50 Nu, e un pic mai mic. Gata $ python if.py Introduceţi un întreg : 22 Nu, e un pic mai mare. Gata

30

$ python if.py Introduceţi un întreg : 23 Felicitări, aţi ghicit, dar nu câştigaţi niciun premiu! Gata

Cum funcţionează:  În acest program preluăm de la utilizator încercări de a ghici numărul şi verificăm dacă este  numărul memorat. Setăm variabila număr la ce valoare vrem, să zicem 23. Apoi preluăm numărul  încercat de utilizator folosind funcţia input(). Funcţiile sunt nişte porţiuni de program  reutilizabile. Vom afla mai multe despre ele în capitolul următor.  Furnizăm un şir funcţiei implicite input() care îl tipăreşte pe ecran şi aşteaptă introducerea de  informaţie de la utilizator. Îndată ce introducem ceva (ENTER ­ rom. a intra/introduce) şi apăsăm  tasta ENTER, funcţia input() dă ca rezultat ceea ce am introdus, sub formă de şir. Convertim  acest şir întrun întreg folosind declaraţia int şi stocăm valoarea în variabila ghici. De fapt int este o clasă, dar ce trebuie să ştiţi în acest moment este că îl folosiţi pentru a converti un şir într­un  întreg (presupunând că şirul conţine un întreg valid în text).  În continuare comparăm alegerea utilizatorului cu numărul stabilit de noi. Dacă acestea sunt egale,  tipărim un mesaj de succes. Observaţi că folosim nivele de indentare pentru a­i spune Pythonului  cărui bloc aparţine fiecare declaraţie. Iată de ce este indentarea atat de importantă în Python. Sper  că v­aţi ataşat de regula indentării consistente. Este aşa?  Observaţi cum declaraţia if conţine semnul două puncte la sfârşit ­ aşa îi spunem Pythonului că  urmează un bloc de declaraţii.  Mai departe, testăm dacă numărul furnizat de utilizator este mai mic decât numărul şi, dacă este aşa,  informşăm utilizatorul că trebuie să ţintească mai sus de atât. Ce am folosit aici este clauza elif care de fapt combină două declaraţii if else-if else într­o singură declaraţie if-elifelse. Asta face programul mai uşor şi reduce numărul de indentări necesar.  Şi clauzele elif şi else trebuie să aibă la sfârşitul liniei logice semnul două puncte după care  poate urma blocul lor de declaraţii (cu indentarea adecvată, desigur).  Puteţi pune o altă declaraţie if în interiorul blocului 'if' al declaraţiei if s.a.m.d. ­ în acest caz  declaraţiile if se numesc imbricate (engl. nested).  Clauzele elif şi else sunt opţionale. O declaraţie if minimală este:  if True: print('Da, e adevarat.')

După ce Python a terminat execuţia întregii declaraţii if inclusiv clauzele elif şi else, el trece  la următoarea declaraţie din blocul care conţine declaraţia if. În acest caz este vorba de blocul  main (rom. principal), unde începe întotdeauna execuţia programului, iar instrucţiunea următoare  este declaraţia print('Gata'). După aceasta, Python vede sfârşitul programului şi încheie.  Deşi acesta este un program foarte simplu, am indicat o mulţime de lucruri care trebuie observate.  Toate acestea sunt destul de directe (şi simple pentru cei care au cunoştinţe de C/C++) şi iniţial  necesită să deveniţi constienţi de ele, dar apoi vor deveni uzuale şi vă vor părea 'naturale'.  Notă pentru programatorii în C/C++  Nu există declaraţia switch în Python. Puteţi utiliza declaraţia if..elif..else pentru a  face acelaşi lucru (şi în unele cazuri, puteţi folosi o structură de date pentru a rezolva repede).  31

Declaraţia while  Declaraţia while ne permite să executăm repetat un bloc de declaraţii atât timp cât o condiţie  rămâne adevărată. O declaraţie while este un exemplu de instrucţiune de ciclare. Poate avea şi  clauza else.  Exemplu:  #!/usr/bin/python # Fişier: while.py număr = 23 ciclu = True while ciclu: ghici = int(input('Introduceţi un întreg : ')) if ghici == număr: print('Felicitări, aţi ghicit!') ciclu = False # asta face ciclul să se întrerupă elif ghici < număr: print('Nu, este puţin mai mare.') else: print('Nu, este puţin mai mic..') else: print('Bucla s-a încheiat.') # Aici puteţi face ce prelucrări vreţi print('Gata')

Rezultat:  $ python while.py Introduceţi un întreg : 50 Nu, este puţin mai mic. Introduceţi un întreg : 22 Nu, este puţin mai mare Introduceţi un întreg : 23 Felicitări, aţi ghicit. Bucla s-a încheiat. Gata

Cum funcţionează:  În acest program jucăm tot jocul cu ghicirea numărului, dar avantajul este ca utilizatorul poate  continua încercările până când ghiceşte ­ nu trebuie să ruleze programul de fiecare dată, cum am  facut în programul precedent. Ceea ce este chiar o demostraţie de declaraţie while.  Deplasăm declaraţiile input şi if în interiorul buclei while şi iniţializăm variabila ciclu cu  True înaintea buclei. La început testăm dacă variabila ciclu este True şi apoi continuăm cu  executarea blocului while. După ce blocul a fost executat, condiţia este evaluată din nou şi, în acest  caz, condiţia este variabila ciclu. Dacă este True, executăm blocul while din nou, altfel  verificăm dacă există o clauză else ca s­o executăm.  Blocul else este executat atunci cand condiţia de ciclare devine False ­ asta poate fi chiar şi  prima dată când se testează condiţia. Dacă exista un bloc else la bucla while, ea va fi  întotdeauna executată, dacă nu se iese forţat din buclă cu o declaraţie break.  32

Valorile True şi False sunt numite booleene şi pot fi considerate a fi echivalente cu valorile 1 şi  respectiv 0.  Notă pentru programatorii în C/C++  Reţineţi că poate exista o clauză else la bucla while. 

Bucla for  Declaraţia for..in este o declaraţie de ciclare care iterează elementele unei secvenţe de obiecte.  Vom afla mai multe despre secvenţe în capitolele următoare. Ce trebuie ştiut acum este că o  secvenţă este pur şi simplu o colecţie ordonată de elemente. Exemplu:  #!/usr/bin/python # Fişier: for.py for i in range(1, 5): print(i) else: print('Bucla s-a terminat')

Rezultat:  $ python for.py 1 2 3 4 Bucla s-a terminat

Cum funcţionează:  În acest program, tipărim o secvenţă de numere. Generăm secvenţa cu ajutorul funcţiei predefinite  range.  Noi dăm funcţiei range două numere şi ea ne dă secvenţa de numere începând cu primul număr şi  până la cel de­al doilea. De exemplu, range(1,5) înseamnă secvenţa [1, 2, 3, 4]. Implicit,  range are pasul 1. Dacă îi dăm şi un al treilea număr, range acela devine pasul secvenţei. De  exemplu range(1,5,2) dă [1,3]. Reţineţi că gama de numere (engl. range) se extinde până la  al doilea număr, dar nu' îl şi include.  Aşadar bucla for iterează peste acesta gamă ­ for i in range(1,5) este echivalent cu for i in [1, 2, 3, 4] ceea ce este ca şi cum s­ar atribui fiecare obiect din secvenţă lui i, pe  rând, şi executarea blocului de declaraţii pentru fiecare valoare a lui i. În acest caz, nu facem  altceva decât să tipărim valoarea obiectului.  Amintiţi­vă că clauza else este opţională. Când este inclusă, este executată întotdeauna o dată,  după încheierea buclei for, cu excepţia cazului în care se întâlneşte o declaraţie break.  De reţinut că bucla for..in funcţionează pentru orice secvenţă. În acest caz avem doar o listă de  numere, generată cu funcţia predefinită range, dar în general, putem folosi orice fel de secvenţă de  orice fel de obiecte.  Notă pentru programatorii în C/C++/Java/C#  În Python bucla for este radical diferită de bucla for din C/C++. Programatorii C# vor  reţine că bucla for din Python este similară cu bucla foreach din C#. Programatorii Java  33

să observe că acelaşi lucru este similar cu for (int i : IntArray) în Java 1.5.  În C/C++, dacă vrei să scrii for (int i = 0; i < 5; i++), atunci în Python scrii  doar for i in range(0,5). Aşa cum vedeţi, în Python bucla for este mai simplă, mai  expresivă şi mai puţin predispusă la erori. 

Declaraţia break  Declaraţia break este folosită pentru a întrerupe (engl. break) executarea unei declaraţii de ciclare,  chiar şi dacă condiţia testată nu a devenit încă False sau secvenţa nu a fost parcursă complet.  O notă importantă este că dacă se întrerupe o bucla for sau while, nici clauza else nu va fi  executată.  Exemplu:  #!/usr/bin/python # Fişier: break.py while True: s = (input('Introduceţi ceva:')) if s == 'quit': break print('Lungimea şirului introdus este', len(s)) print('Gata')

Rezultat:  $ python break.py Introduceţi ceva: Programarea e mişto Lungimea şirului introdus este 15 Introduceţi ceva: Când treaba e facută Lungimea şirului introdus este 20 Introduceţi ceva: Dacă vrei să te şi distrezi: Lungimea şirului introdus este 27 Introduceţi ceva: foloseşte Python! Lungimea şirului introdus este 17 Introduceţi ceva: quit Gata

Cum funcţionează:  În acest program, preluăm datele de intrare în mod repetat de la utilizator şi tipărim lungimea  fiecărui şir introdus. Prevedem şi o condiţie specială pentru oprirea programului, prin căutarea  cuvântului 'quit'. Oprim programul prin întreruperea buclei şi ajungerea la sfârşitul blocului de  declaraţii.  Lungimea şirului de intrare poate fi găsită folosind funcţia predefinită len.  Reţineţi că declaraţia break poate fi folosită şi cu declaraţia for. 

Poezia lui Swaroop despre Python  Ce am folosit aici drept intrare (de la utilizator) este un mini poem scris de mine, numit Swaroop's  Poetic Python (în limba engleză):  Programming is fun

34

When the work is done if you wanna make your work also fun: use Python!

Declaraţia continue  Declaraţia continue se foloseşte pentru a spune lui Python să treacă la următoarea iteraţie fără să  execute instrucţiunile rămase din blocul declaraţiei de ciclare.  Exemplu:  #!/usr/bin/python # Fişier: continue.py while True: s = input('Introduceţi ceva: ') if s == 'quit': break if len(s) < 3: print('Prea puţin') continue print('Şirul introdus are lungime suficientă') # Faceţi alte procesări aici...

Rezultat:  $ python test.py Introduceţi ceva: a Prea puţin Introduceţi ceva: 12 Prea puţin Introduceţi ceva: abc Şirul introdus are lungime suficientă Introduceţi ceva: quit

Cum funcţionează:  În acest program acceptăm date de la utilizator, dar le procesăm doar dacă au cel puţin 3 caractere  lungime. Aşadar, folosim funcţia len pentru a obţine lungimea şi, dacă aceasta este mai mică decât  3, sărim peste ce a mai rămas din iteraţia curentă folosind declaraţia continue. În caz contrar,  restul declaraţiilor din buclă sunt executate şi putem să facem orice fel de procesare în zona unde  este acel comentariu.  Retineţi că declaraţia continue funcţionează şi cu bucla for. 

Rezumat  Am văzut cum se folosesc cele trei instrucţiuni de control al execuţiei ­ if, while şi for împreună cu asociatele lor, declaraţiile break şi continue. Acestea sunt unele dintre cele mai  utilizate părţi din Python şi de aceea este esenţial să te obişnuieşti cu ele.  În continuare vom învăţa să construim şi să folosim funcţii. 

35

Python ro:Funcţii Introducere  Funcţiile sunt porţiuni de program reutilizabile. Ele vă permit să daţi nume unui bloc de declaraţii şi  puteţi rula acel bloc de declaraţii în program de câte ori vreţi. Asta se numeşte apel al funcţiei. Noi  am folosit deja multe funcţii predefinite precum len şi range.  Conceptul de funcţie este probabil cel mai important bloc constructiv al oricărui program nonbanal  (în orice limbaj de programare), deci vom explora diverse aspecte ale funcţiilor în acest capitol.  Funcţiile sunt definite folosind cuvântul cheie def. Acesta este urmat de un nume identificator  pentru funcţie urmat de o pereche de paranteze care pot include nişte nume de variabile. În  continuare este plasat blocul de declaraţii care compun funcţia. Un exemplu va arăta cât este de  simplu:  Exemplu:  #!/usr/bin/python # Fişier: function1.py def sayHello(): print('Hello World!') # blocul funcţiei # Sfârşitul funcţiei sayHello() # apel la funcţia sayHello() sayHello() # din nou apel la funcţia sayHello()

Rezultat:  $ python function1.py Hello World! Hello World!

Cum funcţionează:  Definim o funcţie numită sayHello folosind sintaxa explicată mai sus. Aceasta funcţie nu  primeşte parametri şi deci nu sunt declarate variabile în paranteze. Parametrii pentru funcţie sunt  doar nişte modalităţi de a­i transmite funcţiei diferite valori sau/şi de a extrage valorile  corespunzătoare.  Observaţi că putem apela aceeaşi funcţie de două ori, ceea ce înseamnă că nu mai trebuie să scriem  aceeaşi porţiune de cod din nou. 

Parametrii funcţiilor  O funcţie poate accepta parametri, care sunt valori furnizate funcţiei pentru ca aceasta să poată face  ceva cu aceste valori. Aceşti parametri sunt ca variabilele numai că valorile acestor variabile sunt  definite în momentul apelului funcţiei şi deja le sunt atribuite valori la momentul executării blocului  funcţiei.  36

Parametrii sunt specificaţi într­o pereche de paranteze în definiţia funcţiei, separate prin virgule.  Când apelăm funcţia, furnizăm aceste valori într­un fel sau altul. Observaţi terminologia folosită ­  numele date în funcţie se numesc parametri în timp ce valorile pe care le furnizăm în apelul funcţiei  se numesc argumente.  Exemplu:  #!/usr/bin/python # Fişier: func_param.py def printMax(a, b): if a > b: print(a, 'este maximum') elif a == b: print(a, 'este egal cu', b) else: print(b, 'este maximum') printMax(3, 4) # argumente date prin literali x = 5 y = 7 printMax(x, y) # argumente date prin variabile

Rezultat:  $ python func_param.py 4 este maximum 7 este maximum

Cum funcţionează:  Aici definim o funcţie numită printMax care primeşte doi parametri numiţi a şi b. Găsim cel mai  mare număr dintre ele folosind o simpla declaraţie if..else şi tipărim pe ecran cel mai mare  număr.  În primul apel al funcţiei printMax, furnizăm argumentele în forma literală. În al doilea apel dăm  funcţiei valorile parametrilor prin intermediul variabilelor. printMax(x, y) face ca valoarea  variabilei x să fie atribuită parametrului a şi valoarea variabilei y să fie atribuită parametrului b.  Funcţia printMax lucrează la fel în ambele cazuri. 

Variabile locale  Când se declară variabile în interiorul definiţiei funcţiei, acestea nu au nici un fel de legătură cu alte  variabile din afara definiţiei funcţiei, nici chiar dacă ar avea acelaşi nume, de aceea se numesc  variabile locale funcţiei. Acesta este domeniul variabilei. Toate variabilele au ca domeniu blocul în  care sunt declarate, începând cu punctul în care a fost definit numele ei.  Exemplu:  #!/usr/bin/python # Fişier: func_local.py x = 50 def func(x):

37

print('x este', x) x = 2 print('Am schimbat x local în ', x) func(x) print('x este tot ', x)

Rezultat:  $ python func_local.py x este 50 Am schimbat x local în 2 x este tot 50

Cum funcţionează:  În funcţie, prima dată când folosim valoarea numelui x, Python foloseşte valoarea parametrului  declarat în funcţie.  În continuare atribuim valoarea 2 lui x. Numele x este local funcţiei noastre. Prin urmare, când  schimbăm valoarea lui x în funcţie, x definit în blocul principal rămâne neafectat.  În ultimul apel al funcţiei print, afişăm valoarea lui x din blocul principal ca să confirmăm că a  rămas neafectată. 

Folosirea declaraţiei global  Dacă vreţi să atribuiţi o valoare unui nume definit la nivelul cel mai înalt al programului (adică nu  în interiorul domeniului funcţiei sau clasei), va trebui să­i spuneţi lui Python că acel nume nu este  local ci global. Obţinem asta folosind declaraţia global. Este imposibil ca în interiorul unei  funcţii să atribui o valoare unei variabile definite în afara funcţiei fără declaraţia global.  Puteţi folosi valorile definite în afara funcţiilor (presupunând că nu există o variabilă cu acelaşi  nume definită în blocul funcţiei). Totuşi, acest fapt nu este încurajat şi trebuie evitat întrucât devine  neclar cititorului unde este definiţia acelei variabile. Folosind declaraţia global marcăm foarte  clar că variabila este definită în cel mai exterior bloc.  Exemplu:  #!/usr/bin/python # Fişier: func_global.py x = 50 def func(): global x print('x is', x) x = 2 print('Am schimbat x global în ', x) func() print('Valoarea lui x este', x)

Rezultat:  $ python func_global.py

38

x este 50 Am schimbat x global în 2 Valoarea lui x este 2

Cum funcţionează:  Declaraţia global este folosită pentru a declara că x este o variabilă globală ­ de aceea, când  atribuim o valoare lui x în interiorul funcţiei, acea schimbare se reflectă când folosim valoarea lui x în blocul principal.  Puteţi specifica mai multe variabile globale folosind declaraţia global. De exemplu, global x, y, z. 

Folosirea declaraţiei nonlocal  Am învăţat să accesăm variabile în domeniul local şi global. Mai există un domeniu specific  funcţiilor, numit "nonlocal" şi care se află între cele două. Domeniile nonlocal se observă când  definiţi funcţii în interiorul funcţiilor.  Întrucât totul în Python este cod executabil, se pot defini funcţii oriunde.  Să luăm un exemplu:  #!/usr/bin/python # Fişier: func_nonlocal.py def func_outer(): x = 2 print('x este', x) def func_inner(): nonlocal x x = 5 func_inner() print('x local a devenit ', x) func_outer()

Rezultat:  $ python func_nonlocal.py x este 2 x local a devenit 5

Cum funcţionează:  Când ne aflăm în interiorul unei funcţii func_inner, 'x' definit în prima linie a funcţiei  func_outer este undeva între global şi local. Declarăm că folosim acest x cu declaraţia  nonlocal x şi astfel obţinem acces la acea variabilă.  Încercaţi să schimbaţi nonlocal x cu global x şi să eliminaţi complet declaraţia, ca să vedeţi  ce diferenţe de comportament sunt în aceste cazuri. 

39

Valori implicite ale argumentelor  Pentru unele funcţii, poate vreţi să faceţi unii parametri opţionali şi să folosiţi valori implicite în  cazul în care utilizatorul nu furnizează o valoare pentru parametrul respectiv. Asta se face cu  ajutorul valorilor implicite ale parametrilor. Puteţi specifica valorile implicite ale argumentelor în  definiţia funcţiei, punând operatorul de atribuire (=) urmat de valoarea implicită.  Observaţi că valoarea implicită a argumentului trebuie să fie o constantă. Mai precis, trebuie să fie  imuabilă ­ acest fapt va fi explicat în detaliu în capitolele următoare. Pentru moment reţineţi doar  atât.  Exemplu:  #!/usr/bin/python # Fişier: func_default.py def say(mesaj, ori = 1): print(mesaj * ori) say('Hello') say('World', 5)

Rezultat:  $ python func_default.py Hello WorldWorldWorldWorldWorld

Cum funcţionează:  Funcţia numită say este folosită pentru a tipări pe ecran un şir de atâtea ori cât se specifică. Dacă  nu furnizăm acea valoare, atunci va fi folosită valoarea implicită, 1. Obţinem aceasta punând  valoarea implicită 1 a parametrului ori.  La prima folosire a funcţiei say, dăm numai şirul şi ea îl tipăreşte o dată. În a doua folosire dăm  funcţiei say şi şirul şi un argument 5 ceea ce spune că vrem să fie tipărit şirul de 5 ori.  Important  Numai parametrii de la sfârşitul listei de parametri pot avea valori implicite deci nu puteţi avea  un parametru cu valoare implicită înaintea altuia fără valoare implicită în lista de parametri a  funcţiei.  Motivul este că valorile sunt atribuite parametrilor prin poziţie. De exemplu, def func(a, b=5) este validă, dar def func(a=5, b) este invalidă. 

Argumente cuvânt cheie  Dacă aveţi funcţii cu mulţi parametri şi vreţi să specificaţi numai pe unii, atunci puteţi să daţi valori  parametrilor prin numele lor ­ acest mod de specificare se numeşte prin argumente cuvânt cheie ­  folosim cuvântul cheie (engl. keyword) în locul poziţiei (pe care am folosit­o până acum) pentru a  specifica argumente funcţiei.  Există două avantaje ­ unu, folosirea funcţiei este mai uşoară, întrucât nu trebuie să ne preocupăm  de ordinea parametrilor. Doi, putem da valori numai unor parametri selectaţi, cu condiţia ca toţi  ceilalţi sa aibă în definiţia funcţiei valori implicite.  40

Exemplu:  #!/usr/bin/python # Fişier: func_key.py def func(a, b=5, c=10): print('a este', a, 'şi b este', b, 'şi c este', c) func(3, 7) func(25, c=24) func(c=50, a=100)

Rezultat:  $ a a a

python func_key.py este 3 şi b este 7 şi c este 10 este 25 şi b este 5 şi c este 24 este 100 şi b este 5 şi c este 50

Cum funcţionează:  Funcţia numită func are un parametru fără valoare implicită, urmat de doi parametri cu valori  implicite.  În primul apel, func(3, 7), parametrul a primeşte valoarea 3, parametrul b primeşte valoarea  7, iar c valoarea implicită, 10.  În al doilea apel, func(25, c=24), variabila a ia valoarea 25 datorită poziţiei argumentului. Pe  urmă, parametrul c ia valoarea 24 prin nume ­ argument cuvânt cheie. Variabila b ia valoarea  implicită, 5.  În al treilea apel, func(c=50, a=100), folosim numai tehnica nouă, a cuvintelor cheie.  Observaţi, specificăm valoarea parametrului c înaintea parametrului a deşi a este definit înaintea  variabilei c în definiţia funcţiei. 

Parametri VarArgs  TODO  Să scriu despre asta într­un capitol următor, fiindcă nu am vorbit încă despre liste şi  dicţionare?  Uneori aţi putea dori să definiţi o funcţie care să ia orice număr de parametri, asta se poate face  folosind asteriscul:  #!/usr/bin/python # Fişier: total.py def total(iniţial=5, *numere, **keywords): numărător = iniţial for număr in numere: numărător += număr for cheie in keywords: numărător += keywords[cheie] return numărător print(total(10, 1, 2, 3, legume=50, fructe=100))

41

Rezultat:  $ python total.py 166

Cum funcţionează:  Când declarăm un parametru cu asterisc precum *parametri, toţi parametrii poziţionali de la  acel punct încolo sunt colectaţi întro listă numită 'parametri'.  Similar, când declarăm un parametru cu două asteriscuri, precum **parametri, toate  argumentele cuvânt cheie de la acel punct încolo sunt colectate într­un dicţionar numit 'parametri'.  Vom explora listele şi dicţionarele întrun capitol următor. 

Parametri exclusiv cuvânt cheie  Dacă vrem să specificăm anumiţi parametri cuvânt cheie pentru a fi disponibili numai în forma  cuvânt cheie şi niciodată ca parametri poziţionali, aceştia pot fi declaraţi după un parametru cu  asterisc:  #!/usr/bin/python # Fişier: keyword_only.py def total(iniţial=5, *numere, legume): numărător = iniţial for număr in numere: numărător += număr numărător += legume return numărător print(total(10, 1, 2, 3, legume=50)) print(total(10, 1, 2, 3)) # Ridică o eroare pentru că nu am furnizat o valoare implicită pentru 'legume'

Rezultat:  $ python keyword_only.py 66 Traceback (most recent call last): File "test.py", line 12, in print(total(10, 1, 2, 3)) TypeError: total() needs keyword-only argument legume

Cum funcţionează:  Declararea de parametri după un parametru cu asterisc (engl. starred parameter) produce argumente  exclusiv cuvânt cheie. Dacă acestea nu sunt definite cu valori implicite, apelurile funcţiei vor ridica  o eroare dacă nu se furnizează argumentul cuvânt cheie, aşa cum s­a văzut mai sus.  Dacă vreţi să aveţi parametri exclusiv cuvânt cheie, dar nu aveţi nevoie de nici un parametru cu  asterisc, folosiţi un asterisc izolat, ca în exemplul:  def total(iniţial=5, *, legume). 

42

Declaraţia return  Declaraţia return este folosită pentru a ne întoarce dintr­o funcţie (deci a evada din ea ­ engl.  break out). Opţional putem întoarce o valoare la fel de bine.  Exemplu:  #!/usr/bin/python # Fişier: func_return.py def maximum(x, y): if x > y: return x else: return y print(maximum(2, 3))

Rezultat:  $ python func_return.py 3

Cum funcţionează:  Funcţia maximum întoarce parametrul cel mai mare furnizat funcţiei. Ea foloseşte o declaraţie  simplă if..else pentru a găsi numărul cel mai mare şi apoi întoarce (engl. return) acea valoare.  Observaţi că declaraţia return fără o valoare este echivalentă cu return None. None este un  tip special în Python care reprezintă nimicul. De exemplu, este folosit pentru a indica faptul că o  variabilă nu are nici o valoare, deci are valoarea None.  Orice funcţie, în mod implicit, conţine o declaraţie return None la sfârşitul blocului de  declaraţii, cu excepţia cazului în care îi scrieţi o altă declaraţie return. Puteţi vedea asta rulând  print o_funcţie_oarecare() în care nu este dată o declaraţie return precum:  def o_functie_oarecare(): pass

Declaraţia pass este folosită în Python pentru a indica un bloc de declaraţii gol.  Notă  Există o funcţie predefinită numită max care implementează această funcţionalitate de a 'găsi  maximul', deci folosirea aceste funcţii este posibilă oricand. 

DocStrings  Python are o facilitate drăguţă numită documentation strings, numită de obicei pe numele scurt  docstrings. DocStrings (rom. şiruri de documentaţie, sg. docstring) sunt o unealtă importantă pentru  că vă ajută să documentaţi programele mai bine şi le face mai uşor de înţeles. Uimitor, putem chiar  să extragem şirurile de documentare ale, să zicem, unei funcţii chiar în timp ce programul rulează!  Exemplu:  #!/usr/bin/python # Fişier: func_doc.py

43

def printMax(x, y): '''Tipăreşte pe ecran cel mai mare din două numere. Cele două numere trebuie să fie întregi.''' x = int(x) # converteşte în integer, dacă este posibil y = int(y) if x > y: print(x, 'este maximum') else: print(y, 'este maximum') print(printMax.__doc__) printMax(3, 5)

Rezultat:  $ python func_doc.py Tipăreşte pe ecran cel mai mare din două numere. Cele două numere trebuie să fie întregi. 5 este maximum

Cum funcţionează:  Un şir pe prima linie logică a funcţiei devine docstring pentru acea funcţie. De retinut că DocStrings  se aplică şi la module şi clase, despre care vom învăţa în capitolele respective.  Convenţia urmată pentru un docstring este: un şir multilinie în care prima linie începe cu majusculă  şi se încheie cu punct. Apoi linia a doua este goală şi urmată de o explicaţie mai detaliată începand  cu linia a treia. Vă sfătuim cu căldură să urmaţi aceasta convenţie pentru toate docstringurile tuturor  funcţiilor nebanale pe care le scrieţi.  Putem accesa docstringul funcţiei printMax folosind atributul __doc__ (observaţi dublu  underscore) al funcţiei. Amintiţi­vă că Python tratează totul ca obiect, inclusiv funcţiile. Vom învăţa  mai mult despre obiecte în capitolul despre clase.  Daca aţi folosit help() în Python, aţi văzut deja cum se foloseşte docstring! Ceea ce face ea este  că extrage atributul __doc__ al funcţiei şi îl afişează într­o maniera convenabilă. Puteţi încerca  asta asupra funcţiei de mai sus ­ includeţi pur şi simplu declaraţia help(printMax) în program.  Nu uitaţi să tastaţi q pentru a ieşi din help.  Utilitarele pot colecta automat documentaţia din programe în această maniera. De aceea vă  recomand insistent să folosiţi docstring pentru orice funcţie nebanală pe care o scrieţi. Comanda  pydoc inclusă în distribuţia Python funcţionează similar cu help() folosind docstringurile. 

Adnotări  Funcţiile mai au o facilitate avansată numită adnotare (engl. annotations) care este o cale deşteaptă  de a ataşa informaţie pentru fiecare din parametri precum şi pentru valoarea întoarsă. Întrucât  limbajul Python în sine nu interpretează aceste adnotări în nici un fel (această funcţionalitate este  lăsată bibliotecilor third­party să interpreteze ele în ce fel vor), vom trece peste această facilitate în  discuţia noastră. Dacă sunteţi interesaţi despre adnotări, puteţi citi PEP No. 3107. 

44

Rezumat  Am discutat multe aspecte ale funcţiilor, dar reţineţi că nu am acoperit toate aspectele posibile.  Totuşi, am acoperit deja majoritatea aspectelor pe care le vom folosi în mod uzual.  Vom afla în continuare cum să folosim, dar şi să cream module Python. 

45

Python ro:Module 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('\n\nPYTHONPATH 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ă.  46

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. 

47

Î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

48

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. 

49

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  50

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:  - / - 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'. 

51

Python ro:Structuri de date Introducere  Structurile de date sunt în esenţă exact asta ­ structuri care pot memora date grupate. Cu alte  cuvinte, sunt folosite pentru a stoca colecţii de date înrudite.  Există patru structuri predefinite în Python ­ liste, tupluri, dicţionare şi seturi. Vom învăţa să le  folosim pe fiecare şi cum ne pot uşura ele viaţa. 

Liste  O listă (engl. list) este o structură de date care păstrează o colecţie ordonată de elemente deci se  poate memora o secvenţă de elemente întro listă. Asta este uşor de imaginat dacă ne gândim la o  listă de cumpărături, numai că pe listă fiecare item ocupă un rând separat, iar în Python punem  virgule intre ele.  Elementele listei trebuie incluse în paranteze drepte astfel încât Python să înţeleagă că este o  specificare de listă. Odată ce am creat lista, putem adăuga, şterge sau căuta elemente în ea. De aceea  se poate spune că listele sunt muabile, acest tip de date poate fi modificat. 

Introducere rapidă în obiecte şi clase  Deşi în general am amânat discutarea obiectelor şi claselor pâna acum, este necesară o scurtă  introducere, pentru a se putea înţelege listele mai bine. Detaliile le vom afla în capitolul dedicat  acestora.  O listă este un exemplu de utilizare a obiectelor şi claselor. Când folosim o variabilă i şi îi atribuim  o valoare, să zicem întregul 5, putem gândi că am creat un obiect (de fapt instanţă) i din clasa (de  fapt tipul) int. De fapt se poate citi help(int) pentru o înţelegere mai aprofundatată.  O clasă poate avea şi metode adică funcţii definite pentru a fi folosite exclusiv în raport cu acea  clasă. Puteţi folosi aceste funcţionalităţi numai asupra unui obiect din acea clasă. De exemplu,  Python oferă o metodă append pentru clasa list care ne permite să adăugăm un element la  sfârşitul listei. Prin urmare lista_mea.append('un item') va adăuga acel şir la  lista_mea. De reţinut folosirea notaţiei cu punct pentru accesarea metodelor obiectelor.  O clasă poate avea şi câmpuri (engl. fields) care nu sunt altceva decât variabile definite în raport  exclusiv cu acea clasă. Se pot folosi acele variabile/nume numai în raport un obiect din acea clasă.  Câmpurile sunt accesate tot prin notaţia cu punct, de exemplu lista.câmp.  Exemplu:  #!/usr/bin/python # Fişier: using_list.py # Lista mea de cumpărături shoplist = ['mere', 'mango', 'morcovi', 'banane']

52

print('Am de cumpărat', len(shoplist), 'itemuri.') print('Acestea sunt:', end=' ') for item in shoplist: print(item, end=' ') print('\nTrebuie să cumpăr şi orez.') shoplist.append('orez') print('Lista mea de cumpărături este acum', shoplist) print('Acum vom sorta lista') shoplist.sort() print('Lista sortată este', shoplist) print('Primul lucru de cumpărat este', shoplist[0]) item_cumpărat = shoplist[0] del shoplist[0] print('Am cumpărat', item_cumpărat) print('Lista mea este acum', shoplist)

Rezultat:  $ python using_list.py Am de cumpărat 4 itemuri. Acestea sunt: mere mango morcovi banane Trebuie să cumpăr şi orez. Lista mea de cumpărături este acum ['mere', 'mango', 'morcovi', 'banane', 'orez'] Acum vom sorta lista Lista sortată este ['banane', 'mango', 'mere', 'morcovi', 'orez'] Primul lucru de cumpărat este banane Am cumpărat banane Lista mea este acum ['mango', 'mere', 'morcovi', 'orez']

Cum funcţionează:  Variabila shoplist este o listă de cumpărături pentru cineva care merge la piaţă. În shoplist,  memorăm şiruri care reprezintă numele lucrurilor pe care le avem de cumpărat, dar putem adăuga  orice fel de obiect inclusiv numere sau alte liste.  Am folosit bucla for..in pentru a itera prin itemurile listei. Până acum cred că aţi realizat ca o  listă este şi secvenţă în acelaşi timp. Specificul secvenţelor va fi discutat întrun subcapitol următor.  Observaţi utilizarea argumentului cuvânt cheie end al funcţiei print pentru a­i transmite că vrem  să încheiem linia cu un spaţiu (' ') în loc de încheierea uzuală.  În continuare adăugăm un item la listă folosind metoda append a obiectului listă, aşa cum am  discutat anterior. Verificăm că adăugarea s­a realizat tipărind conţinutul listei prin transmiterea ei  funcţiei print care o tipăreşte frumos pe ecran.  Mai departe sortăm lista folosind metoda sort a listei. Este important să întelegem că această  metodă afecteaza însăşi lista şi nu întoarce o listă modificată ­ spre deosebire de comportamentul  sirurilor. Asta vrem să zicem prin muabile pe când şirurile sunt imuabile.  După ce cumpărăm un item de la piaţă, vrem să­l eliminăm din listă. Pentru aceasta utilizăm  declaraţia del. Trebuie menţionat aici itemul pe care vrem să­l eliminăm şi declaraţia del îl  53

elimină pentru noi. Specificăm că vrem să eliminăm primul item, de aici declaraţia del shoplist[0] (amintiţi­vă că Python începe numărătoarea de la 0).  Dacă vreţi să ştiţi toate metodele definite de obiectul listă, citiţi help(list). 

Tupluri  Tuplurile sunt folosite pentru păstra colecţii de obiecte. Sunt similare cu listele, dar fără  funcţionalitatea extinsă pe care o dau clasele. O facilitate majoră a tuplurilor este că ele sunt  imuabile ca şi şirurile adică nu pot fi modificate.  Tuplurile sunt definite prin specificarea itemurilor separate prin virgule întro pereche opţională de  paranteze.  Tuplurile sunt folosite de obicei în cazurile în care o declaraţie sau o funcţie definită de utilizator  poate presupune fără risc de greşeală că o colecţie de valori nu se va schimba..  Exemplu:  #!/usr/bin/python # Fişier: using_tuple.py zoo = ('piton', 'elefant', 'pinguin') # reţineţi că parantezele sunt opţionale print('Numărul animalelor în zoo este', len(zoo)) zoo_nou = ('maimuţă', 'cămilă', zoo) print('Numărul de cuşti în noul zoo este', len(zoo_nou)) print('Animalele din noul zoo sunt ', zoo_nou) print('Animalele aduse din vechiul zoo sunt ', zoo_nou[2]) print('Ultimul animal adus din vechiul zoo este', zoo_nou[2][2]) print('Numărul de animale în noul zoo este', len(zoo_nou)-1+len(zoo_nou[2]))

Rezultat:  $ python using_tuple.py Numărul animalelor în zoo este 3 Numărul de cuşti în noul zoo este 3 Animalele din noul zoo sunt ('maimuţă', 'cămilă', ('piton', 'elefant', 'pinguin')) Animalele aduse din vechiul zoo sunt ('piton', 'elefant', 'pinguin') Ultimul animal adus din vechiul zoo este pinguin Numărul de animale în noul zoo este 5

Cum funcţionează:  Variabila zoo este un tuplu de itemuri. Vedem că funcţia len lucrează şi pentru tupluri. De  asemenea asta arată că tuplurile sunt şi secvenţe.  Acum mutăm aceste animale într­un nou zoo, deoarece vechiul zoo s­a închis, să zicem. Ca urmare  tuplul zoo_nou conţine nişte animale care erau acolo împreună cu animalele aduse din vechiul  zoo. În realitate, acum, reţineţi că un tuplu în interiorul altui tuplu nu îşi pierde identitatea.  Putem accesa itemurile din tuplu specificând poziţia întro pereche de paranteze pătrate, ca pentru  liste. Acesta se numeşte operator de indexare. Accesăm al treilea item din zoo_nou specificând  zoo_nou[2] şi accesăm al treilea item al tuplului zoo din tuplul zoo_nou specificând  zoo_nou[2][2]. E destul de simplu după ce aţi înteles regula. 

54

Paranteze  Deşi parantezele sunt opţionale, eu prefer să le pun mereu, pentru a face evident că e vorba de  un tuplu, în special pentru a evita ambiguitatea. De exemplu print(1,2,3) şi  print( (1,2,3) ) înseamnă două lucruri foarte diferite ­ prima tipăreşte trei numere, iar  a doua tipăreşte un tuplu (care conţine trei numere).  Tupluri cu 1 sau 0 elemente  Un tuplu vid este construit folosind o pereche de paranteze goale myempty = (). Totuşi, un  tuplu cu un singur element nu e aşa de simplu. Trebuie să îl specificaţi folosind virgula după  primul (şi ultimul) element, ca Python să poată diferenţia între tuplu şi un alt obiect cuprins în  paranteze întro expresie deci va trebui să specificaţi singleton = (2 , ) dacă vreţi să  se înţeleagă 'tuplul care conţine doar elementul 2'.  Notă pentru programatorii în Perl  O listă întro listă nu­şi pierde identitatea adică nu este asimilată ca în Perl. Asta se aplică şi  pentru un tuplu întrun tuplu, o listă întrun tuplu, un tuplu întro listă etc. În ce priveşte limbajul  Python, ele sunt nişte obiecte stocate în alte obiecte. 

Dicţionare  Un dicţionar este ca o carte de adrese în care poţi găsi adresa sau datele de contact ale persoanei  doar ştiindu­i numele, adică asociem chei (nume) cu valori (detalii). De observat că o cheie trebuie  să fie unică, pentru a nu exista confuzii, exact ca atunci când nu poţi deosebi două persoane dacă au  acelaşi nume.  Pe post de chei puteţi folosi numai obiecte imuabile (precum şirurile), dar pe post de valori putem  folosi orice fel de valori. În esenţă înseamnă că ar trebui să folosim pe post de chei numai obiecte  simple.  Perechile cheie ­ valoare sunt specificate întrun dicţionar folosind notaţia d = {cheie1 : valoare1, cheie2 : valoare2 }. Observaţi că perechile cheie ­ valoare sunt separate  prin virgulă, iar cheia este separată de valoare prin semnul două puncte. Dicţionarul este delimitat  de o pereche de acolade.  Reţineţi că întrun dicţionar perechile cheie ­ valoare nu sunt ordonate în nici un fel. Dacă vreţi o  anumită ordine, va trebui să îl sortaţi singuri înainte de folosire.  Dicţionarele pe care le veţi folosi sunt instanţe/obiecte ale clasei dict.  Exemplu:  #!/usr/bin/python # Fişier: using_dict.py # 'ab' este o prescurtare de la 'a'ddress'b'ook ab = {

'Swaroop' 'Larry' 'Matsumoto' 'Spammer'

: : : :

'[email protected]', '[email protected]', '[email protected]', '[email protected]'

} print("Adresa lui Swaroop este", ab['Swaroop'])

55

# Ştergerea unei perechi cheie - valoare del ab['Spammer'] print('\nExistă {0} contacte în address-book\n'.format(len(ab))) for nume, adresa in ab.items(): print('Contactaţi pe {0} la adresa {1}'.format(nume, adresa)) # Adăugarea unei perechi cheie - valoare ab['Guido'] = '[email protected]' if 'Guido' in ab: # OR ab.has_key('Guido') print("\nAdresa lui Guido este", ab['Guido'])

Rezultat:  $ python using_dict.py Adresa lui Swaroop este [email protected] Există 3 contacte în address-book Contactaţi pe Swaroop la adresa [email protected] Contactaţi pe Matsumoto la adresa [email protected] Contactaţi pe Larry la adresa [email protected] Adresa lui Guido este [email protected]

Cum funcţionează:  Creăm dicţionarul ab folosind notaţia deja discutată. Accesăm perechile cheie ­ valoare specificând  cheia şi folosind operatorul de indexare, aşa cum am discutat la liste şi tupluri. Observaţi simplitatea  sintaxei.  Putem şterge perechi cheie valoare folosind vechiul nostru prieten ­ declaraţia del. Pur şi simplu  specificăm dicţionarul şi operatorul de indexare pentru cheia care trebuie ştearsă şi le dăm  declaraţiei del. Nu este necesar să se cunoască şi valoarea asociata cheii pentru a realiza această  operaţie.  În continuare accesăm fiecare pereche cheie ­ valoare din dicţionar folosind metoda items a  dicţionarului care întoarce o listă de tupluri în care fiecare tuplu conţine o pereche de itemuri ­ cheia  urmată de valoare. Extragem această pereche şi o atribuim variabilelor nume şi adresă corespunzător pentru fiecare pereche folosind o buclă for..in în care tipărim aceste informaţii.  Putem adăuga perechi noi cheie ­ valoare prin simpla utilizare a operatorului de indexare pentru a  accesa cheia şi a atribui acea valoare, aşa cum am făcut pentru Guido în cazul de mai sus.  Putem testa dacă există în dicţionar o anumită pereche cheie ­ valoare folosind operatorul in sau  chiar metoda has_key a clasei dict. Puteţi consulta documentaţia pentru o listă completă a  metodelor clasei dict folosind comanda help(dict).  Argumente cuvânt cheie şi dicţionare  Într­o altă ordine de idei, dacă aţi folosit argumente cuvânt cheie în funcţii, înseamnă că aţi  folosit deja dicţionare! Ia gândiţi­vă: perechea cheie ­ valoare este specificată în lista de  parametri a definiţiei funcţiei şi când accesaţi variabilele, numele lor sunt chei de acces ale  unui dicţionar numit tabel de simboluri în terminologia proiectării de compilatoare). 

56

Secvenţe  Listele, tuplurile şi şirurile sunt exemple de secvenţe, dar ce sunt secvenţele şi ce le face atât de  speciale?  Facilitatea cea mai importantă este că au teste de apartenenţă (adică expresiile in şi not in) şi  operaţii de indexare. Operaţia de indexare ne permite să extragem direct un item din secvenţă.  Au fost menţionate trei tipuri de secvenţe ­ liste, tupluri şi şiruri şi operaţia de feliere, care ne  permite să extragem o parte (engl. slice) din secvenţă.  Exemplu:  #!/usr/bin/python # Fişier: seq.py shoplist = ['mere', 'mango', 'morcovi', 'banane'] nume = 'swaroop' # Operaţia de indexare sau 'subscriere' print('Itemul 0 este', shoplist[0]) print('Itemul 1 este', shoplist[1]) print('Itemul 2 este', shoplist[2]) print('Itemul 3 este', shoplist[3]) print('Itemul -1 este', shoplist[-1]) print('Itemul -2 este', shoplist[-2]) print('Caracterul 0 este', nume[0]) # Felierea unei liste print('Itemurile de la print('Itemurile de la print('Itemurile de la print('Itemurile de la

1 la 3 sunt', shoplist[1:3]) 2 la sfârsit sunt', shoplist[2:]) 1 la -1 sunt', shoplist[1:-1]) început la sfârşit sunt', shoplist[:])

# Felierea unui şir print('Caracterele de print('Caracterele de print('Caracterele de print('Caracterele de

1 la 3 sunt', nume[1:3]) 2 la end sunt', nume[2:]) 1 la -1 sunt', nume[1:-1]) început la sfârşit sunt ', nume[:])

la la la la

Rezultat:  $ python seq.py Itemul 0 este mere Itemul 1 este mango Itemul 2 este morcovi Itemul 3 este banane Itemul -1 este banane Itemul -2 este morcovi Caracterul 0 este s Itemurile de la 1 la 3 sunt ['mango', 'morcovi'] Itemurile de la 2 la sfârşit sunt ['morcovi', 'banane'] Itemurile de la 1 la -1 sunt ['mango', 'morcovi'] Itemurile de la început la sfârşit sunt ['mere', 'mango', 'morcovi', 'banane'] Caracterele de la 1 la 3 sunt wa Caracterele de la 2 la sfârşit sunt aroop Caracterele de la 1 la -1 sunt waroo Caracterele de la început la sfârşit sunt swaroop

57

Cum funcţionează:  La început, vedem cum se folosesc indecşii pentru a obţine un element anume din secvenţă. Asta se  mai numeşte operaţia de subscriere. De câte ori specificaţi un număr întro pereche de paranteze  drepte alăturate unei secvenţe, Python vă va extrage itemul corespunzator poziţiei în secvenţă.  Reţineţi că Python începe numărătoarea de la 0. Astfel shoplist[0] extrage primul item şi  shoplist[3] îl extrage pe al patrulea din secvenţa shoplist.  Indexul poate fi şi un număr negativ, caz în care poziţia este calculată de la sfârşitul secvenţei. Din  acest motiv shoplist[-1] indică ultimul item din secvenţă, iar shoplist[-2] penultimul  item.  Operaţia de feliere este folosită specificând numele secvenţei urmat de o pereche opţională de  numere separate prin semnul doua puncte (engl. colon) incluse în paranteze drepte. Observaţi că  este foarte asemănător cu operaţia de indexare folosită până acum. De reţinut că numerele sunt  opţionale, semnul două puncte NU este opţional.  Primul număr (înainte de două puncte) în operaţia de feliere indică punctul unde începe felia, iar al  doilea număr indică unde se temină. Dacă nu este specificat primul număr, Python va începe cu  începutul secvenţei. Dacă este omis al doilea număr, Python se va opri la sfârşitul secvenţei.  Observaţi că felia întoarsă (uneori se spune 'returnată') începe cu poziţia dată de primul număr, dar  se încheie imediat înainte de poziţia dată de al doilea număr adică începutul este inclus, sfârşitul nu  este inclus în felie.  Astfel, shoplist[1:3] întoarce o felie din secvenţa care începe cu poziţia 1, include poziţia 2,  dar nu include poziţia 3 deci este întoarsă o felie de două itemuri. Similar, shoplist[:] întoarce  o copie a secvenţei.  Mai puteti face feliere şi cu indecşi negativi. Numerele negative sunt folosite pentru a indica poziţii  de la sfârşitul secvenţei. De exemplu, shoplist[:-1] va întoarce o felie din secvenţă care  exclude ultimul item din secvenţă, dar include tot restul secvenţei.  De asemenea, putem da al treilea argument pentru feliere, care devine pasul de feliere (implicit  pasul este 1):  >>> shoplist = ['mere', 'mango', 'morcovi', 'banane'] >>> shoplist[::1] ['mere', 'mango', 'morcovi', 'banane'] >>> shoplist[::2] ['mere', 'morcovi'] >>> shoplist[::3] ['mere', 'banane'] >>> shoplist[::-1] ['banane', 'morcovi', 'mango', 'mere']

Iată ce se întâmplă când pasul este 2, obţinem itemurile cu poziţiile 0, 2, ... Dacă pasul este 3,  obtinem itemurile din poziţiile 0, 3, etc.  Încercaţi variate combinaţii de specificaţii de feliere în modul interactiv, pentru a vedea imediat  rezultatele. Marele avantaj al secvenţelor este că puteţi accesa tuplurile, listele şi şirurile în acelaşi  fel! 

Seturi  Seturile sunt colecţii neordonate de obiecte simple. Acestea sunt folosite atunci cand existenţa unui  58

obiect în colecţie este mai importantă decât poziţia lui sau numărul de apariţii.  Folosind seturi, puteţi testa apartenenţa, dacă un set este subset al altui set, puteţi afla intersecţia a  două seturi şi aşa mai departe.  >>> bri = set(['brazilia', 'rusia', 'india']) >>> 'india' in bri True >>> 'usa' in bri False >>> bric = bri.copy() >>> bric.add('china') >>> bric.issuperset(bri) True >>> bri.remove('rusia') >>> bri & bric # OR bri.intersection(bric) {'brazilia', 'india'}

Cum funcţionează:  Exemplul este autoexplicativ deoarece implică teoria de bază învăţată la şcoala despre mulţimi  (seturi). 

Referinţe  Când creaţi un obiect şi îi atribuiţi o valoare, variabila doar indică obiectul creat, nu reprezintă  obiectul însuşi! Asta înseamnă că numele variabilei este un indicator către acea parte a memoriei  calculatorului în care este stocat obiectul. Acest fapt se numeşte legare (engl. binding) a numelui la  obiect.  În general, nu trebuie să vă îngrijoraţi de asta, dar există un efect subtil darorat referinţei de care  trebuie să fiţi conştienţi:  Exemplu:  #!/usr/bin/python # Fişier: reference.py print('Atribuire simplă') lista_iniţială = ['mere', 'mango', 'morcovi', 'banane'] lista_mea = lista_iniţială # lista_mea este doar un alt nume al aceluiaşi obiect! del lista_iniţială[0] # Am cumpărat primul item, deci să-l ştergem din listă print('lista initială este', lista_iniţială) print('lista mea este', lista_mea) # Observaţi că ambele liste apar fără 'mere', confirmând # astfel că ele indică acelaşi obiect print('Copiere făcând o felie intergală') lista_mea = lista_iniţială[:] # Face o copie prin feliere integrală del lista_mea[0] # eliminăm primul item print('lista_iniţială este', lista_iniţială) print('lista_mea este', lista_mea) # Observaţi că acum cele două liste sunt diferite?

59

Rezultat:  $ python reference.py Atribuire simplă lista_iniţială este ['mango', 'morcovi', 'banane'] lista_mea este ['mango', 'morcovi', 'banane'] Copiere făcând o felie intergală lista_iniţială este ['mango', 'morcovi', 'banane'] lista_mea este ['morcovi', 'banane']

Cum funcţionează:  Partea principală a explicaţiei se regăseşte în comentarii.  Reţineţi că dacă vreţi să faceţi o copie a unei liste sau a unor obiecte complexe (nu simple obiecte,  cum ar fi întregii), atunci trebuie să folosiţi felierea. Dacă folosiţi atribuirea obţineţi încă un nume  pentru acelaşi obiect şi asta poate aduce probleme dacă nu sunteţi atenţi.  Notă pentru programatorii în Perl  Reţineţi că o declaraţie de atribuire pentru liste nu creeaza o copie. Va trebui să folosiţi  felierea pentru a face o copie a secvenţei. 

Alte detalii despre şiruri  Am discutat deja în detaliu despre şiruri. Ce ar mai putea fi de ştiut? Ei bine, ştiaţi că şirurile sunt  obiecte şi au metode care fac orice de la verificarea unor părţi ale şirului până la eliminarea  spaţiilor?  Sirurile pe care le folosiţi în programe sunt obiecte din clasa str. Câteva metode utile sunt arătate  în exemplul următor. Pentru o listă completă a metodelor, citiţi help(str).  Exemplu:  #!/usr/bin/python # Fişier: str_methods.py nume = 'Swaroop' # Acesta este obiectul şir if name.startswith('Swa'): print('Da, şirul începe cu "Swa"') if 'a' in nume: print('Da, şirul conţine subşirul "a"') if name.find('war') != -1: print('Da, şirul conţine subşirul "war"') delimitator = '_*_' Lista_mea= ['Brazilia', 'Rusia', 'India', 'China'] print(delimitator.join(lista_mea))

Rezultat:  $ python str_methods.py Da, şirul începe cu "Swa" Da, şirul conţine subşirul "a" Da, şirul conţine subşirul "war"

60

Brazilia_*_Rusia_*_India_*_China

Cum funcţionează:  Aici vedem o mulţime de metode în acţiune. Metoda startswith este folosită pentru a testa dacă  şirul începe sau nu cu un şir dat. Operatorul in se foloseşte pentru a verifica includerea unui şir în  şirul dat.  Metoda find este folosită pentru a găsi poziţia unui şir dat în şirul iniţial, care întoarce ­1 dacă nu  a găsit nimic. Clasa str are şi o metodă simpatică join pentru a alătura itemurile dintro secvenţă,  cu un şir pe post de delimitator între itemuri şi intoarce un şir lung generat din toate acestea. 

Rezumat  Am explorat diversele structuri de date predefinite în Python în detaliu. Aceste structuri de date vor  deveni esenţiale pentru scrierea de programe de dimensiuni rezonabile.  Acum că avem o mulţime de elemente Python asimilate, vom vedea cum se proiectează şi se scriu  programe Python în lumea de zi cu zi. 

61

Python ro:Rezolvarea problemelor Am explorat diverse părţi din limbajul Python şi acum vom vedea cum conlucrează acestea prin  proiectarea şi scrierea unui program care face ceva util. Ideea este de a învăţa cum să scriem un  program Python propriu. 

Problema  Problema este "Vreau un program care să facă un backup al tuturor fişierelor mele importante".  Deşi aceasta este o problema simplă, nu avem destule informaţii pentru a începe găsirea unei soluţii.  Se impune o analiză suplimentară. De exemplu, cum specificăm care fişiere trebuie salvate? Cum  vor fi ele stocate? Unde vor fi stocate?  După o analiză corectă a problemei, proiectăm programul. Facem o listă cu lucruri care descriu cum  trebuie să funcţioneze programul nostru. În acest caz, am creat lista următoare care descrie cum  vreau EU să meargă. Dacă faceţi voi proiectarea s­ar putea să rezulte o altfel de analiză, întrucât  fiecare face lucrurile în felul lui, deci e perfect OK.  1. 2. 3. 4. 5.

Fişierele şi directoarele care trebuie salvate sunt specificate într­o listă.  Backup­ul trebuie stocat în directorul principal de backup  Fişierele sunt stocate întro arhivă zip.  Numele arhivei zip este data şi ora.  Folosind comanda standard zip disponibilă implicit în toate distribuţiile Linux/Unix.  Utilizatorii de Windows pot instala din pagina proiectului GnuWin32 şi adauga  C:\Program Files\GnuWin32\bin la variabila de mediu PATH, similar modului în  care am făcut pentru recunoaşterea însăşi a comenzii python. Reţineţi că puteţi folosi orice  comandă de arhivare atât timp cât această are o interfaţă linie de comandă, ca să îi putem  transmite argumente din programul nostru. 

Soluţia  Întrucât designul programului nostru este relativ stabil, putem scrie codul care implementează  soluţia noastră.  #!/usr/bin/python # Fişier: backup_ver1.py import os import time # 1. Fişierele şi directoarele de salvat sunt specificate într-o listă. source = ['"C:\\My Documents"', 'C:\\Code'] # Observaţi că a fost nevoie de ghilimele duble în interiorul şirului pentru a proteja spaţiile din interiorul numelor. # 2. Salvarea (engl. backup) trebuie stocată în directorul principal de backup target_dir = 'E:\\Backup' # Nu uitaţi să schimbaţi asta cu directorul folosit de voi

62

# 3. Fişierele sunt salvate întro arhivă zip. # 4. Numele arhivei zip este data şi ora curentă target = target_dir + os.sep + time.strftime('%Y%m%d%H%M%S') + '.zip' # 5. Folosim comanda zip pentru a include fişierele şi directoarele de salvat în arhivă zip_command = "zip -qr {0} {1}".format(target, ' '.join(source)) # Rulăm comanda de backup if os.system(zip_command) == 0: print('Salvare reuşită în ', target) else: print('Backup EŞUAT')

Rezultat:  $ python backup_ver1.py Salvare reuşită în E:\Backup\20090208153040.zip

Acum suntem în faza de testare în care verificăm dacă programul nostru lucrează corect. Dacă nu  se comportă cum trebuie, va fi nevoie de debugging adică eliminarea erorilor din program.  Dacă programul nu va merge, puneţi o declaraţie print(zip_command) imediat înainte de  apelul os.system şi rulaţi programul. Acum copiaţi comanda zip_command la promptul shell­ ului şi verificaţi dacă merge pe cont propriu. Dacă aceasta eşuează, citiţi manualul comenzii zip ca  să aflaţi ce ar putea fi greşit. Dacă reuşeşte, verificaţi programul Python ca să vedeţi dacă este exact  ca mai sus.  Cum funcţionează:  Veţi observa cum am transformat designul în cod întro manieră pas cu pas.  Utilizăm modulele os şi time importându­le de la început. Apoi specificăm directoarele care  trebuie salvate în lista source. Directorul destinaţie este locul unde stocăm toate salvările şi acesta  este specificat în variabila target_dir. Numele arhivei zip pe care o vom crea este "data  curentă+ora curentă" pe care le găsim folosind funcţia time.strftime(). Arhiva va avea  extensia .zip şi va fi stocată în directorul target_dir.  Observaţi folosirea variabilei os.sep ­ cea care ne dă separatorul de director al sistemului vostru  de operare; acesta va fi '/' în Linux şi Unix, '\\' în Windows şi ':' în Mac OS. Folosirea  declaraţiei os.sep în locul acestor caractere va face programul mai portabil între aceste sisteme.  Funcţia time.strftime() primeşte o specificaţie ca aceea folosită în program. Specificaţia %Y va fi înlocuită cu anul, fără secol. Specificaţia %m va fi înlocuită cu luna, ca numar zecimal între 01 şi 12 ş.a.m.d. Lista completă a specificaţiilor poate fi găsită în Manualul de referinţă Python.  Creăm numele directorului destinaţie folosind operatorul de adunare care concatenează şirurile  adică alătură şirurile şi produce unul mai lung. Atunci noi creăm un şir zip_command care  conţine comanda pe care o vom executa. Puteţi verifica dacă a rezultat o comandă corectă prin  executarea ei de sine stătătoare într­un shell (terminal Linux sau DOS prompt).  Comanda zip pe care o folosim are câteva opţiuni şi parametri transmişi. Opţiunea -q este folosită  pentru a indica modul de lucru tăcut (engl. quiet). Opţiunea -r specifică modul recursiv de  parcurgere a directoarelor, adică trebuie să includă şi toate subdirectoarele şi subdirectoarele  acestora etc. Cele două opţiuni se combină şi se specifică pe scurt -qr. Opţiunile sunt urmate de  63

numele arhivei care va fi creată urmată de lista fişierelor şi directoarelor de salvat. Convertim lista  source într­un şir folosind metoda join a şirurilor, pe care am învăţat deja s­o folosim.  În fine, rulăm comanda folosind funcţia os.system care execută comanda ca şi cum ar fi fost  lansată din sistem adică în shell ­ ea întoarce 0 dacă comanda a fost executată cu succes, altfel  întoarce un cod de eroare.  În funcţie de rezultatul comenzii, tipărim pe ecran mesajul adecvat, cum că salvarea a reuşit sau nu.  Asta e, am creat un script care să faca un backup al fişierelor importante din sistem!  Notă pentru utilizatorii de Windows  În locul secvenţelor de evadare cu dublu backslash, puteţi folosi şi şiruri brute. De exemplu,  folosiţi 'C:\\Documents' sau r'C:\Documents'. În orice caz, nu folosiţi  'C:\Documents' întrucât veţi ajunge să folosiţi o secvenţă de evadare necunoscută, \D.  Acum că avem un script funcţional de salvare, îl putem rula de câte ori vrem să obţinem o salvare a  fişierelor. Utilizatorii de Linux/Unix sunt sfătuiţi să folosească metode executabile aşa cum am  discutat în capitolele precedente, astfel ca ele să poată rula de oriunde, oricând. Asta se numeşte  faza de operare sau de distribuire a software­ului.  Programul de mai sus funcţionează corect, dar (de obicei) primul program nu funcţionează cum ne­ am aştepta. De exemplu ar putea fi probleme dacă nu am proiectat corect programul sau dacă avem  o eroare de dactilografiere în scrierea codului (engl. typo), etc. În modul adecvat, vă veţi întoarce la  faza de design sau debuggigg pentru a rezolva problema. 

A doua versiune  Prima versiune a scriptului nostru funcţionează. Totuşi, putem rafina programul pentru a lucra mai  bine în utilizarea sa de zi cu zi. Asta se numeşte întreţinere sau mentenanţă a software­ului (engl.  maintenance).  Unul din rafinamentele pe care le­am considerat eu utile a fost un mecanism mai bun de denumire a  salvărilor, folosind ora ca nume al fişierului, iar data ca nume de subdirector al directorului de  backup care să conţină salvările din aceeaşi data. Primul avantaj este că salvările vor fi stocate într­o  manieră ierarhică şi vor fi mai uşor de gestionat. Al doilea avantaj este că lungimea numelor de  fişier va fi mai mult mai mică. Al treilea avantaj este că se va putea verifica mai uşor dacă au fost  făcute salvări zilnic (în ziua în care nu s­a facut, directorul având ca nume acea dată lipseşte,  întrucât nu a fost creat).  #!/usr/bin/python # Fişier: backup_ver2.py import os import time # 1. Fişierele şi directoarele de salvat sunt specificate întro listă. source = ['"C:\\My Documents"', 'C:\\Code'] # Observaţi că au fost necesare ghilimele duble pentru a proteja spaţiile din interiorul numelor. # 2. Salvarea trebuie stocată în directorul principal de backup target_dir = 'E:\\Backup' # Nu uitaţi să schimbaţi asta cu directorul pe care îl folosiţi voi

64

# 3. Fişierele sunt salvate în fişiere zip. # 4. Data curentă este numele subdirectorului din folderul principal azi = target_dir + os.sep + time.strftime('%Y%m%d') # Ora curentă este numele arhivei zip acum = time.strftime('%H%M%S') # Creăm subdirectorul, dacă nu exista înainte if not os.path.exists(azi): os.mkdir(azi) # creăm directorul print('Am creat cu succes directorul ', azi) # Numele fişierului arhiva zip target = azi + os.sep + acum + '.zip' # 5. Folosim comanda zip pentru a colecta fişierele în arhivă. zip_command = "zip -qr {0} {1}".format(target, ' '.join(source)) # Rulăm programul de salvare if os.system(zip_command) == 0: print('Salvare reuşită în ', target) else: print('Salvare EŞUATĂ')

Rezultat:  $ python backup_ver2.py Am creat cu succes directorul E:\Backup\20090209 Salvare reuşită în E:\Backup\20090209\111423.zip $ python backup_ver2.py Salvare reuşită în E:\Backup\20090209\111837.zip

Cum funcţionează:  Majoritatea codului ramâne neschimbat. Schimbările constau un testarea existenţei directorului  având ca nume data curentă în interiorului directorului principal de backup folosind funcţia  os.path.exists. Dacă acesta nu există, îl creăm noi folosind funcţia os.mkdir. 

Versiunea a treia  A doua versiune merge bine când facem multe salvări, dar e greu de văzut ce este salvat în fiecare  arhiva! De exemplu, poate am făcut o schimbare mare unui program sau unei prezentări şi aş vrea să  asociez aceste schimbări cu numele programului sau prezentării şi arhiva zip. Aceasta se poate  realiza uşor prin ataşarea unui comentariu furnizat de utilizator la numele arhivei zip.  Notă  Următorul program nu funcţionează, deci nu va alarmaţi, urmaţi­l totuşi, pentru că e o lecţie  în el.  #!/usr/bin/python # Fişier: backup_ver3.py import os import time

65

# 1. Fişierele şi directoarele de salvat sunt specificate întro listă. source = ['"C:\\My Documents"', 'C:\\Code'] # Observaţi că a fost nevoie de ghilimele duble pentru a proteja spaţiile din interiorul numelor. # 2. Salvarea trebuie stocată în directorul principal target_dir = 'E:\\Backup' # Nu uitaţi să schimbaţi asta cu ce folosiţi voi # 3. Fişierele sunt salvate întro arhivă zip. # 4. Data curentă este numele subdirectorului azi = target_dir + os.sep + time.strftime('%Y%m%d') # Ora curentă este numele arhivei zip acum = time.strftime('%H%M%S') # Luăm un comentariu de la utilizator pentru a crea numele comentariu = input('Introduceţi un comentariu --> ') if len(comentariu) == 0: # Verificaţi dacă a fost introdus target = azi + os.sep + acum+ '_' + comentariu.replace(' ', '_') + '.zip' # Creăm subdirectorul dacă nu există deja if not os.path.exists(azi): os.mkdir(azi) # Creăm directorul print('Am creat cu succes directorul ', azi) # 5. Folosim comanda zip pentru a colecta fişierele în arhiva zip_command = "zip -qr {0} {1}".format(target, ' '.join(source)) # Rulăm salvarea if os.system(zip_command) == 0: print('Salvare reuşită în ', target) else: print('Salvare EŞUATĂ')

Rezultat:  $ python backup_ver3.py File "backup_ver3.py", line 25 target = azi + os.sep + now + '_' + ^

SyntaxError: invalid syntax

Cum (nu) funcţionează:  Acest program nu funcţionează! Python spune că e undeva o eroare de sintaxă ceea ce înseamnă că  programul nu a fost bine scris, că nu respectă structura pe care se aşteaptă Python să o găsească  acolo. Când vedem eroarea dată de Python, aflăm şi locul unde a detectat el eroarea. Deci începem  eliminarea erorilor (engl. debugging) programului de la acea linie.  La o observaţie atentă, vedem ca o linie logică a fost extinsă pe două linii fizice fără să se specifice  acest lucru. În esenţă Python a găsit operatorul de adunare (+) fără vreun operand în acea linie şi  prin urmare nu ştie cum să continue. Vă amintiţi că putem specifica trecerea unei linii logice pe  următoarea linie fizică folosind un backslash la sfârşitul liniei fizice. Astfel facem corectura la  progrmul nostru. Aceasta corecţie a programului când gasim erori se numeşte depanare (engl. bug  fixing). 

66

Versiunea a patra  #!/usr/bin/python # Fişier: backup_ver4.py import os import time # 1. Fişierele de salvat sunt specificate întro listă. source = ['"C:\\My Documents"', 'C:\\Code'] # Observaţi că a trebuit să punem ghilimele duble pentru a proteja spaţiile din interiorul numelor. # 2. Salvarea trebuie stocată în directorul principal de backup target_dir = 'E:\\Backup' # Nu uiţati să schimbaţi asta cu ceea ce folosiţi voi # 3. Salvările se fac în arhive zip. # 4. Ziua curentă este numele subdirectorului din directorul principal de backup azi = target_dir + os.sep + time.strftime('%Y%m%d') # Ora curentă este numele arhivei zip acum = time.strftime('%H%M%S') # Acceptăm un comentariu de la utilizator comentariu = input('Introduceţi un comentariu --> ') if len(comentariu) == 0: # Verificăm dacă a fost introdus un comentariu target = azi + os.sep + acum + '.zip' else: target = azi + os.sep + acum + '_' + \ comentariu.replace(' ', '_') + '.zip' # Creăm subdirectorul, dacă nu exista deja if not os.path.exists(azi): os.mkdir(azi) # creăm directorul print('Am creat cu succes directorul ', today) # 5. Folosim comanda zip pentru a colecta fişierele în arhivă zip zip_command = "zip -qr {0} {1}".format(target, ' '.join(source)) # Rulăm comanda de backup if os.system(zip_command) == 0: print('Salvare reuşită în ', target) else: print('Salvare EŞUATĂ')

Rezultat:  $ python backup_ver4.py Introduceţi un comentariu --> noi exemple adăugate Salvare reuşită în E:\Backup\20090209\162836_noi_exemple_adăugate.zip $ python backup_ver4.py Introduceţi un comentariu --> Salvare reuşită în E:\Backup\20090209\162916.zip

Cum functionează: 

67

Acest program funcţionează, acum! Să parcurgem îmbunătăţirile pe care i le­am adus în versiunea 3.  Acceptăm un comentariu de la utilizator folosind funcţia input şi apoi testăm dacă s­a introdus  ceva sau nu calculând lungimea şirului introdus cu ajutorul funcţiei len. Dacă utilizatorul a dat  ENTER fără să introducă ceva (poate era doar un backup de rutină şi n­au fost făcute modificări  anume), apoi continuăm ca mai înainte.  Totuşi, dacă a fost introdus un comentariu, acesta este ataşat numelui arhivei zip, chiar înaintea  extensiei .zip. Observaţi că înlocuim spaţiile în comentariu cu underscore ­ ca să fie mai uşoară  gestiunea fişierelor cu nume lungi. 

Alte rafinamente  A patra versiune este una satisfăcătoare pentru majoritatea utilizatorilor, dar este mereu loc pentru  mai bine. De exemplu se poate introduce un nivel de logoree (engl. verbosity) pentru program, cu  ajutorul opţiunii -v Pentru a face programul mai vorbăreţ.  Altă îmbunătăţire posibilă ar fi să permitem ca fişierele şi directoarele de salvat să fie transmise  scriptului la linia de comandă. Noi le putem culege din lista sys.argv şi le putem adăuga la  variabila listă source folosind metoda extend a clasei list.  Cea mai importanta extindere ar fi să nu folosim os.system ci direct modulele predefinite  zipfile sau tarfile pentru a crea aceste arhive. Ele sunt parte a bibliotecii standard şi sunt  deja disponibile pentru a scrie un program fără dependente externe pentru programul de arhivare.  Totuşi, am folosit os.system pentru crearea salvărilor din motive pedagogice, pentru ca exemplul  să fie destul de simplu de înteles, dar şi util.  Puteţi încerca să scrieţi a cincea variantă folosind modulul zipfile în locul apelului os.system? 

Procesul de dezvoltare de software  Am trecut prin diverse faze în procesul de scriere a unui program. Aceste faze pot fi rezumate astfel:  1. 2. 3. 4. 5. 6.

Ce (Analiza)  Cum (Design)  Executare (Implementare)  Test (Testare şi eliminare erori)  Utilizare (Operare sau distribuire)  Mentenanţă (Rafinare) 

O cale recomandată de a scrie programe este procedura urmată de noi la scrierea scriptului de  salvare: facem analiza şi designul. Începem implementarea cu o versiune simplă. O testăm şi o  depanăm. O folosim pentru a ne asigura că merge cum ne­am propus. Acum îi adăugăm noi facilităţi  pe care le dorim şi parcurgem ciclul FACI ­ TESTEZI ­ UTILIZEZI de câte ori este nevoie. Reţineţi,  Software­ul este crescut, nu construit. 

Rezumat  Am văzut cum se creează un program/script Python şi diferite stadii implicate de scrierea unui  program. Aţi putea considera utilă scrierea de programe proprii, atât pentru acomodarea cu Python  cât şi pentru a rezolva probleme.  68

În continuare vom discuta despre programarea orientată pe obiecte. 

69

Python ro:Programare orientată pe obiecte Introducere  În toate programele folosite până acum ne­am construit soluţiile în jurul funcţiilor adică blocuri de  declaraţii care manipulează date. Acest mod de programare se numeşte orientat pe proceduri. Există  şi un alt mod de organizare a programelor, în care funcţionalitatea şi datele sunt împachetate  împreună în unităţi numite obiecte. Acest mod de structurare defineşte paradigma "orientat pe  obiecte. Aproape tot timpul puteţi folosi abordări procedurale în programare, dar când scrieţi  programe mari sau aveţi de rezolvat probleme care sunt mai aproape de acest mod de structurare,   puteţi folosi tehnicile de programare orientată pe obiecte..  Clasele şi obiectele sunt două aspecte ale programării orientate pe obiecte. O clasă creeaza un nou  tip în care obiectele sunt instanţe ale clasei. O analogie este că puteţi avea variabile de tip int care  se traduce prin aceea că variabilele care stochează întregi sunt instanţe (obiecte) ale clasei int.  Notă pentru programatorii în limbaje cu tipuri statice  Observaţi că până şi întregii sunt trataţi ca obiecte (ale clasei int). Asta e diferit de C++ şi  Java (în versiunile dinainte de 1.5) în care întregii sunt tipuri primitive native. A se vedea  help(int) pentru detalii despre clasă.  Programatorii în C# şi Java 1.5 vor găsi o similaritate cu conceptele de încapsulare şi  decapsulare.  Obiectele pot stoca date folosind variabile obişnuite care aparţin obiectului. Variabilele care aparţin  unui obiect sunt numite câmpuri. Obiectele pot avea şi funcţionalitate folosind funcţii care aparţin  clasei. Aceste funcţii se munesc metode ale clasei. Această terminologie este importantă deoarece  ne ajuta să diferenţiem între funcţii şi variabile independente şi cele aparţinând unui obiect sau unei  clase. Împreună, variabilele şi funcţiile care aparţin unei clase se numesc atribute ale clasei.  Câmpurile sunt de două tipuri ­ ele pot aparţine fiecărei instanţe/obiect al clasei sau pot aparţine  însăşi clasei. Acestea sunt numite variabile de instanţă respectiv variabile ale clasei.  O clasă este creată folosind cuvântul cheie class. Câmpurile şi metodele clasei sunt listate întrun  bloc indentat. 

self  Clasele şi metodele au o diferenţă specifică faţă de funcţiile obişnuite ­ ele trebuie să aibă un  prenume suplimentar care trebuie adăugat la începutul listei de parametri, dar nu trebuie să­i daţi o  valoare când apelaţi metoda, Python o va furniza. Această variabilă specială se referă la obiectul  însuşi (engl. self) şi prin convenţie este numită self.  Cu toate acestea, deşi puteţi să­i daţi orice nume acestui parametru, este puternic recomandat să  folosiţi numele self ­ orice alt nume este dezaprobat. Există multe avantaje în folosire numelui  standard ­ orice cititor al programului va înţelege imediat despre ce este vorba şi chiar mediile IDE  (Integrated Development Environments) specializate te pot ajuta dacă foloseşti self.  70

Notă pentru programatorii în C++/Java/C#  self din Python este echivalent cu pointerul this din C++ şi cu referinţa this din Java şi  C#.  Probabil vă întrebaţi cum dă Python valoarea corectă lui self şi de ce nu trebuie să­i dăm o  valoare. Un exemplu va clarifica această problemă. Să zicem că aveţi o clasă numită MyClass şi o  instanţă a acestei clase, numită myobject. Când apelaţi o metodă a acestui obiect  myobject.method(arg1, arg2), apelul este automat convertit de Python în  MyClass.method(myobject, arg1, arg2) ­ asta e toată marea specialitate a lui self.  Asta înseamnă şi că dacă aveţi o metodă care nu primeşte argumente, tot va trebui să aveţi un  argument ­ self. 

Clase  Cea mai simplă clasă posibilă este arătată în exemplul următor.  #!/usr/bin/python # Fişier: simplestclass.py class Persoana: pass # Un bloc gol p = Persoana() print(p)

Rezultat:  $ python simplestclass.py

Cum funcţionează:  Creăm o clasă nouă folosind declaraţia class şi numele clasei. Aceasta este urmată de un bloc  indentat de declaraţii care formează corpul clasei. În acest caz avem un bloc gol, arătat de declaraţia  pass.  În continuare creăm un obiect/instanţă a acestei clase folosind numele clasei urmat de o pereche de  paranteze. (Vom învăţa mai multe despre instanţiere în paragraful următor). Pentru propria  verificare, confirmăm tipul variabilei prin simpla ei tipărire. Aflăm că avem o instanţă a variabilei  din clasa Persoana din modulul __main__.  Observaţi că a fost tipărită şi adresa unde este stocat obiectul în memoria calculatorului. Adresa  aceasta va avea o valoare diferită în alt calculator deoarece Python îl stochează unde are loc. 

Metodele obiectelor  Am discutat deja că obiectele/clasele pot avea metode, exact ca funcţiile, doar că au un argument  self în plus. Iată un exemplu.  #!/usr/bin/python # Fişier: metoda.py class Persoana:

71

def ziSalut(self): print('Salut, ce mai faci?') p = Persoana() p.ziSalut() # Acest exemplu poate fi scris şi ca Persoana().ziSalut()

Rezultat:  $ python metoda.py Salut, ce mai faci?

Cum funcţionează:  Aici vedem particula self în acţiune. Observaţi că metoda ziSalut nu primeşte parametri, dar  tot are argumentul self în definiţia funcţiei. 

Metoda __init__  Există multe nume de metode care au un înteles special în clasele Python. Acum vom afla  semnificaţia metodei __init__.  Metoda __init__ este executată imediat ce este instanţiat un obiect al clasei. Metoda este utilă  pentru a face iniţializarea dorită pentru obiectul respectiv. Observaţi că numele este încadrat cu  dublu underscore.  Exemplu:  #!/usr/bin/python # Fişier: class_init.py class Persoana: def __init__(self, nume): self.nume = nume def ziSalut(self): print('Salut, numele meu este ', self.nume) p = Persoana('Swaroop') p.ziSalut() # Acest exemplu putea fi scris Persoana('Swaroop').ziSalut()

Rezultat:  $ python class_init.py Salut, numele meu este Swaroop

Cum funcţionează:  Definim metoda __init__ să ia un parametru nume (pe lângă obişnuitul self). În acest caz  creăm doar un câmp numit nume. Observaţi că deşi ambele sunt numite 'nume', cele două sunt  obiecte diferite. Notaţia cu punct ne permite să le deosebim.  Cel mai important, observaţi că nu apelăm explicit metoda __init__ ci îi transmitem argumentele  în paranteză după numele clasei în momentul creării obiectului/instanţa a clasei. Aceasta este  semnificaţia acestei metode.  72

Acum putem să folosim câmpul self.name în metodele noastre, ceea ce este arătat în metoda  ziSalut. 

Variabile de clasă, variabile de instanţă  Am discutat deja partea de funcţionalitate a claselor şi obiectelor (adică metodele), acum să învăţăm  ceva despre partea de date. Partea de date, aşa­numitele câmpuri, nu sunt altceva decât variabile  obişnuite care sunt legate de spaţiile de nume ale claselor şi obiectelor. Asta înseamnă că aceste  nume sunt valabile numai în contextul claselor şi obiectelor respective. Din acest motiv acestea sunt  numite spaţii de nume (engl. name spaces).  Există două feluri de câmpuri ­ variabile de clasa şi variabile de obiect/instanţă, care sunt clasificate  în funcţie de proprietarul variabilei.  Variabilele de clasă sunt partajate ­ ele pot fi accesate de toate instanţele acelei clase. Există doar un  exemplar al variabilei de clasă şi când o instanţă îi modifică valoarea, această modificare este văzută  imediat de celelalte instanţe.  Variabilele de instanţă sunt proprietatea fiecărei instanţe a clasei. În acest caz, fiecare obiect are  propriul exemplar al acelui câmp adică ele nu sunt relaţionate în nici un fel cu câmpurile având  acelaşi nume în alte insţante. Un exemplu va ajuta la înţelegerea situaţiei:  #!/usr/bin/python # Fişier: objvar.py clasa Robot: '''Reprezintă un robot cu nume.''' # O variabilă de clasă, numărătorul populaţiei de roboţi populaţie = 0 def __init__(self, nume): '''Iniţializează datele.''' self.nume = nume print('(Iniţializez robotul {0})'.format(self.nume)) # Când această instanţă este creată, robotul se # adaugă la populaţie Robot.populaţie += 1 def __del__(self): '''Dispar...''' print('{0} este dezmembrat!'.format(self.nume)) Robot.populaţie -= 1 if Robot.populaţie == 0: print('{0} a fost ultimul.'.format(self.nume)) else: print('Mai există {0:d} roboţi apţi de lucru.'.format(Robot.populaţie)) def ziSalut(self): '''Salutare de la robot. Da, pot să facă şi asta.''' print('Salut. Stăpânii mei îmi zic {0}.'.format(self.nume))

73

def câţi(): '''Tipăreşte populaţia curentă.''' print('Avem {0:d} roboţi.'.format(Robot.populaţie)) câţi = staticmethod(câţi) droid1 = Robot('R2-D2') droid1.ziSalut() Robot.câţi() droid2 = Robot('C-3PO') droid2.ziSalut() Robot.câţi() print("\nRoboţii pot să facă nişte treabă aici.\n") print("Roboţii au terminat treaba. Deci să-i distrugem.") del droid1 del droid2 Robot.câţi()

Rezultat:  (Iniţializez robotul R2-D2) Salut. Stăpânii mei îmi zic R2-D2. Avem 1 roboţi. (Iniţializez robotul C-3PO) Salut. Stăpânii mei îmi zic C-3PO. Avem 2 roboţi. Roboţii pot să facă nişte treabă aici. Roboţii au terminat treaba. Deci să-i distrugem. R2-D2 este dezmembrat! Mai există 1 roboţi apţi de lucru. C-3PO este dezmembrat! C-3PO a fost ultimul. Avem 0 roboţi.

Cum funcţionează:  Este un exemplu lung, dar ajută la evidenţierea naturii variabilelor de clasă şi de instanţă. Aici  câmpul populaţie aparţine clasei Robot şi este deci o variabilă de clasă. Variabila nume aparţine obiectului (îi este atribuită folosind self.) deci este o variabilă de obiect/instanţă.  Asadar ne referim la variabila de clasă populaţie cu notaţia Robot.populaţie şi nu cu  self.populaţie. Ne referim la variabila de instanţă nume cu notaţia self.nume în metodele  acelui obiect. Amintiţi­vă această diferenţă simplă între variabilele de clasă şi de instanţă. Mai  observaţi şi că o variabilă de obiect cu acelaşi nume ca o variabilă de clasă, va ascunde variabila de  clasă faţă de metodele clasei!  Metoda câţi este în fapt o metodă a clasei şi nu a instanţei. Asta înseamnă că trebuie să o definim  cu declaraţia classmethod sau staticmethod Dacă vrem să ştim cărui spaţiu de nume îi  aparţine. Întrucât nu vrem aceasta informaţie, o vom defini cu staticmethod.  Am fi putut obţine acelaşi lucru folosind decoratori:  @staticmethod

74

def câţi(): '''Tipăreşte populaţia curentă.''' print('Avem {0:d} roboti.'.format(Robot.populaţie))

Decoratorii pot fi concepuţi ca scurtături pentru apelarea unor declaraţii explicite, aşa cum am văzut  în acest exemplu.  Observaţi că metoda __init__ este folosită pentru a iniţializa cu un nume instanţa clasei Robot.  În această metodă, mărim populaţie cu 1 intrucât a fost creat încă un robot. Mai observaţi şi că  valoarea self.nume este specifică fiecărui obiect, ceea ce indică natura de variabilă de instanţă a  variabilei.  Reţineţi că trebuie să vă referiţi la variabilele şi metodele aceluiaşi obiect numai cu self. Acest  mod de indicare se numeşte referinţă la atribut.  În acest program mai vedem şi docstrings pentru clase şi metode. Putem accesa docstringul clasei  în runtime (rom. timpul execuţiei) folosind notaţia Robot.__doc__ şi docstring­ul metodei  ziSalut cu notaţia Robot.ziSalut.__doc__  Exact ca şi metoda __init__, mai există o metodă specială, __del__, care este apelată atunci  când un obiect trebuie distrus, adică nu va mai fi folosit, iar resursele lui sunt returnate sistemului.  În această metodă reducem şi numărul Robot.populaţie cu 1.  Metoda __del__ este executată dacă obiectul nu mai este în folosinţă şi nu există o garanţie că  metoda va mai fi rulată. Dacă vreţi să o vedeţi explicit în acţiune, va trebui să folosiţi declaraţia del cum am făcut noi aici.  Notă pentru programatorii în C++/Java/C#  Toţi membrii unei clase (inclusiv membrii date) sunt publici şi toate metodele sunt virtual în  Python.  O excepţie: Dacă folosiţi membrii date cu nume care încep cu dublu underscore precum  __var_privată, Python exploatează acest aspect şi chiar va face variabila să fie privată.  Aşadar, convenţia este că orice variabilă care vrem să fie folosită numai în contextul clasei sau  obiectului, ar trebui să fie numită cu primul caracter underscore, iar toate celelalte nume sunt  publice şi pot fi folosite de alte clase/instanţe. Reţineţi că aceasta este doar o convenţie şi nu  este impusă de Python (exceptând prefixul dublu underscore). 

Moştenire  Un beneficiu major al programării orientate pe obiecte este refolosirea codului şi o cale de a obţine  asta este mecanismul de moştenire. Moştenirea poate fi descrisă cel mai bine ca şi cum ar  implementa o relaţie între un tip şi un subtip între clase.  Să zicem că scrieţi un program în care trebuie să ţineţi evidenţa profesorilor şi studenţilor într­un  colegiu. Ei au unele caracteristici comune, precum nume, adresă, vârstă. Ei au şi caracteristici  specifice, cum ar fi salariul, cursurile şi perioadele de absenţă, pentru profesori, respectiv notele şi  taxele pentru studenţi.  Puteţi crea două clase independente pentru fiecare tip şi procesa aceste clase prin adăugarea de  caracteristici noi. Aşa programul devine repede un hăţis necontrolabil.  O cale mai bună ar fi să creaţi o clasă comună numită MembruAlŞcolii şi să faceţi clasele  student şi profesor să moştenească de la această clasă, devenind astfel subclase ale acesteia, şi apoi  75

să adăugaţi caracteristici la aceste subtipuri.  Această abordare are multe avantaje. Dacă facem vreo schimbare la funcţionalitatea clasei  MembruAlŞcolii, ea este automat reflectată şi în subtipuri. De exemplu, puteţi adăuga un nou  câmp card ID şi pentru studenţi şi pentru profesori prin simpla adăugare a acestuia la clasa  MembruAlŞcolii. Totuşi, schimbările din subtipuri nu afectează alte subtipuri. Alt avantaj este că  puteţi face referire la un profesor sau student ca obiect MembruAlŞcolii object, ceea ce poate fi  util în anumite situaţii precum calculul numărului de membri ai şcolii. Acest comportament este  numit polimorfism, în care un subtip poate fi folosit în orice situatie în care se aşteaptă folosirea  unui tip părinte adică obiectul poate fi tratat drept instanţă a tipului părinte.  Observaţi şi că refolosim codul clasei părinte şi nu e nevoie să­l repetăm în subclase cum am fi fost  nevoiţi dacă am fi creat clase independente.  Clasa MembruAlŞcolii în această situaţie este numită clasa bază sau superclasa. Clasele  profesor şi student sunt numite clase derivate sau subclase.  Vom vedea acest exemplu pe un program.  #!/usr/bin/python # Fişier: inherit.py class MembruAlŞcolii: '''Reprezintă orice membru al şcolii.''' def __init__(self, nume, vârstă): self.nume = nume self.varsta = vârstă print('(Iniţializez MembruAlŞcolii: {0})'.format(self.nume)) def descrie(self): '''Afişează detaliile mele.''' print('Nume:"{0}" Vârstă:"{1}"'.format(self.nume, self.vârstă), end=" ") class profesor(MembruAlŞcolii): '''Reprezintă un profesor.''' def __init__(self, nume, vârstă, salariu): MembruAlŞcolii.__init__(self, nume, vârstă) self.salariu = salariu print('(Iniţializez Profesor: {0})'.format(self.nume)) def descrie(self): MembruAlŞcolii.descrie(self) print('Salariu: "{0:d}"'.format(self.salariu)) class student(MembruAlŞcolii): '''Reprezintă un student.''' def __init__(self, nume, vârstă, note): MembruAlŞcolii.__init__(self, nume, vârstă) self.note = note print('(Iniţializez student: {0})'.format(self.nume)) def descrie(self): MembruAlŞcolii.descrie(self) print('Note: "{0:d}"'.format(self.note)) p = profesor('D-na. Shrividya', 40, 30000) s = student('Swaroop', 25, 75) print() # Afişează o linie goală

76

membri = [p, s] for membru in membri: membru.descrie() # Funcţionează şi pentru profesor şi pentru student

Rezultat:  $ python inherit.py (Iniţializez MembruAlŞcolii: Mrs. Shrividya) (Iniţializez profesor: D-na. Shrividya) (Iniţializez MembruAlŞcolii: Swaroop) (Iniţializez student: Swaroop) Nume:"D-na. Shrividya" Vârstă:"40" Salariu: "30000" Nume:"Swaroop" Vârstă:"25" Note: "75"

Cum funcţionează:  Pentru a folosi moştenirea, specificăm clasele bază întrun tuplu care urmează numele în definiţia  clasei. Apoi observăm că metoda __init__ a clasei bază este apelată explicit folosind variabila  self ca să putem iniţializa partea din obiect care provine din clasa bază. Este foarte important de  reţinut ­ Python nu apeleaza automat constructorul clasei bază, trebuie să faceţi asta explicit.  Mai observăm că apelurile către clasa bază se fac prefixind numele clasei apelului metodelor şi  punând variabila self împreună cu celelalte argumente.  Se confirmă că folosim instanţele claselor profesor şi student ca şi cum ar fi instanţe ale  clasei MembruAlŞcolii când folosim metoda descrie a clasei MembruAlŞcolii.  În plus, observaţi că este apelată metoda descrie a subtipului nu metoda descrie a clasei  MembruAlŞcolii. O cale de a întelege asta este că Python începe întotdeauna căutarea  metodelor în tipul curent, ceea ce face în acest caz. Dacă nu ar fi găsit metoda, ar fi căutat în clasele  părinte, una câte una, în ordinea specificată în tuplul din definiţia clasei.  O notă asupra terminologiei ­ daca în tuplul de moştenire este listată mai mult de o clasă, acest caz  este de moştenire multiplă. 

Rezumat  Am explorat diverse aspecte ale claselor şi obiectelor precum şi diferite terminologii asociate cu  acestea. Am văzut de asemenea beneficiile şi punctele slabe ale programării orientate pe obiecte.  Python este puternic orientat pe obiecte şi înţelegerea acestor concepte vă va ajuta enorm în cariera  de programator.  Mai departe vom învăţa să tratăm cu intrările şi ieşirile şi cum să accesam fişiere în Python. 

77

Python ro:Intrări/ieşiri Introducere  Există situaţii în care programul la care lucraţi trebuie să interacţioneze cu utilizatorul. De exemplu,  vreţi să preluaţi date de la utilizator şi să tipăriţi nişte rezultate. Putem folosi funcţiile input() şi  print().  Pentru ieşire, putem folosi şi diverse metode ale clasei str (string). De exemplu, putem folosi  metoda rjust pentru a alinia judicios la dreapta pe o anumită lungime. A se vedea help(str) pentru detalii suplimentare.  Alt tip obişnuit de intrare/ieşire este lucrul cu fişiere. Capacitatea de a crea, citi şi scrie fişiere este  esenţială pentru programele pe care le vom scrie în acest capitol. 

Intrări de la utilizator  #!/usr/bin/python # FIşier: user_input.py def reverse(text): return text[::-1] def is_palindrome(text): return text == reverse(text) ceva = input('Introduceţi textul: ') if (is_palindrome(ceva)): print("Da, este un palindrom") else: print("Nu, nu este un palindrom")

Rezultat:  $ python user_input.py Introduceţi textul: şir Nu, nu este un palindrom $ python user_input.py Introduceţi textul: madam Da, este un palindrom $ python user_input.py Introduceţi textul: racecar Da, este un palindrom

Cum funcţionează:  Folosim facilitatea de feliere pentru a inversa textul. Am învăţat deja cum să facem felii din secvenţe  între poziţiile a şi b folosind formula seq[a:b]. Putem da şi un al treilea argument care  determină pasul felierii. Pasul implicit este 1 motiv pentru care va rezulta o porţiune continuă din  78

text. Cu un pas negativ, de exemplu -1 textul va fi inversat.  Funcţia input() ia ca argument un şir şi îl afişează utilizatorului. Apoi asteaptă utilizatorul să  introducă ceva şi să apese tasta ENTER. În acel moment funcţia input() va întoarce în program  textul introdus.  Luăm acel text şi îl inversăm. Dacă originalul şi textul inversat sunt identice, textul este un  palindrom (definiţia pentru limba engleza).  Tema pentru acasă:  Verificarea calităţii de palindrom ar trebui să ignore punctuaţia, spaţiile şi cazul caracterelor. De  exemplu "Ele fac cafele." este de asemenea palindrom, dar programul nostru spune că nu. Puteţi  îmbunătăţi acest program ca să recunoască acest palindrom? 

Fişiere  Puteţi deschide fişiere pentru scriere sau citire prin crearea unui obiect din clasa file (rom. fişier)  şi folosind metodele sale read, readline sau write după caz. Capacitatea de a citi sau scrie  întrun fişier depinde de modul în care aţi specificat fişierul în declaraţia de deschidere. În final,  când aţi terminat lucrul cu fişierul, puteţi apela metoda close pentru a­i da lui Python să­l închidă.  Exemplu:  #!/usr/bin/python # Fişier: using_file.py from __future__ import print_function poem = '''\ Programming is fun When the work is done if you wanna make your work also fun: use Python! ''' f = open('poem.txt', 'w') # Deschidere pentru scriere # 'w' vine de la 'writing' (rom. scriere) f.write(poem) # scriem textul în fişier f.close() # închidem fişierul f = open('poem.txt') # Dacă nu este specificat modul, se presupune citire, 'r' vine de la 'read' (rom. citire) while True: linie = f.readline() if len(linie) == 0: # Lungime 0 indică EOF - sfârşitul fişierului (engl. End Of File) break print(linie, end='') f.close() # închidem fişierul

Rezultat:  $ python using_file.py Programming is fun When the work is done if you wanna make your work also fun: use Python!

79

Cum funcţionează:  Întâi deschidem un fişier folosind funcţia predefinită open şi specificând numele fişierului şi  modul în care vrem să fie deschis fişierul. Modul poate fi 'mod citire' ('r'), mod 'scriere' ('w')  sau mod 'adăugare la sfârşit' ('a') (engl. append). Putem folosi şi ('t') pentru fişiere text sau  ('b') pentru fişiere binare. În realitate există multe moduri posibile, pe care le puteţi afla lansând  help(open). Implicit, open() consideră fişierul 't'ext şi îl deschide în mod 'r' (citire).  În exemplul nostru deschidem fişierul în mod scriere şi folosim metoda write a obiectului fişier  pentru a scrie în fişier şi apoi îl închidem cu funcţia close.  În continuare deschidem acelaşi fişier din nou, în mod citire. Nu avem nevoie să specificăm modul  deoarece este cel implicit. Citim fiecare linie folosind funcţia readline întro buclă. Această  metoda întoarce un rând complet, inclusiv caracterul 'linie nouă' (engl. newline) de la sfârşitul liniei.  Dacă este returnat un şir gol (engl. empty), înseamnă că s­a ajuns la sfârşitul fişierului şi ieşim din  buclă cu declaraţia 'break'.  Implicit, funcţia print() tipăreste textul şi un caracter newline în mod automat pe ecran.  Suprimăm caracterul newline automat specificând end='' deoarece linia citită are deja un caracter  newline la sfârşit. La final închidem fişierul cu close.  Acum verificaţi conţinutul fişierului poem.txt pentru a confirma că programul a scris întradevăr  în fişier şi a citit din acesta. 

Conservarea  Python oferă un modul standard numit pickle (rom. a conserva, a mura) cu ajutorul căruia puteţi  depozita orice obiect Python întrun fişier pentru a­l reactiva mai târziu. Acest fapt se numeşte  stocare persistentă.  Exemplu:  #!/usr/bin/python # Fişier: pickling.py import pickle # Numele fişierului în care stocăm obiectul shoplistfile = 'shoplist.data' # lista de cumpărături shoplist = ['mere', 'mango', 'morcovi'] # Scriem în fişier f = open(shoplistfile, 'wb') pickle.dump(shoplist, f) # depunem (engl. dump) obiectul în fişier f.close() del shoplist # distrugem variabila shoplist # Refacem din depozit f = open(shoplistfile, 'rb') storedlist = pickle.load(f) # încărcăm obiectul din fişier print(storedlist)

Rezultat: 

80

$ python pickling.py ['mere', 'mango', 'morcovi']

Cum funcţionează:  Pentru a stoca un obiect întrun fişier, trebuie să deschidem fişierul în mod scriere binară ('w' şi 'b')  cu funcţia open şi să apelăm funcţia dump a modulului pickle. Acest proces se numeşte pickling  (rom. conservare, figurativ:punere la murat).  Apoi refacem obiectul folosind funcţia load a modulului pickle, care întoarce obiectul. Acest  proces se numeşte unpickling (rom. deconservare, figurativ: scoatere de la murat). 

Rezumat  Am discutat variate tipuri de intrări/ieşiri şi manipularea fişierelor folosind modulul pickle.  Acum vom studia conceptul de excepţie. 

81

Python ro:Excepţii Introducere  Excepţiile pot apărea atunci când apar anumite situaţii excepţionale în program. De exemplu, dacă  trebuie să citiţi un fişier, dar acesta nu există? Sau dacă l­aţi şters accidental în timpul rulării  programului? Astfel de situaţii sunt tratate folosind excepţii.  Similar, daca în program erau câteva declaraţii invalide? Aceste situaţii sunt tratate de Python care  ridică mâinile şi vă spune ca există o eroare. 

Erori  Iată un exemplu simplu de apel al funcţiei print. daca aţi scris greşit Print în loc de print?  Observaţi majuscula. În acest caz, Python ridică o eroare de sintaxă.  >>> Print('Hello World') Traceback (most recent call last): File "", line 1, in Print('Hello World') NameError: name 'Print' is not defined >>> print('Hello World') Hello World

Observaţi că a fost ridicată o eroare NameError şi a fost indicată poziţia unde a fost detectată  eroarea. Asta este acţiunea unei rutine pentru tratarea erorii (engl. error handler). 

Excepţii  Vom încerca (engl. try) să preluăm date de la utilizator. Daţi ctrl-d şi vedeţi ce se întâmplă.  >>> s = input('Introduceţi ceva --> ') Introduceţi ceva --> Traceback (most recent call last): File "", line 1, in s = input('Introduceţi ceva --> ') EOFError: EOF when reading a line

Python ridică o eroare numită EOFError ceea ce înseamnă în esenţă că a găsit simbolul end of file  (care se reprezinta prin ctrl-d) întrun moment în care nu era posibil. 

Tratarea excepţiilor  Putem trata excepţiile folosind declaraţia try..except. Pe scurt, punem declaraţiile uzuale în  blocul try şi toate tratamentele de erori în blocul except.  #!/usr/bin/python # Fişier: try_except.py

82

try: text = input('Introduceţi ceva --> ') except EOFError: print('De ce îmi dai EOF?') except KeyboardInterrupt: print('Aţi anulat operaţia.') else: print('Aţi introdus {0}'.format(text))

Rezultat:  $ python try_except.py Introduceţi ceva --> De ce îmi dai EOF?

# Daţi ctrl-d

$ python try_except.py Introduceţi ceva --> Aţi anulat operaţia.

# Daţi ctrl-c

$ python try_except.py Introduceţi ceva --> # fără excepţii, acum Aţi introdus fără excepţii, acum

Cum funcţionează:  Punem toate declaraţiile care ar putea ridica excepţii/erori în blocul try şi apoi punem rutine de  tratare pentru erorile/excepţiile respective în blocul except. Clauza except poate trata o singură  eroare sau excepţie specificată, sau o listă în paranteze a excepţiilor/erorilor. Dacă nu sunt date  nume de erori/excepţii, sunt tratate toate erorile şi excepţiile.  Reţineţi că trebuie să existe măcar o clauză except asociată cu fiecare clauză try. În caz contrar  ce înteles are un bloc try?  Dacă o eroare sau excepţie nu este tratată, este apelată rutina implicită de tratare a limbajului Python  care pur şi simplu opreşte execuţia programului şi tipăreste pe ecran un mesaj de eroare. Am văzut  deja asta.  Mai poate exista şi o clauză else asociată cu un bloc try..except. Clauza else este executată  dacă nu apare nici o excepţie/eroare.  În următorul exemplu vom vedea cum să obţinem obiectul excepţie, pentru a­i extrage informaţii  suplimentare. 

Ridicarea excepţiilor  Puteti ridica excepţii folosind declaraţia raise şi furnizînd numele erorii/excepţiei şi obiectul care  urmează a fi aruncat (engl. thrown).  Eroarea sau excepţia pe care o ridicaţi trebuie să fie o clasă derivată direct sau indirect din clasa  Exception.  #!/usr/bin/python # Fişier: raising.py class ShortInputException(Excepţie): '''O clasa de excepţii definită de utilizator.''' def __init__(self, lungime, minim):

83

Excepţie.__init__(self) self.lungime = lungime self.minim = minim try: text = input('Introduceţi ceva --> ') if len(text) < 3: raise ShortInputException(len(text), 3) # Alte prelucrări pot continua aici ca înainte except EOFError: print('De ce îmi dai EOF?') except ShortInputException as ex: print('ShortInputException: Aţi introdus un text de lungime {0}, era necesar minim {1}'\ .format(ex.lungime, ex.minim)) else: print('Nu a fost ridicată nici o excepţie.')

Rezultat:  $ python raising.py Introduceţi ceva --> a ShortInputException: Aţi introdus un text de lungime 1, era necesar minim 3 $ python raising.py Introduceţi ceva --> abc Nu a fost ridicată nici o excepţie.

Cum funcţionează:  Aici creăm un tip propriu de excepţie. Acest tip nou de excepţie este numit  ShortInputException. Are două câmpuri ­ lungime care este lungimea introducerii şi  minim care este lungimea minimă acceptată de program.  În clauza except menţionăm clasa de erori care va fi stocată sub numele (engl. as) variabilei  care va păstra obiectul excepţie. Asta este analog parametrilor şi argumentelor în apelul funcţiei.  Anume în această clauză except folosim câmpurile lungime şi minim ale obiectului excepţie  pentru a tipări un mesaj adecvat către utilizator. 

try .. finally  Să presupunem că vreţi să citiţi un fişier întrun program. Cum vă asiguraţi că fişierul a fost închis  corect indiferent dacă a apărut sau nu o eroare? Asta se poate face folosind blocul finally.  Observaţi că puteţi folosi o clauză except împreună cu clauza finally pentru acelaşi bloc try.  Va trebui să le imbricaţi dacă le vreţi pe amândouă.  #!/usr/bin/python # Fişier: finally.py import time try:

f = open('poem.txt') while True: # citirea obişnuită line = f.readline() if len(line) == 0: break

84

print(line, end='') time.sleep(2) # Ca să ne asigurăm că funcţionează un timp except KeyboardInterrupt: print('!! Aţi anulat citirea din fişier.') finally: f.close() print('(Curăţenie: Am închis fişierul)')

Rezultat:  $ python finally.py Programming is fun When the work is done if you wanna make your work also fun: !! Aţi anulat citirea din fişier. (Curăţenie: Am închis fişierul)

Cum funcţionează:  Facem treburile curente la citirea fişierelor, dar avem o aşteptare de două secunde introdusă arbitrar  după tipărirea fiecarei linii folosind funcţia time.sleep ca să ruleze mai lent (Python este foarte  rapid prin natura lui). Când programul încă rulează apasaţi ctrl-c pentru a întrerupe programul.  Observaţi că este aruncată excepţia KeyboardInterrupt şi programul se încheie. Totuşi,  înainte ca programul să se încheie, clauza finally se execută şi obiectul fişier este întotdeauna închis. 

Declaraţia with  Achiziţia unei resurse în blocul try şi eliberarea ei în blocul finally este o schemă obişnuită.  Din acest motiv există şi o declaraţie with care permite ca această utilizare a resursei să se facă  într­o manieră mai clară:  #!/usr/bin/python # Fişier: using_with.py with open("poem.txt") as f: for line in f: print(line, end='')

Cum funcţionează:  Rezultatul trebuie să fie la fel ca în exemplul precedent, diferenţa este că acum folosim funcţia  open cu declaraţia with ­ lăsăm închiderea fişierului să fie făcută automat de declaraţia with open ....  Ce se întâmplă în culise este un protocol utilizat de declaraţia with. Ea extrage obiectul întors de  funcţia open, să­i zicem "fişierul" în acest caz.  Ea apelează întotdeauna funcţia fişierul.__enter__ înainte de a începe blocul de declaraţii  pe care îl include şi funcţia fişierul.__exit__ după încheierea blocului de declaraţii.  Astfel codul care ar fi trebuit să fie scris în blocul finally este înlocuit automat de metoda  __exit__. Astfel suntem ajutaţi să evităm utilizarea explicită a declaraţiilor try..finally în  mod repetat.  Discuţia mai aprofundată a acestui subiect este dincolo de obiectivul acestei cărti, deci vă rog să  citiţi PEP 343 pentru o explicaţie completă.  85

Rezumat  Am discutat utilizarea declaraţiilor try..except şi try..finally. Am văzut cum putem  crea propriul tip de excepţie şi cum să ridicăm excepţii.  Vom explora în continuare biblioteca Python standard. 

86

Python ro:Biblioteca Python standard Introducere  Biblioteca Python standard conţine un număr uriaş de module utile şi este parte a oricărei instalări  standard Python. Este important să vă familiarizaţi cu biblioteca standard întrucât multe probleme  pot fi rezolvate rapid dacă cunoaşteţi plaja de lucruri pe care aceste module le pot face.  Vom explora câteva module utilizate mai frecvent din această bibliotecă. Detaliile complete (în  limba engleză) despre biblioteca Python standard pot fi găsite în capitolul 'Library Reference' din  documentaţia care vine cu instalarea Python.  Să explorăm cateva module utile.  Notă  Dacă aceste subiecte vi se par prea avansate puteţi trece peste acest capitol. Totuşi, vă  recomand călduros să reveniţi atunci când veţi fi mai familiarizaţi cu folosirea limbajului  Python. 

Modulul sys  Modulul sys conţine funcţionalitate specifică sistemului de operare. Am aflat deja că lista  sys.argv conţine argumentele liniei de comandă.  Să zicem că vreţi să verificaţi versiunea comenzii Python utilizate, să zicem pentru a vă asigura că  este cel puţin versiunea 3. Modulul sys dă o astfel de funcţionalitate.  >>> import sys >>> sys.version_info (3, 0, 0, 'beta', 2) >>> sys.version_info[0] >= 3 True

Cum funcţionează:  Modulul sys are un tuplu version_info care da informaţia despre versiune. Primul element dă  versiunea majoră. Noi o putem testa pentru a ne asigura că programul rulează sub versiunea minim  3.0:  #!/usr/bin/python # Fişier: versioncheck.py import sys, warnings if sys.version_info[0] < 3: warnings.warn("E nevoie de Python 3.0 sau ulterior pentru a rula acest program", RuntimeWarning) else: print('Continuăm normal')

Rezultat:  87

$ python2.5 versioncheck.py versioncheck.py:6: RuntimeWarning: E nevoie de Python 3.0 sau ulterior pentru a rula acest program $ python3 versioncheck.py Continuăm normal

Cum funcţionează:  Folosim alt modul din biblioteca standard, numit warnings (rom. avertizări) folosit pentru a afişa  utilizatorului avertismente pe ecran. Dacă versiunea Python nu este cel puţin 3, afişăm un  avertisment corespunzător. 

Modulul logging  Ce e de făcut dacă vreţi să stocaţi undeva mesaje importante sau de depanare, astfel încât să le  verificaţi mai târziu ca să analizaţi mersul programului? Cum stocaţi undeva aceste mesaje? Acest  obiectiv pate fi atins folosind modulul logging (rom. jurnalizare).  #!/usr/bin/python # Fişier: use_logging.py import os, platform, logging if platform.platform().startswith('Windows'): logging_file = os.path.join(os.getenv('HOMEDRIVE'), os.getenv('HOMEPATH'), 'test.log') else: logging_file = os.path.join(os.getenv('HOME'), 'test.log') logging.basicConfig( level=logging.DEBUG, format='%(asctime)s : %(levelname)s : %(message)s', filename = logging_file, filemode = 'w', ) logging.debug("Începutul programului") logging.info("O prelucrare importantă") logging.warning("Încheiere")

Rezultat:  $python use_logging.py Logging to C:\Users\swaroop\test.log

Dacă verificăm conţinutul fişierului test.log, vom găsi cam aşa:  2009-02-09 13:18:16,233 : DEBUG : Începutul programului 2009-02-09 13:18:16,233 : INFO : O prelucrare importantă 2009-02-09 13:18:16,233 : WARNING : Încheiere

Cum funcţionează:  Folosim trei module din biblioteza standard ­ modulul os pentru interacţiunea cu sistemul de  operare, modulul platform pentru informaţii despre platformă adică sistemul de operare şi  modulul logging pentru a jurnaliza informaţii. 

88

La început verificăm ce versiune de sistem de operare folosim prin analiza şirului întors de funcţia  platform.platform() (pentru informaţii suplimentare a se vedea import platform; help(platform)). Dacă este Windows, determinăm drive­ul pe care se află directoarele  utilizatorului, directorul în care se găsesc acestea şi numele fişierului în care vom stoca informaţia.  Combinând aceste trei părţi putem stabili calea întreagă a fişierului. Pentru alte platforme ne trebuie  doar directorul utilizatorului şi avem calea completă a fişierului.  Folosim funcţia os.path.join() pentru a reuni aceste trei părţi ale căii. Motivul pentru care  folosim o funcţie specială în loc de simpla concatenare este garanţia că rezultatul va fi conform  aşteptărilor sistemului de operare.  Configurăm modulul logging să scrie toate mesajele întrun format anume, în fişierul specificat.  În final, putem stoca mesaje pentru debugging, urmărire, avertizare sau chiar mesaje critice. Odată  ce programul a fost lansat, putem vedea ce s­a întâmplat în program, chiar dacă nu a fost afişat  nimic pe ecran utilizatorului care a lansat programul. 

Modulele urllib şi json  Cât de distractiv ar fi dacă aţi putea scrie programe care să dea rezultatul unor căutări pe Internet?  Ia să vedem.  Putem face asta folosind câteva module. Întâi modulul urllib pe care îl folosim ca să aducă o  pagină de pe Internet. Vom folosi motorul de căutare Yahoo! pentru a obţine rezultatele căutării şi  din fericire el ne va da rezultatele căutării în format JSON ceea ce e uşor de procesat pentru noi  datorită modulului json din biblioteca standard.  TODO  Acest program nu funcţionează încă ceea ce pare a fi o eroare (engl. bug) în Python 3.0 beta 2.  #!/usr/bin/python # Fişier: yahoo_search.py import sys if sys.version_info[0] != 3: sys.exit('Acest program necesită Python 3.0 sau ulterior') import json import urllib, urllib.parse, urllib.request, urllib.response # Vă puteţi lua APP ID la http://developer.yahoo.com/wsregapp/ YAHOO_APP_ID = 'jl22psvV34HELWhdfUJbfDQzlJ2B57KFS_qs4I8D0Wz5U5_yCI1Awv8.lBSfPhwr' SEARCH_BASE = 'http://search.yahooapis.com/WebSearchService/V1/webSearch' class YahooSearchError(Excepţie): pass # Luat de la http://developer.yahoo.com/python/python-json.html def search(interogare, rezultate=20, start=1, **kwargs): kwargs.update({ 'appid': YAHOO_APP_ID, 'query': interogare, 'results': rezultate, 'start': start, 'output': 'json'

89

}) url = SEARCH_BASE + '?' + urllib.parse.urlencode(kwargs) result = json.load(urllib.request.urlopen(url)) if 'Error' in result: raise YahooSearchError(result['Error']) return result['ResultSet'] query = input('Ce doriţi să căutaţi? ') for result in search(query)['Rezultat']: print("{0} : {1}".format(result['Titlu'], result['Url']))

Rezultat:  TODO  Cum funcţionează:  Putem obţine rezultatul căutării de la un anumit website dând şirul după care căutăm, întrun anumit  format. Trebuie să specificăm mai multe opţiuni pe care le combinăm folosind formatul  cheie1=valoare1&cheie2=valoare2 care este procesat de funcţia  urllib.parse.urlencode().  De exemplu, deschideţi acest link în browserul web (Internet Explorer sau similar) şi veţi vedea 20  de rezultate, începând cu primul, după cuvintele "byte of python", şi cu rezultatul în format JSON.  Facem o conexiune la acest URL folosind funcţia urllib.request.urlopen() şi transmitem  acea referinţă funcţiei json.load() care va citi conţinutul paginii şi va converti fiecare rezultat  întrun obiect Python. Apoi ciclăm prin aceste obiecte şi le afişăm utilizatorului. 

Seria Modulul săptămânii  Sunt multe de explorat în biblioteca standard cum ar fi depanarea, gestiunea opţiunilor liniei de  comandă, expresiile regulare s.a.m.d.  Cea mai bună cale de a continua explorarea bibliotecii standard este citirea excelentei serii Modulul  Python al săptămânii a lui Doug Hellmann. 

Rezumat  Am explorat o parte din funcţionalitatea multor module din biblioteca Python standard. Este  recomandat să parcurgeţi documentaţia bibliotecii Python standard pentru a vă face o idee asupra  modulelor disponibile.  În continuare vom acoperi diverse aspecte care pot face Python mai complet. 

90

Python ro:Plus Introducere  Am acoperit până acum majoritatea aspectelor din Python pe care le veţi utiliza. În acest capitol  vom mai acoperi câteva aspecte care vor 'rotunji' cunoştinţele voastre despre Python. 

Transmiterea tuplurilor  V­aţi dorit vreodată să returnaţi mai multe răspunsuri dintro funcţie? Puteţi. Nu trebuie decât să  folosiţi un tuplu.  >>> def get_error_details(): ... return (2, 'detalii eroarea 2') ... >>> errnum, errstr = get_error_details() >>> errnum 2 >>> errstr 'detalii eroarea 2'

Observaţi folosirea formulei a, b =  care interpretează rezultatul unei expresii  ca fiind un tuplu cu două valori.  Dacă vreţi să interpretaţi rezultatul ca (a, ), trebuie să folosiţi asteriscul, ca  la parametrii funcţiilor:  >>> >>> 1 >>> [2,

a, *b = [1, 2, 3, 4] a b 3, 4]

Asta înseamnă că cea mai rapida cale de a interschimba două variabile în Python este:  >>> >>> >>> (8,

a = 5; b = 8 a, b = b, a a, b 5)

Metode speciale  Există anumite metode, precum __init__ şi __del__ care au semnificaţie specială în clase.  Metodele speciale sunt folosite pentru a imita anumite comportamente ale tipurilor predefinite. De  exemplu, dacă vreţi să folosiţi operaţia de indexare x[cheie] pentru o clasă (aşa cum aţi folosi­o  pentru liste sau tupluri), atunci nu trebuie decât să implementaţi metoda __getitem__() şi  treaba este făcută. Dacă vă gândiţi, asta face Python pentru însăşi clasa list!  Câteva metode speciale folositoare sunt listate în tabelul următor. Dacă vreţi să studiaţi toate  91

metodele speciale consultaţi manualul.  Metode Speciale  Nume 

Explicaţie 

__init__(self, ...) 

Metoda este apelată imediat înainte de returnarea obiectului nou creat. 

__del__(self) 

Apelată chiar înainte de distrugerea obiectului 

__str__(self) 

Apelată premergător executării funcţiei print sau str(). 

__lt__(self, altceva) 

Apelată când se foloseşte operatorul mai mic decât (, etc.) 

__getitem__(self,  cheie) 

Apelată când se foloseşte operaţia de indexare x[cheie]. 

__len__(self) 

Apelată când se foloseşte funcţia predefinită len() pentru un obiect  secvenţă. 

Blocuri cu o singură declaraţie  Am văzut că fiecare bloc de declaraţii este separat de celelalte blocuri prin nivelul de indentare. Ei  bine, acesta este un punct riscant. Dacă blocul de declaraţii conţine o singură declaratie, atunci o  puteţi specifica pe aceeaşi linie cu declaraţia condiţională sau declaraţia de ciclare. Exemplul  următor va ajuta la clarificarea problemei:  >>> indicator = True >>> if indicator: print 'Da' ... Da

Observaţi că declaraţia unică este folosită pe loc nu întrun bloc separat. Cu toate că puteţi folosi asta  pentru a obţine programe mai mici, Eu vă recomand cu tărie să nu folosiţi această scurtătura, cu  excepţia cazului când verificaţi erorile, în special pentru că va fi mult mai uşor să adaugi o  declaraţie în plus dacă foloseşti indentarea. 

Formule lambda  O declaraţie lambda se foloseşte pentru a crea obiecte­funcţie în runtime.  #!/usr/bin/python # Fişier: lambda.py def repetor(n):

92

return lambda s: s * n dublu = repetor(2) print(dublu('cuvânt')) print(dublu(5))

Rezultat:  $ python lambda.py cuvântcuvânt 10

Cum funcţionează:  Folosim o formulă lambda numită repetor pentru a crea funcţii obiect în runtime şi a le returna  în program. În esenţă, formula lambda primeşte un parametru urmat de o expresie unică ce devine  corpul funcţiei obiect şi valoarea acestei funcţii este returnată de noua funcţie. Reţineţi că întro  formulă lambda nu poate fi utilizată nici măcar o declaraţie print, ci numai expresii.  TODO  Putem executa o funcţie list.sort() furnizănd o funcţie de comparare generată cu o  declaraţie lambda?  puncte = [ { 'x' : 2, 'y' : 3 }, { 'x' : 4, 'y' : 1 } ] # puncte.sort(lambda a, b : cmp(a['x'], b['x']))

Includeri de liste  Includerile de liste sunt folosite pentru a deriva o listă nouă dintro listă existentă. Să zicem că avem  o listă de numere şi vrem să obţinem o listă a numerelor înmulţite cu 2 dar numai dacă numărul este  mai mare decât 2. Includerile de liste sunt ideale pentru aşa ceva.  #!/usr/bin/python # Fişier: list_comprehension.py lista1 = [2, 3, 4] lista2 = [2*i for i in lista1 if i > 2] print(lista2)

Rezultat:  $ python list_comprehension.py [6, 8]

Cum funcţionează:  În acest exemplu derivăm noua listă specificând procesarea necesară (2*i) când condiţia este  satisfăcută (if i > 2). Observaţi că originalul rămâne neschimbat.  Avantajul folosirii includerilor de liste este că reduce volumul de declaraţii necesare la ciclarea prin  elementele listei şi stocarea în altă listă a rezultatelor. 

93

Primirea tuplurilor şi listelor în funcţii  Există o cale specială de a primi parametri întro funcţie sub formă de tuplu sau dicţionar folosind  prefixul *, respectiv **. Aceasta este utilă atunci când se primeşte un număr variabil de argumente  în funcţie.  >>> def sumadeputeri(putere, *argumente): ... ''' Intoarce suma argumentelor ridicate la o putere dată.''' ... total = 0 ... for i in argumente: ... total += pow(i, putere) ... return total ... >>> sumadeputeri(2, 3, 4) 25 >>> sumadeputeri(2, 10) 100

Deoarece avem prefixul * la variabila argumente, toate argumentele transmise funcţiei sunt  stocate în argumente ca tuplu. Dacă am fi folosit prefixul **, parametrii suplimentari ar fi fost  consideraţi perechi cheie/valoare întrun dicţionar. 

Funcţiile exec şi eval  Funcţia exec se foloseşte pentru a executa declaraţii Python stocate întrun şir sau fişier, nu în  programul însuşi. De exemplu putem genera în runtime un şir conţinând cod Python şi să îl  executăm folosind declaraţia exec:  >>> exec('print("Hello World")') Hello World

Similar, funcţia eval este folosită ca să evalueze expresii Python valide stocate întrun şir. Iată un  exemplu simplu.  >>> eval('2*3') 6

Declaraţia assert  Declaraţia assert este folosită pentru a afirma ceva. De exemplu dacă sunteţi foarte siguri că aveţi  cel puţin un element în lista pe care o folosiţi şi vreţi să verificaţi asta prin ridicarea unei erori dacă  nu e aşa declaraţia assert este ideală în aceasta situaţie. Dacă declaraţia assert dă False, este  ridicată o excepţie AssertionError.  >>> list= ['item'] >>> assert len(lista) >= 1 >>> lista.pop() 'item' >>> lista [] >>> assert len(lista) >= 1 Traceback (most recent call last): File "", line 1, in

94

AssertionError

Declaraţia assert trebuie folosită judicios. De cele mai multe ori este mai bine să prinzi excepţii  fie că tratezi problema fie că afişezi un mesaj de eroare şi închizi programul. 

Funcţia repr  Funcţia repr se foloseşte pentru a obţine o reprezentare canonică a obiectului sub formă de şir.  Partea interesantă este că veţi avea eval(repr(obiect)) == obiect aproape tot timpul.  >>> i = [] >>> i.append('item') >>> repr(i) "['item']" >>> eval(repr(i)) ['item'] >>> eval(repr(i)) == i True

În esenţă, funcţia repr se foloseşte pentru a obţine o reprezentare tipăribilă a obiectului. Puteţi  controla ce returnează o clasă pe care o scrieţi la executarea funcţiei repr definind metoda  __repr__ în acea clasă. 

Rezumat  Am mai acoperit câteva facilităţi ale limbajului Python în acest capitol dar încă nu le­am acoperit pe  toate. Totuşi, la acest nivel am acoperit mare parte din ceea ce veţi folosi vreodată în practică. Asta  este suficient pentru pornire în orice program doriţi să creaţi.  Mai departe vom discuta cum să continuăm explorarea limbajului Python. 

95

Python ro:Ce urmează Dacă aţi citit această carte cu atenţie până acum şi aţi exersat o mulţime de programe, v­aţi  familiarizat deja cu Python. Probabil aţi scris câteva programe ca să încercaţi diverse idei şi să vă  exersaţi aptitudinile. Dacă nu aţi făcut aşa, ar trebui. Întrebarea este 'Ce urmează?'  V­aş sugera să abordaţi această problemă:  Creaţi­vă propria carte de adrese cu interfaţă la linia de comandă, pe care o puteţi  răsfoi, puteţi adăuga, şterge, modifica contacte precum prieteni, familie colegi etc. şi  informaţiile lor precum adresa de e­mail şi numărul de telefon. Detaliile trebuie stocate  pentru o accesare în viitor.  Asta este destul de uşor dacă vă gândiţi la ea prin prisma diverselor elemente studiate până acum.  Dacă încă mai vreţi indicaţii cum să porniţi, iată un pont.  Pont (nu citiţi)  Creaţi o clasă pentru a reprezenta o persoană cu informaţiile ei. Folosiţi un dictionar pentru a  stoca obiectele persoană cu cheie numele lor. Folosiţi modulul pickle pentru a stoca obiectele  în mod persistent pe harddisc. Folosiţi metodele predefinite ale dicţionarelor pentru a adăuga,  şterge şi modifica persoanele.  Odată ce puteţi face asta, puteţi spune că sunteţi programator Python. În acel moment trimiteţi­mi  un e­mail de mulţumire pentru minunata carte ;­) . Acest pas este opţional, dar recomandat. De  asemenea, vă rog să luaţi în calcul o donaţie, participarea cu îmbunătăţiri sau voluntariatul la  traduceri pentru a susţine dezvoltarea continuă acestei cărţi.  Dacă programul vi s­a părut uşor, iată altul:  Implementaţi comanda replace. Această comandă va înlocui un şir cu altul întro listă de  fişiere dată.  Comanda replace poate fi atât de simplă sau de sofisticată cum vreţi, de la o simplă formulă de  substituţie de şiruri până la căutarea de scheme (expresii regulare).  După asta, mai există câteva căi de a vă continua călătoria în Python: 

Coduri exemplificative  Cea mai bună cale de a învăţa un limbaj de programare este de a citi şi scrie mult cod:  • • • •

 Proiectul PLEAC    Depozitul de cod Rosetta    exemple Python la java2s    Cartea de bucate Python  este o colecţie foarte valoroasă de reţete şi ponturi pentru a rezolva  anumite tipuri de probleme folosind Python. Astea trebuie citite neapărat de fiecare utilizator  Python. 

96

Întrebări şi răspunsuri  • • • • •

 DA­uri şi NU­uri oficiale Python    FAQ oficial Python    Lista lui Norvig de întrebări rare (engl. Infrequently Asked Questions)    Interviu cu întrebări şi răspunsuri Python    întrebări cu tag 'Python' pe StackOverflow  

Ponturi si smecherii  (engl. tips and tricks)  •  Python Tips & Tricks   •  Advanced Software Carpentry using Python  (rom. Tamplarie software avansata folosind  Python)  •  Charming Python  este o serie excelenta de articole in legatura cu Python de David Mertz. 

Carti, documentatii, tutoriale, filmulete  Urmatorul pas logic dupa cartea aceasta este sa cititi minunata carte a lui Mark Pilgrim Dive Into  Python (rom Aprofundare in Python) pe care o puteti citi si online. Cartea Dive Into Python  exploreaza subiecte ca expresii regulare, procesare de XML, servicii web, testari de unitati, etc. in  detaliu.  Alte resurse folositoare sunt:  • • • • • •

 filmulete ShowMeDo pentru Python    filmulete GoogleTechTalks despre Python    Lista de tutoriale Python a lui Awaretek    Zona Python Effbot's    Link­uri la sfarsitul fiecarul mesaj Python­URL!    Documentatii Python  

Discuţie  Dacă vă încurcă o problemă Python şi nu ştiţi pe cine să întrebaţi, grupul de discuţii  comp.lang.python este cel mai bun loc de a pune întrebarea.  Asiguraţi­vă că v­aţi făcut tema încercând întâi să o rezolvaţi singuri. 

Noutăţi  Dacă vreţi să învăţaţi cele apărute mai nou în lumea Python atunci mergeţi la Planeta oficială  Python şi/sau Planeta neoficială Python. 

Instalarea bibliotecilor  Există un număr uriaş de biblioteci open source pe care le puteţi folosi în programe la Indexul  97

pachetelor Python.  Pentru a le instala şi utiliza puteţi să folosiţi excelentul utilitar EasyInstall. 

Software grafic  Să zicem că vreţi sa creaţi propriul program cu interfaţă grafică (GUI) folosind Python. Asta se  poate face folosind o biblioteca GUI (engl. Graphical User Interface) cu conexiunile ei Python.  Legăturile sunt ceea ce ne permite să scriem programe în Python şi să folosim biblioteci scrise în C  sau C++, dar şi în alte limbaje.  Exista o mulţime de opţiuni de GUI care folosesc Python:  PyQt  Aceasta este o conexiune Python pentru kitul de utilitare Qt care este fundaţia pe care este  construit KDE. Qt este extrem de uşor de folosit şi foarte puternic, în special datorită mediului  Qt Designer şi uimitoarei documentaţii Qt. PyQt este free dacă vreţi să creaţi software open  source (licenta GPL) respectiv trebuie să­l cumparaţi dacă vreţi să creaţi soft cu sursele  protejate (închise). Începând cu Qt 4.5 îl puteţi folosi şi pentru a crea soft non GPL. Pentru a  începe citiţi tutorialul PyQt sau cartea PyQt.  PyGTK  Aceasta este conexiunea Python pentru kitul de utilitare GTK+ care este baza pe care este  construit GNOME. GTK+ are multe complicaţii în utilizare, dar îndata ce te familiarizezi cu  el, poţi crea aplicaţii GUI rapid. Mediul Glade de proiectare a interfelelor grafice este  indispensabil. Documentaţia mai trebuie îmbunătăţită. GTK+ lucrează bine pe Linux, iar  portarea sa pe Windows este incompletă. Puteţi crea cu GTK+ atât soft open source şi soft  non­GPL. Pentru a începe citiţi tutorialul PyGTK.  wxPython  Acesta este conexiunea Python pentru kitul de utilitare wxWidgets. wxPython are asociată o  curba de învăţare. Totuşi este foarte portabil şi ruleaza pe Linux, Windows, Mac şi chiar pe  platforme implantate (engl. embedded). Există multe IDE­uri disponibile pentru wxPython  care includ medii de proiectare GUI precum SPE (Stani's Python Editor) şi constructorul de  GUI wxGlade. Puteţi crea cu wxPython atât soft open source şi soft non­GPL. Pentru a începe  citiţi tutorialul wxPython.  TkInter  Acesta este unul din cele mai vechi kituri de utilitare GUI. Dacă aţi folosit IDLE, aţi văzut  programul TkInter la lucru. Nu are cel mai bun aspect şi atmosferă ci unul de şcoala veche.  TkInter este portabil şi merge atât pe Linux/Unix cât şi pe Windows. Important, TkInter este  parte a distribuţiei standard Python. Pentru a începe citiţi tutorialul Tkinter.  Pentru mai multe opţiuni răsfoiţi pagina wiki GuiProgramming de pe websitul oficial Python]. 

Rezumatul utilitarelor GUI  Din nefericire nu existp un utilitar GUI standard pentru Python. Eu vp propun sp vp alegeşi una din  uneltele de mai sus, în funcţie de situaţie. Primul factor este dacă doriţi să plătiţi pentru vreuna din  uneltele GUI. Al doilea factor dacă vreţi să meargă programul numai pe Windows, numai pe Mac  98

sau Linux sau pe toate. Al treilea factor, dacă a fost aleasă platforma Linux este dacă sunteţi  utilizator KDE sau GNOME sub Linux.  Pentru o analiză comparativă mai detaliată citiţi pagina 26 din Publicaţia Python, Volumul 3,  Numarul 1. 

Diverse implementări  De obicei există două părţi ale unui limbaj de programare ­ limbajul şi programele. Un limbaj este  cum să scriem ceva. Programul este ceea ce se foloseşte pentru a rula programele.  Pentru a rula programele noastre am folosit software­ul (pe scurt softul) CPython. I se spune  CPython pentru că este scris în limbajul C şi este interpretorul Python clasic.  Mai există şi alte softuri care pot rula programe Python:  Jython  O implementare Python care rulează pe platforma Java. Asta înseamnă că puteţi folosi  bibliotecile Java şi clase din Python şi reciproc.  IronPython  O implementare Python care merge pe platforma .NET. Asta înseamnă că puteţi folosi  bibliotecile .NET şi clase din Python şi reciproc.  PyPy  O implementare Python scrisă în Python! Acesta este un proiect de cercetare având ca  obiectiv scrierea unui interpretor care să fie uşor de îmbunătăţit întrucât interpretorul însuşi  este scris întrun limbaj cu tipuri dinamice (spre deosebire de limbajele cu tipuri statice,  precum C, Java sau C# în aceste trei implementări)  Stackless Python  O implementare Python specializată pentru performanţă orientată pe fir de execuţie.  Mai există şi altele, precum CLPython ­ O implementare Python scrisă în Common Lisp şi  IronMonkey care este o portare a IronPython pentru a merge susţinută de un interpretor JavaScript  ceea ce ar putea însemna că pot fi scrise programe de web­browser ("Ajax") în Python (în loc de  Javascript).  Fiecare din aceste implementări are domeniul ei în care este utilă, datorită specializării. 

Rezumat  Am ajuns la sfârşitul acestei cărţi, dar cum se spune este începutul sfârşitului!. Acum sunteţi un  utilizator avid de Python şi fără îndoială sunteti gata să rezolvaţi multe probleme folosind Python.  Puteti să începeţi să automatizaţi calculatorul să facă tot felul de lucruri, de neimaginat până acum  sau puteţi scrie propriile jocuri şi multe altele. Deci să începem! 

99

Python ro:Apendix FLOSS Free/Libre and Open Source Software (FLOSS)  FLOSS este bazat pe conceptul de comunitate care este el însuşi bazat pe conceptul de partajare, în  particular pe partajarea cunoştinţelor. FLOSS sunt libere pentru utilizare, modificare şi redistribuire.  Dacă aţi citit deja cartea aceasta, sunteţi deja familiar cu FLOSS întrucât aţi folosit Python tot  timpul, iar Python este software 'open source'!  Iată câteva exemple de FLOSS pentru a da o idee despre genul de lucruri pe care le poate crea o  comunitate care construieşte în comun:  • Linux. Acesta este un sistem de operare FLOSS Pe care încet, încet îl îmbrăţişează toată  lumea! El a fost iniţiat de Linus Torvalds pe când era student. Acum este un concurent serios  pentru Microsoft Windows. [ Nucleul Linux ]  • Ubuntu. Aceasta este o distribuţie menţinută de o comunitate, sponsorizată de firma  Canonical şi este cea mai populară distribuţie în zilele noastre. Ea vă permite să instalaţi o  mulţime de FLOSS disponibile şi toate întro maniera uşor de instalat şi folosit. Mai mult  decât atât, puteţi restarta calculatorul şi rula Linux de pe un CD! Acest lucru vă permite să  încercaţi toate facilităţile noului sistem de operare înainte de a­l instala în calculator.  [ Ubuntu Linux ]  • OpenOffice.org. Aceasta este o suită de aplicaţii de birou cu editor de text, prezentări, foi de  calcul şi componente de desenare printre altele. Poate deschide şi edita chiar şi fişiere MS  Word şi MS PowerPoint cu usurinţă. Rulează pe mai toate platformele. [ OpenOffice ]  • Mozilla Firefox. Acesta este browserul web al noii generaţii care oferă o adevarată  competiţie lui Internet Explorer. Este rapid ca fulgerul şi a primit felicitări importante pentru  facilităţile sale sensibile şi impresionante. Conceptul de extensie permite folosirea oricărui  fel de plug­in (rom. implant).  • Produsul său partener Thunderbird (rom. pasărea fulger) este un excelent client de e­mail  care citeşte e­mailul cât ai clipi. [ Mozilla Firefox, Mozilla Thunderbird ]  • Mono. Acesta este un soft open source care implementează platforma .NET creată de  Microsoft. El permite aplicaţiilor .NET să fie create şi să ruleze pe Linux, Windows,  FreeBSD, Mac OS şi pe multe alte platforme. [ Mono, ECMA, Microsoft .NET ]  • Serverul web Apache. Acesta este binecunoscutul server web open source. De fapt, este cel  mai popular server web de pe planetă! El rulează mai mult de jumătate din websiturile  existente. Da, aşa e ­ Apache susţine mai multe websituri decât toată competiţia la un loc  (inclusiv Microsoft IIS). [ Apache ]  • MySQL. Acesta este un server de baze de date open source. Este faimos pentru viteza sa  fulgerătoare. Este M din faimoasa suită LAMP care rulează majoritatea websiteurilor de pe  Internet. [ MySQL ]  • VLC Player. Acesta este un player video care poate reda orice de la DivX la MP3 la Ogg la  VCD­uri şi DVD­uri şi ... cine zice că open source nu e mişto? ;­) [ VLC media player ]  • GeexBox este o distributie Linux proiectată să redea filme de îndată ce butezi de pe un CD!  [ GeexBox ]  100

Această listă vrea doar să vă faceţi o idee ­ există multe FLOSS excelente, precum limbajul Perl,  limbajul PHP, sistemul Drupal de management al conţinutului websiturilor, serverul de baze de date  PostgreSQL, jocul de curse TORCS, KDevelop IDE, playerul de filme Xine, editorul VIM, Editorul  Quanta+, playerul audio Banshee, programul de editare de imagini GIMP, ... Lista ar putea ţine la  nesfârşit.  Pentru a prinde cele mai recente subiecte din lumea FLOSS, accesaţi următoarele websituri:  • • • •

 linux.com    LinuxToday    NewsForge    DistroWatch  

Vizitaţi următoarele websituri pentru informaţii despre FLOSS:  •  SourceForge   •  FreshMeat   Aşadar, înainte în explorarea imensei lumi libere (engl. free) şi deschise (engl. open) FLOSS! 

101

Python ro:Apendix Despre... Apreciere finală  Aproape tot softul folosit la crearea acestei cărţi este free şi open source. 

Naşterea acestei cărţi  În primul draft al ei am folosit Linux Red Hat 9.0 ca bază a mediului meu de lucru şi începând cu al  şaselea draft Linux Fedora Core 3.  Iniţial foloseam KWord pentru a scrie cartea (cum am explicat în lecţia de istorie din prefaţă). 

Anii adolescenţei  Mai târziu am trecut pe DocBook XML folosind Kate, dar l­am considerat greoi. Aşa că am trecut  la OpenOffice care avea un control excelent al formatării şi al generării de PDF, dar producea  documente HTML cam ţopăite.  În final am descoperit XEmacs şi am rescris cartea de la 0 în DocBook XML (din nou) după ce am  decis că aceasta este soluţia de termen lung.  În al şaselea draft m­am hotărât să folosesc Quanta+ pentru toata editarea. Foloseam foile de stiluri  XSL care au venit cu Fedora Core 3 şi fonturile implicite standard. Totuşi, am scris un document  CSS pentru a da culoare şi stil paginilor HTML. Am scris şi un analizor lexical brut, în Python  desigur, care aducea evidenţierea automată a sintaxei în toate listingurile. 

Acum  Pentru acest al şaptelea draft, folosesc MediaWiki ca bază a aranjamentului. Acum editez totul  online şi cititorii pot citi/edita/comenta direct în situl wiki.  Încă folosesc Vim pentru editare datorită extensiei ViewSourceWith pentru Firefox care se  integrează cu Vim. 

Despre autor  http://www.swaroopch.com/about/ 

102

Python ro:Apendix Istoricul reviziilor • 1.90  • • • • • 1.20  • • • 1.15  • • • 1.12  • • • 1.10  • • • 1.00  • •

04/09/2008 şi încă evoluează  Revenire după un salt peste 3.5 ani!   Updatarea la Python 3.0   Rescriere folosind MediaWiki (din nou)  13/01/2005  Rescriere completă folosind Quanta+ pe platforma FC3 cu o mulţime de corecturi şi  actualizări. Multe exemple noi. Rescris aranjamentul DocBook de la 0.  28/03/2004  Revizii minore  16/03/2004  Adăugiri şi corecturi.  09/03/2004  Alte corecturi dactilo datorate multor cititori utili şi entuziaşti.  08/03/2004  Dupa enorm de mult feedback şi sugestii de la cititori am facut multe modificări la  conţinut şi corecturi dactilo. 

• 0.99  • 22/02/2004  • Adaugăt un capitol nou, despre module. Adăugat detalii despre numărul variabil de  argumente în funcţii.  • 0.98  • 16/02/2004  • Scris script Python şi foaie de stiluri CSS pentru a îmbunătăţi rezultatul XHTML,  inclusiv un analizor lexical brut, dar funcţional pentru evidenţierea sintaxei în stil  Vim în listingurile de programe.  • 0.97  • 13/02/2004  • Alt draft complet rescris, din nou in XML DocBook. Cartea a fost îmbunătăţită  masiv ­ este mai coerentă şi lizibilă.  • 0.93  • 25/01/2004  • Adăugat discuţia despre IDLE şi altele specifice Windows  • 0.92  • 05/01/2004  103













• 0.91  • • 0.90  • • 0.60  • • 0.20  • • 0.15  • • 0.10  • •

Schimbări la unele exemple.  30/12/2003  Corectat dactilo. Improvizat mai multe subiecte.  18/12/2003  Adaugăt încă 2 capitole. Format OpenOffice cu revizii.  21/11/2003  Rescris şi expandat cartea.  20/11/2003  Corectat cateva erori minore şi dactilo.  20/11/2003  Conversie în XML DocBook.  14/11/2003  Draft iniţial editat cu KWord. 

104

View more...

Comments

Copyright ©2017 KUPDF Inc.
SUPPORT KUPDF