3. O introducere informală în Python
************************************

În exemplele următoare, intrările și ieșirile se deosebesc prin
prezența, respectiv prin absența prompturilor (*>>>* și *...*): ca să
probați un exemplu, va trebui să tastați tot ce urmează după promptul
lui, atunci când vă apare promptul; liniile care nu încep cu un prompt
fac parte din ieșirea interpretorului. Țineți seama de faptul că
prezența promptului secundar de unul singur pe o linie dintr-un
exemplu înseamnă că trebuie să introduceți o linie goală; prin aceasta
se încheie o comandă de mai multe linii.

Multe din exemplele acestui manual, inclusiv cele introduse la
promptul interactiv, includ comentarii. Comentariile încep în Python
cu caracterul haștag, "#", și țin până la finalul liniei fizice. Un
comentariu poate apărea la început de linie, în continuarea unui
spațiu gol sau a codului, dar nu în interiorul unui șir de caractere.
Un caracter haștag aflat în interiorul unui șir de caractere este un
simplu caracter haștag. Deoarece comentariile sunt destinate
clarificării codului și nu sunt interpretate de Python, le puteți
omite atunci când veți tasta exemplele.

Câteva exemple

   # this is the first comment
   spam = 1  # and this is the second comment
             # ... and now a third!
   text = "# This is not a comment because it's inside quotes."


3.1. Folosind Python-ul pe post de calculator
=============================================

Haideți să încercăm niște comenzi simple în Python. Porniți
interpretorul și așteptați să apară promptul principal, ">>>". (N-ar
trebui să dureze mult.)


3.1.1. Numere
-------------

Interpretorul acționează ca un simplu calculator: dumneavoastră
tastați o expresie în el și el vă afișează valoarea ei. Sintaxa
expresiei este una imediată: operatorii "+", "-", "*" și "/" se
folosesc la aritmetică; parantezele ("()") se utilizează la
subexpresii. De exemplu:

   >>> 2 + 2
   4
   >>> 50 - 5*6
   20
   >>> (50 - 5*6) / 4
   5.0
   >>> 8 / 5  # division always returns a floating point number
   1.6

Numerele întregi (precum "2", "4", "20") sunt de tipul "int", cele cu
parte fracționară (cum ar fi "5.0", "1.6") de tipul "float". Vom
reveni ulterior la tipurile numerice în tutorial.

Împărțirea ("/") întoarce întotdeauna un număr în virgulă mobilă.
Pentru a găsi *partea întreagă la împărțirea cu rest*, cu alte
cuvinte, pentru a obține un rezultat întreg al împărțirii va trebui să
folosiți operatorul "//"; pentru calculul restului, utilizați-l pe
"%":

   >>> 17 / 3  # classic division returns a float
   5.666666666666667
   >>>
   >>> 17 // 3  # floor division discards the fractional part
   5
   >>> 17 % 3  # the % operator returns the remainder of the division
   2
   >>> 5 * 3 + 2  # floored quotient * divisor + remainder
   17

În Python, puteți folosi operatorul "**" pentru a calcula puteri [1]:

   >>> 5 ** 2  # 5 squared
   25
   >>> 2 ** 7  # 2 to the power of 7
   128

Semnul egal ("=") se folosește pentru a atribui o valoare unei
variabile. După aceasta, nu se se va afișa nimic până la apariția
următorului prompt interactiv:

   >>> width = 20
   >>> height = 5 * 9
   >>> width * height
   900

Dacă o variabilă nu este "definită" (nu i s-a atribuit o valoare),
atunci când veți încerca să o folosiți vi se va semnala o eroare:

   >>> n  # try to access an undefined variable
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   NameError: name 'n' is not defined

Folosirea numerelor în virgulă mobilă are suport complet; operatorii
cu operanzi de tipuri diferite vor converti operandul întreg la un
operand în virgulă mobilă corespunzător:

   >>> 4 * 3.75 - 1
   14.0

În modul interactiv, ultima expresie afișată va fi atribuită
variabilei "_". Ceea ce înseamnă că, atunci când folosiți Python-ul
drept calculator de birou, este cumva mai ușor să continuați calculele
lungi, ca de exemplu:

   >>> tax = 12.5 / 100
   >>> price = 100.50
   >>> price * tax
   12.5625
   >>> price + _
   113.0625
   >>> round(_, 2)
   113.06

Această variabilă trebuie considerată ca fiind doar-de-citit de către
utilizator. Nu-i atribuiți în mod explicit nicio valoare --- dacă o
veți face, atunci veți fi definit o variabilă locală, independentă, cu
același nume, care va masca variabila predefinită în limbaj cu tot cu
purtarea ei magică.

În afară de "int" și de "float", Python-ul suportă și alte tipuri de
numere, precum "Decimal" și "Fraction". De asemeni, Python-ul are
suport predefinit pentru numerele complexe și folosește sufixul "j"
sau "J" pentru a desemna partea imaginară (ca în "3+5j").


3.1.2. Text
-----------

Python-ul poate manipula textul (reprezentat de tipul "str", așa-
numitele "șiruri de caractere"; de la englezescul *string*, la
singular) la fel de bine ca numerele. Acesta include caractere precum
""!"", cuvinte cum ar fi ""iepure"", nume ca ""Paris"", propoziții de
felul lui ""Te ajut eu."", șamd. ""Uraa! :)"". Toate acestea pot fi
încadrate fie de ghilimele simple ("'...'") fie de ghilimele duble
(""...""), cu același rezultat [2]. Exemplul care urmează folosește
*referințe intraductibile* la scheciurile Monty Python. Astfel, apar
expresiile spam eggs și Paris rabbit got your back.

>>> 'spam eggs'  # single quotes
'spam eggs'
>>> "Paris rabbit got your back :)! Yay!"  # double quotes
'Paris rabbit got your back :)! Yay!'
>>> '1975'  # digits and numerals enclosed in quotes are also strings
'1975'

Ca să citați ghilimelele (simple sau duble), trebuie să le "salvați"
(de la englezescul *escape*; vom utiliza constructele: caracter
escape, secvență escape, a escapa și derivate ale lor, întâlnite în
literatura de specialitate) prefixându-le cu "\". Altfel, puteți
încadra textul respectiv cu celălalt tip de semne de punctuație pentru
citare:

   >>> 'doesn\'t'  # use \' to escape the single quote...
   "doesn't"
   >>> "doesn't"  # ...or use double quotes instead
   "doesn't"
   >>> '"Yes," they said.'
   '"Yes," they said.'
   >>> "\"Yes,\" they said."
   '"Yes," they said.'
   >>> '"Isn\'t," they said.'
   '"Isn\'t," they said.'

În interpretorul de comenzi Python, rezultatul afișării unui șir de
caractere poate să difere mult de definiția șirului de caractere.
Funcția "print()" produce o afișare lizibilă a acestuia, omițând
ghilimele care îl încadrează și tipărind caracterele escape, respectiv
caracterele speciale:

   >>> s = 'First line.\nSecond line.'  # \n means newline
   >>> s  # without print(), special characters are included in the string
   'First line.\nSecond line.'
   >>> print(s)  # with print(), special characters are interpreted, so \n produces new line
   First line.
   Second line.

Dacă nu doriți să fie interpretate drept caractere speciale
caracterele prefațate cu "\", atunci puteți utiliza *șirurile brute*
(de la englezescul *raw*) de caractere adăugând un "r" înaintea
ghilimelelor simple de început:

   >>> print('C:\some\name')  # here \n means newline!
   C:\some
   ame
   >>> print(r'C:\some\name')  # note the r before the quote
   C:\some\name

Există o subtilitate vizavi de șirurile brute de caractere: un șir
brut de caractere nu se poate termina cu un număr impar de caractere
"\"; vedeți rubrica FAQ/IFF (întrebări formulate frecvent) pentru mai
multe informații și tehnici de evitare a dificultăților.

String literals can span multiple lines.  One way is using triple-
quotes: """"..."""" or "'''...'''".  End of lines are automatically
included in the string, but it's possible to prevent this by adding a
"\" at the end of the line.  The following example:

   print("""\
   Usage: thingy [OPTIONS]
        -h                        Display this usage message
        -H hostname               Hostname to connect to
   """)

produces the following output (note that the initial newline is not
included):

   Usage: thingy [OPTIONS]
        -h                        Display this usage message
        -H hostname               Hostname to connect to

Șirurile de caractere pot fi concatenate (lipite unul de celălalt) cu
operatorul "+", respectiv repetate cu operatorul "*":

   >>> # 3 times 'un', followed by 'ium'
   >>> 3 * 'un' + 'ium'
   'unununium'

Două sau mai multe *literale șir-de-caractere* (adică șiruri de
caractere încadrate de semne de citare), odată ce sunt plasate unul
lângă celălalt, vor fi concatenate automat:

   >>> 'Py' 'thon'
   'Python'

Această caracteristică este utilă mai ales atunci când intenționați să
porționați șirurile lungi de caractere:

   >>> text = ('Put several strings within parentheses '
   ...         'to have them joined together.')
   >>> text
   'Put several strings within parentheses to have them joined together.'

Această tehnică funcționează numai cu valori literale, deci nu cu
variabile și nici cu expresii:

   >>> prefix = 'Py'
   >>> prefix 'thon'  # can't concatenate a variable and a string literal
     File "<stdin>", line 1
       prefix 'thon'
              ^^^^^^
   SyntaxError: invalid syntax
   >>> ('un' * 3) 'ium'
     File "<stdin>", line 1
       ('un' * 3) 'ium'
                  ^^^^^
   SyntaxError: invalid syntax

Dacă doriți să concatenați variabile ori o variabilă cu o valoare
literală, atunci folosiți "+"-ul:

   >>> prefix + 'thon'
   'Python'

Șirurile de caractere pot fi *indexate* (numerotate), primul caracter
din șir având indicele 0. Nu există tipul caracter de sine stătător;
un caracter este doar un șir de caractere cu lungimea 1:

   >>> word = 'Python'
   >>> word[0]  # character in position 0
   'P'
   >>> word[5]  # character in position 5
   'n'

Indici pot fi și numerele negative, dacă dorim să începem numărătoarea
de la dreapta:

   >>> word[-1]  # last character
   'n'
   >>> word[-2]  # second-last character
   'o'
   >>> word[-6]
   'P'

Remarcați că, deoarece -0 este totuna cu 0, indicii negativi încep de
la -1.

In addition to indexing, *slicing* is also supported.  While indexing
is used to obtain individual characters, *slicing* allows you to
obtain substring:

   >>> word[0:2]  # characters from position 0 (included) to 2 (excluded)
   'Py'
   >>> word[2:5]  # characters from position 2 (included) to 5 (excluded)
   'tho'

Indicii unei tranșe au valori implicite utile; un indice de început,
odată ce este omis, va fi implicit zero pe când un indice de final,
omis, va lua în mod implicit ca valoare lungimea șirului de caractere
în curs de tranșare.

   >>> word[:2]   # character from the beginning to position 2 (excluded)
   'Py'
   >>> word[4:]   # characters from position 4 (included) to the end
   'on'
   >>> word[-2:]  # characters from the second-last (included) to the end
   'on'

Remarcați că începutul este întotdeauna inclus, pe când finalul este
întotdeauna lipsă. Această proprietate face ca "s[:i] + s[i:]" să fie
egal întotdeauna cu "s":

   >>> word[:2] + word[2:]
   'Python'
   >>> word[:4] + word[4:]
   'Python'

O metodă de a ține minte cum funcționează tranșatul este să vă
imaginați indicii ca țintind *între* caractere, iar muchia stângă a
primului caracter ca fiind numerotată cu 0. Atunci, muchia dreaptă a
ultimului caracter al unui șir de caractere de *n* caractere va avea
indexul *n*, ca de exemplu:

    +---+---+---+---+---+---+
    | P | y | t | h | o | n |
    +---+---+---+---+---+---+
    0   1   2   3   4   5   6
   -6  -5  -4  -3  -2  -1

Primul rând de numere dă poziția fiecăruia dintre indicii 0...6 ai
șirului de caractere; cel de-al doilea rând pe cea a indicilor
negativi corespunzători. Tranșa de la *i* la *j* constă din toate
caracterele situate între muchiile notate cu *i* și respectiv cu *j*.

Pentru indicii nenegativi, lungimea unei tranșe este diferența
indicilor, aceasta dacă amândoi sunt în limita valorilor permise. De
exemplu, lungimea lui "cuvântul[1:3]" este 2.

Încercarea de a folosi un indice prea mare va conduce la o eroare:

   >>> word[42]  # the word only has 6 characters
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   IndexError: string index out of range

Cu toate acestea, indicii care depășesc plaja valorilor permise vor fi
rezolvați cu eleganță atunci când îi folosim la tranșare:

   >>> word[4:42]
   'on'
   >>> word[42:]
   ''

Șirurile de caractere Python nu pot fi modificate --- ele sunt
*imutabile*. De aceea, atribuirea de valori unei poziții indexate
dintr-un șir de caractere va produce o eroare:

   >>> word[0] = 'J'
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   TypeError: 'str' object does not support item assignment
   >>> word[2:] = 'py'
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   TypeError: 'str' object does not support item assignment

Dacă este nevoie să modificați un șir de caractere, atunci va trebui
să creați un șir de caractere nou:

   >>> 'J' + word[1:]
   'Jython'
   >>> word[:2] + 'py'
   'Pypy'

Funcția predefinită "len()" returnează lungimea unui șir de caractere.
Șirul de caractere supercalifragilistic... este intraductibil:

   >>> s = 'supercalifragilisticexpialidocious'
   >>> len(s)
   34

Vezi și:

  Tipul secvență de text -- str
     Șirurile de caractere sunt exemple ale *tipurilor secvență de
     date* și permit operațiile suportate în mod obișnuit de asemenea
     tipuri.

  Metodele șirurilor de caractere
     Șirurile de caractere suportă un număr mare de metode privind
     transformările uzuale și căutarea.

  f-șiruri
     Valori literale șir-de-caractere care includ expresii.

  Sintaxa șirurilor de format
     Informații despre formatarea șirurilor de caractere cu
     "str.format()".

  Formatarea șirurilor de caractere în vechiul stil printf
     Vechile operații de formatare invocate atunci când șiruri de
     caractere  îi sunt operand stâng operatorului "%" sunt descrise
     în detaliu aici.


3.1.3. Liste
------------

Python-ul înțelege mai multe tipuri de date *compozite*, folosite la
punerea laolaltă de valori diverse. Cel mai versatil dintre tipuri
este *lista*, pe care o putem scrie în formă de șir încadrat de
paranteze drepte și format din valori (itemi) separate între ele prin
virgule. Listele pot conține itemi de tipuri diferite, însă cel mai
adesea toți itemii sunt de același tip.

   >>> squares = [1, 4, 9, 16, 25]
   >>> squares
   [1, 4, 9, 16, 25]

Aidoma șirurilor de caractere (și a tuturor tipurilor *secvență*
predefinite), listele pot fi atât indexate cât și tranșate:

   >>> squares[0]  # indexing returns the item
   1
   >>> squares[-1]
   25
   >>> squares[-3:]  # slicing returns a new list
   [9, 16, 25]

De asemenea, listele suportă operații precum concatenarea:

   >>> squares + [36, 49, 64, 81, 100]
   [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

Spre deosebire de șirurile de caractere, care sunt *imutabile*,
listele sunt un tip *mutabil*, adică este posibil să le modificăm
conținutul:

   >>> cubes = [1, 8, 27, 65, 125]  # something's wrong here
   >>> 4 ** 3  # the cube of 4 is 64, not 65!
   64
   >>> cubes[3] = 64  # replace the wrong value
   >>> cubes
   [1, 8, 27, 64, 125]

You can also add new items at the end of the list, by using the
"list.append()" *method* (we will see more about methods later):

   >>> cubes.append(216)  # add the cube of 6
   >>> cubes.append(7 ** 3)  # and the cube of 7
   >>> cubes
   [1, 8, 27, 64, 125, 216, 343]

În Python, simpla atribuire nu copiază niciodată datele. Atunci când
asignați o listă unei variabile, variabila se va referi la *lista de
față*. Indiferent ce schimbare faceți în listă prin intermediul unei
variabile, schimbarea va fi vizibilă prin intermediul tuturor
celorlalte variabile care se referă la prima variabilă.:

   >>> rgb = ["Red", "Green", "Blue"]
   >>> rgba = rgb
   >>> id(rgb) == id(rgba)  # they reference the same object
   True
   >>> rgba.append("Alph")
   >>> rgb
   ["Red", "Green", "Blue", "Alph"]

Toate operațiile de feliere vor returna o listă nouă conținând
elementele cerute. Ceea ce înseamnă că următoarea tranșare va returna
o copie superficială (de la englezescul *shallow copy*) a listei:

   >>> correct_rgba = rgba[:]
   >>> correct_rgba[-1] = "Alpha"
   >>> correct_rgba
   ["Red", "Green", "Blue", "Alpha"]
   >>> rgba
   ["Red", "Green", "Blue", "Alph"]

Asignarea la tranșe este, de asemenea, posibilă iar aceasta poate
schimba până și mărimea listei ori șterge toate elementele ei:

   >>> letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
   >>> letters
   ['a', 'b', 'c', 'd', 'e', 'f', 'g']
   >>> # replace some values
   >>> letters[2:5] = ['C', 'D', 'E']
   >>> letters
   ['a', 'b', 'C', 'D', 'E', 'f', 'g']
   >>> # now remove them
   >>> letters[2:5] = []
   >>> letters
   ['a', 'b', 'f', 'g']
   >>> # clear the list by replacing all the elements with an empty list
   >>> letters[:] = []
   >>> letters
   []

Funcția predefinită "len()" se aplică și la liste:

   >>> letters = ['a', 'b', 'c', 'd']
   >>> len(letters)
   4

Este posibil să imbricăm liste (de la englezescul *to nest*; adică să
creăm liste care conțin alte liste), ca de exemplu:

   >>> a = ['a', 'b', 'c']
   >>> n = [1, 2, 3]
   >>> x = [a, n]
   >>> x
   [['a', 'b', 'c'], [1, 2, 3]]
   >>> x[0]
   ['a', 'b', 'c']
   >>> x[0][1]
   'b'


3.2. Primii pași în programare
==============================

Evident, putem folosi Python-ul la sarcini mult mai complicate decât
la a-l aduna pe 2 cu 2. De exemplu, putem construi primii termeni ai
șirului lui Fibonacci după cum urmează:

   >>> # Fibonacci series:
   ... # the sum of two elements defines the next
   ... a, b = 0, 1
   >>> while a < 10:
   ...     print(a)
   ...     a, b = b, a+b
   ...
   0
   1
   1
   2
   3
   5
   8

Acest exemplu introduce mai multe caracteristici noi.

* Prima linie conține o *atribuire multiplă*: variabilele "a" și "b"
  primesc simultan noile valori 0 și 1. Atribuirea va fi folosită din
  nou pe ultima linie, ceea ce ne va arăta că toate expresiile din
  partea dreaptă a semnului atribuirii sunt evaluate înainte să se
  facă orice atribuire. Aceste expresii din partea dreaptă a
  atribuirii se evaluează de la stânga la dreapta.

* Execuția ciclului (de la englezescul *loop*; vom folosi și
  constructele: buclă, instrucțiune iterativă, instrucțiune de
  ciclare, întâlnite în literatura de specialitate) "while" se repetă
  atâta vreme cât condiția lui (în cazul nostru: "a < 10") rămâne
  adevărată. În Python, la fel ca în C, orice număr întreg nenul are
  valoarea logică adevărat; zero, în schimb, are valoarea logică fals.
  Condiția buclei poate lua chiar și valoarea unei liste ori a unui
  șir de caractere, în fapt, pe cea a oricărei date de tip secvență;
  orice obiect de lungime nenulă are valoarea logică adevărat, pe când
  secvențele nule au valoarea logică fals. Testul folosit în exemplu
  este o simplă comparație. Operatorii tipici de comparație se notează
  la fel ca în C: "<" (mai mic decât), ">" (mai mare ca), "==" (egal
  cu), "<=" (mai mic sau egal cu), ">=" (mai mare sau egal cu) și "!="
  (neegal cu).

* *Corpul* instrucțiunii iterative are *indentare*: indentarea este
  modul în care Python-ul grupează instrucțiuni (de la englezescul
  *statements*). La promptul interactiv, trebuie să tastați fie un Tab
  fie un spațiu gol pentru fiecare linie cu indentare. În practică,
  veți prepara inputurile mai complicate destinate Python-ului cu
  ajutorul unui editor de text; toate editoarele de text decente
  posedă sisteme de indentare automată. Atunci când o instrucțiune
  compozită este introdusă în mod interactiv, ea trebuie urmată de o
  linie goală pentru a indica faptul că s-a încheiat (dat fiind că
  parserul nu poate ghici când intenționați să tastați utima linie de
  cod). Remarcați că fiecare din liniile unui asemenea bloc de cod
  trebuie să aibă o indentare de aceeași lungime.

* The "print()" function writes the value of the argument(s) it is
  given. It differs from just writing the expression you want to write
  (as we did earlier in the calculator examples) in the way it handles
  multiple arguments, floating point quantities, and strings.  Strings
  are printed without quotes, and a space is inserted between items,
  so you can format things nicely, like this:

     >>> i = 256*256
     >>> print('The value of i is', i)
     The value of i is 65536

  Argumentul cuvânt-cheie *end* poate fi utilizat pentru a evita
  trecerea la o linie nouă după afișare, precum și atunci când dorim
  ca afișarea să se încheie cu un șir de caractere diferit de
  caracterul linie-nouă:

     >>> a, b = 0, 1
     >>> while a < 1000:
     ...     print(a, end=',')
     ...     a, b = b, a+b
     ...
     0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,

-[ Note de subsol ]-

[1] Deoarece "**" este prioritar (de la englezescul *higher
    precedence*) față de "-", "-3**2" va fi interpretată drept
    "-(3**2)" și astfel rezultatul va fi "-9". Pentru a nu se întâmpla
    așa ceva și a obține "9", puteți scrie "(-3)**2".

[2] Spre deosebire de alte limbaje, caracterele speciale precum "\n"
    au aceeași semnificație indiferent dacă sunt scrise cu ghilimele
    simple ("'...'") ori cu ghilimele duble (""...""). Singura
    deosebire între cele două modalități este că atunci când
    întrebuințăm ghilimele simple nu este nevoie să escapăm
    ghilimelele """ (cu toate că trebuie escapate ghilimelele simple
    "\'") și viceversa.
