Intr-un limbaj de programare, expresiile furnizeaza un mijloc facil de a executa diferite operatii cu diverse tipuri de valori, sau variabile, in scopul generarii unor rezultate.

- o expresie contine operanzi and operatori;
- operanzii reprezinta datele cu care se lucreaza
- operatorii reprezinta operatiile efectuate asupra datelor
- intr-o expresie, operatorii combina operanzii in scopul obtinetii unui rezultat.

Limbajul Python ofera suport pentru urmatoarele categorii de operatori:

1. operatori aritmetici arithmetic operators
2. operatori de comparare comparison (relational) operators
3. operatori de atribuire assignment operators
4. operatori logici logical operators
5. operatori logici pe biti bitwise operators
6. operatori de testare a identitatii obiectelor identity operators
7. operatori de testare a apartenentei unui obiect membership operator

# 1. Operatori aritmetici¶

Operatorii aritmetici sunt aplicati unor operatori de tip numeric (`int`, `float`, `complex`), in scopul executarii unor operatii matematice asupra acestora. Utilizarea acestor operatori genereaza expresii aritmetice, deoarece prin evaluarea acestora se returneaza o valoarea de tip numeric.

Operatorii aritmetici definiti in limbajul Python sunt urmatorii:

- `**` = operatorul de exponentiere (sau ridicare la patrat)
- `-` = operatorul unar de negare a valorii numerice
- `*` = operatorul de multiplicare
- `/` = operatorul de divizare aritmetica - returneaza rezultul impartirii operanzilor implicati in expresie
- `//` = operatorul de divizare intreaga (floor division) - returneaza partea intreaga a rezultatului impartirii operanzilor implicati in expresie-
- `%` = operatorul rest - returneaza restul impartirii operanzilor implicati in expresie
- `+` = operatorul de adunare
- `-` = operatorul de scadere

In limbajul Python, operatorii aritmetici utilizati in expresii respecta aceleasi reguli de prioritate (precedence rules), ca cele care sunt valabile in algebra:

- operatorul de exponentiere are prioritate maxima, fiind evaluat primul.
- operatorul unar de negare este evaluat dupa cel de exponentiere, inaintea operatorilor de multiplicare, impartire si rest.
- operatorii de multiplicare, de impartire si de rest, sunt evaluati inaintea celor de adunare si scadere
- operatorii de adunare si de scadere sunt evaluati inaintea celui de atribuire;
- operatorii de exponentiere si de atribuire sunt asociativi de dreapta; instante consecutive ale acestor operatori sunt evaluate de la dreapta spre stanga
- restul operatorilor sunt asociativi la stanga; instante consecutive ale acestor operatori sunt evaluate de la stanga la dreapta
- ordinea in care sunt evaluati operatorii aritmetici poate fi controlata cu ajutorul parantezelor rotunde

In [1]:

    # Exemplul 1: utilizarea operatorilor aritmetici in expresii aritmetice

    # initializarea a 2 variabile prin utilizarea intructiunii de atribuire multipla
    x, y = 10, 3

    #  expresii aritmetice
    x2y      = x**y
    minus_x  = -x
    xMy      = x*y
    xDy      = x / y
    xFDy     = x // y
    xRy      = x % y
    xAy      = x + y
    xSy      = x - y

    # afisare rezultate
    print('x =', x, ' y =', y)
    print()
    print('x**y = ', x2y)
    print('-x = ', minus_x)
    print('x * y  = ', xMy)
    print('x / y = ', xDy)
    print('x // y = ', xFDy)
    print('x % y  = ', xRy)
    print('x + y = ', xAy)
    print('x - y = ', xSy)

    x = 10  y = 3

    x**y =  1000
    -x =  -10
    x * y  =  30
    x / y =  3.3333333333333335
    x // y =  3
    x % y  =  1
    x + y =  13
    x - y =  7

### Expresii aritmetice care utilizeaza tipuri de date mixte¶

Operatorii aritmetici se pot aplica unor operanzi care apartin categoriei de date numerice; daca operanzii utilizati in expresia aritmetica sunt de tipuri numerice diferite (de exemplu `int` si `float`), atunci expresia respectiva este mixta. In evaluarea unor expresii aritmetice mixte, operandul de tip inferior este convertit temporar si automat la operandul de tip superior (in exemplul considerat, operandul `int` este convertit in `float`). Regulile de conversie sunt urmatoarele:

- un operand `int` este convertit automat la un operand de tip `float` sau `complex`, in functie de tipul operandului de tip superior utilizat in expresie
- un operand `float` este convertit automat la un operand de tip `complex`

In [2]:

    # Exemplul 2: utilizarea operatorilor aritmetici in expresii aritmetice mixte
    3.14 * 3 ** 2

Out[2]:

    28.26

Observatie:
In cazul in care un operator aritmetic este aplicat unor operanzi de tip boolean `bool`, in evaluarea expresiei aritmetice operanzii de tip `bool` sunt inlocuiti cu valorile intregi `1` respectiv `0`, care sunt utilizate pentru reprezentarea interna a valorilor booleene in limbajul Python:

- valoarea `True` este reprezentata intern Python prin valoarea intreaga 1
- valoarea `False` este reprezentata intern Python prin valoarea intreaga 0

In [3]:

    # Exemplul 3: utilizarea operatorilor aritmetici in expresii aritmetice mixte cu operanzi booleeni
    print('True + 1 = ',     True  + 1)
    print('False + 1 = ',    False + 1)
    print('True + False = ', True  + False)

    True + 1 =  2
    False + 1 =  1
    True + False =  1

Observatie:
In cazul in care o expresie devine prea lunga, aceasta poate fi continuata pe urmatoarea linie de cod prin inserarea caracterului `\` la finalul liniei de cod curente, imedist dupa ultimul operator utilizat pe linia respectiva.

In [4]:

    # Exemplul 4: scrierea unei expresii pe 3 linii de cod
    3 + 4 * \
    2 ** 5

Out[4]:

    131

# 2. Operatorul de concatenare¶

Atunci cand este aplicat unor operanzi care reprezinta colectii (containere sau string), operatorul `+` nu mai este interpretat ca operator artimetic de adunare, ci este interpretat ca operator de concatenare. Din acest motiv, se spune ca operatorul `+` este polimorf: isi schimba comportamentul in functie de tipul operanzilor.

Operatorul de concatenare combina colectiile utilizate ca operanzi, rezultatul returnat fiind o colectie compusa din toate colectiile utilizate ca operanzi.

Operatorul `+` nu poate fi aplicat pe operanzi a caror tip apartin unor categorii diferite de date; de exemplu, nu se poate aplica intr-o expresie care combina un operand de tip numeric, cu unul de tip string, cum ar fi `1 + 'a'`. In cazul in care nu se respecta aceasta regula, la executia codului se va lansa un mesaj de eroare de tipul `TypeError`.

In [5]:

    # Exemplul 5: aplicarea incorecta a operatorului "+"
    'Robot' +  1

    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    <ipython-input-5-0b7a4c5d1e60> in <module>
          1 # Exemplul 5: aplicarea incorecta a operatorului "+"
    ----> 2 'Robot' +  1

    TypeError: can only concatenate str (not "int") to str

In [6]:

    # Exemplul 6: concatenarea a 2 string-uri
    message = 'Robot' + '1' + ' turn right!'
    print(message)

    Robot1 turn right!

# 3. Operatorul de replicare¶

Atunci cand unul din operanzii implicati intr-o expresie care utlizeaza operatorul `*` reprezinta o colectie, (containere sau string), operatorul `*` nu mai reprezinta operatorul artimetic de multiplicare, ci se transforma in operatorul de replicare. Din acest motiv, se spune ca operatorul `*` este polimorf: isi schimba comportamentul in functie de tipul operanzilor. Operatorul de replicare combina o data de tip intreg cu o data de tip colectie, rezultatul returnat fiind aceaasi colectie, replicata de un numar de ori egal cu intregul folosit in expresie.

In [8]:

    # Exemplul 7: replicarea unui string de N ori
    message = 'Robot turn right!\n' * 10
    print(message)

    Robot turn right!
    Robot turn right!
    Robot turn right!
    Robot turn right!
    Robot turn right!
    Robot turn right!
    Robot turn right!
    Robot turn right!
    Robot turn right!
    Robot turn right!

# 4. Operatorul de atribuire¶

Este utilizat pentru atribuirea unei valori, unei variabile. Acest operator indica linia de cod in care o variabila (un obiect) este creat si totodata stabileste tipul de data atribuit variabilei. Linia de cod in care o variabila este creata este linia in care variabilei in cauza i se atribuie, pentru prima data, o valoare.
Operatorul de atribuire poate fi utilizat in combinatie cu operatorii aritmetici binari (operatorii care lucreaza cu 2 operanzi), pentru scrierea mai compacta a codului sursa, astfel:

- Sintaxa:

      variabila = variabila  operator_aritmetic_binar  operand

  este echivalent cu:

      variabila  coperator_aritmetic_binar=  operand

- exemplu:

      x += 1  # echivalent cu x = x+1

In [9]:

    # Exemplul 8: incrementarea valorii unei variabile cu un pas constant definit de variabila STEP

    angle = 10
    STEP  = 2

    print(f'1: Robot turn right to {angle} degree')
    angle += STEP
    print(f'2: Robot turn right to {angle} degree')

    1: Robot turn right to 10 degree
    2: Robot turn right to 12 degree

# 5. Operatori de comparare (operatori relationali)¶

Operatorii de comparare sunt utilizati pentru compararea valorii operanzilor. Utilizarea acestor operatori genereaza expresii booleene, deoarece prin evaluarea acestora se returneaza o valoarea de tip boolean `bool`, `True` sau `False`.
Operatorii de comparare definiti in limbajul Python sunt urmatorii:

- `==` : operatorul de egalitate; returneaza `True` daca valorile operanzilor sunt egale si `False` in caz contrar
- `!=` : operatorul de inegalitate; returneaza `False` daca valorile operanzilor sunt egale si `True` in caz contrar
- `>` : operatorul "mai mare"; returneaza `True` daca valoarea operandului din stanga este mai mare decat valoarea operandului din dreapta si `False` in caz contrar
- `>=` : operatorul "mai mare sau egal"; returneaza `True` daca valoarea operandului din stanga este mai mare sau egala cu valoarea operandului din dreapta si `False` in caz contrar
- `<` : operatorul "mai mic"; returneaza `True` daca valoarea operandului din stanga este mai mica decat valoarea operandului din dreapta si `False` in caz contrar
- `<=` : operatorul "mai mic sau egal"; returneaza `True` daca valoarea operandului din stanga este mai mica sau egala cu valoarea operandului din dreapta si `False` in caz contrar

In [10]:

    # Exemplul 9: utilizarea operatorilor de comparare in expresii booleene

    # initializarea a 2 variabile prin utilizarea intructiunii de atribuire multipla
    x, y = 10, 20

    #  expresii booleene
    xEQy   = (x == y)
    xNEQy  = (x != y)
    xGy    = (x > y)
    xGEy   = (x >= y)
    xLy    = (x < y)
    xLEy   = (x <= y)

    # afisare rezultate
    print('x =', x, 'y=', y)
    print()
    print('x == y is ', xEQy)
    print('x != y is ', xNEQy)
    print('x > y  is ', xGy)
    print('x >= y is ', xGEy)
    print('x < y  is ', xLy)
    print('x <= y is ', xLEy)

    x = 10 y= 20

    x == y is  False
    x != y is  True
    x > y  is  False
    x >= y is  False
    x < y  is  True
    x <= y is  True

## 6. Operatori logici¶

Operatorii logici sunt utilizati pentru combinarea unor operanzi booleeni. Operatorii logici se pot aplica si unor operanzi numerici, sau chiar string-uri, dar aceasta abordare se indeparteaza de scopul cu care au fost introdusi acesti operatori. Utilizarea acestor operatori genereaza expresii booleene, deoarece prin evaluarea acestora se returneaza o valoarea de tip boolean `bool`, `True` sau `False`.
Operatorii logici definiti in Python sunt urmatorii:

- `and` : operatorul SI logic; returneaza `True` daca valorile ambilor operanzi sunt `True` si `False` in caz contrar
- `or` : operatorul SAU logic; returneaza `False` daca valorile ambilor operanzi sunt `False` si `True` in caz contrar
- `not` : operatorul de negare logica (unar); returneaza `False` daca valoarea operandului este `True` si `True` daca valoarea operandului este `False`.

In [11]:

    # Exemplul 10: utilizarea operatorilor logici in diverse teste

    # definirea unui interval de valori:
    MIN = 0
    MAX = 100

    # initializarea unei variabile:
    speed = int(input('Set the speed: '))

    # test: `speed` apartine intervalului [MIN, MAX]
    insideRange = (speed >= MIN) and (speed <= MAX)

    # test: `speed` nu apartine intervalului [MIN, MAX]
    outsideRange = (speed < MIN) or (speed > MAX)

    # test: `speed` este negativ
    negativeNumber = not(speed >= MIN)

    # afisare rezultate:
    print ('Q: speed is inside  the range?  A:', insideRange)
    print ('Q: speed is outside the range?  A:', outsideRange)
    print ('Q: speed has a negative value?  A:', negativeNumber)

    Set the speed: 60
    Q: speed is inside  the range?  A: True
    Q: speed is outside the range?  A: False
    Q: speed has a negative value?  A: False

Observatie:

In cazul in care operatorii logici sunt aplicati unor operanzi numerici, in evaluarea expresiei, valoarea numerica 0 este interpretata ca `False`, iar valorile numerice nenule sunt interpretate ca `True`, dar rezultatele nu sunt returnate in toate cazurile ca valori booleene, iar logica rezultatului evaluarii expresiei nu respecta logica dupa care sunt definiti operatorii logici (cazul operatorilor `and` si `or`).

In [12]:

    # Exemplul 11: aplicarea operatorilor logici pe operanzi numerici (nu se recomanda)

    print('1 and 2:', 1 and 2)
    print('2 and 1:', 2 and 1)
    print('1 and 0:', 0 and 1)
    print('0 and 0:', 0 and 0)

    print('1 or 2: ', 1 or 2)
    print('2 or 1: ', 2 or 1)
    print('0 or 1: ', 0 or 1)
    print('0 or 0: ', 0 or 0)

    print('not 1:', not 1)
    print('not 0:', not 0)

    1 and 2: 2
    2 and 1: 1
    1 and 0: 0
    0 and 0: 0
    1 or 2:  1
    2 or 1:  2
    0 or 1:  1
    0 or 0:  0
    not 1: False
    not 0: True

Observatie:

In cazul in care operatorii logici sunt aplicati unor operanzi de tip string, in evaluarea expresiei, sirul gol (empty string) `''` este interpretat ca `False`, iar sirurile care nu sunt goale sunt intepretate ca `True`, dar rezultatele nu sunt returnate in toate cazurile ca valori booleene, iar logica rezultatului evaluarii expresiei nu respecta logica dupa care sunt definiti operatorii logici (cazul operatorilor `and` si `or`).

In [13]:

    # Exemplul 12: aplicarea operatorilor logici pe operanzi string
    print("'a' and 'b': ", 'a' and 'b')
    print("'b' and 'a': ", 'b' and 'a')
    print(" '' and 'b': ", ''  and 'b')

    print("'a' or 'b': ", 'a' or 'b')
    print("'b' or 'a': ", 'b' or 'a')
    print("'' or 'b': " , ''  or 'b')
    print("'' or '': "  , ''  or '')

    print("not 'a': ", not 'a')
    print("not '': " , not '')

    'a' and 'b':  b
    'b' and 'a':  a
     '' and 'b':
    'a' or 'b':  a
    'b' or 'a':  b
    '' or 'b':  b
    '' or '':
    not 'a':  False
    not '':  True

# 7. Operatori logici pe biti (bitwise logic operators)¶

Operatorii logici pe biti se aplica doar operanzilor de tip intreg `int` sau `bool`. In evaluarea expresiilor care contin astfel de operatori, operanzii sunt reprezentati in cod complement fata de 2. In cazul operatorilor de tip `bool`, valorile sunt reprezentare intern (1 = `True`, 0 = `False`). Utilizarea acestor operatori genereaza expresii aritmetice, deoarece prin evaluarea acestora se returneaza o valoarea de tip `int`. Valoarea numerica returnata este reprezentata in cod complement fata de 2.

Operatorii logici pe biti, definiti in limbajul Python sunt urmatorii:

- `&` : operatorul SI logic pe biti; returneaza o valoarea intreaga, reprezentata in cod complement fata de 2, generata prin aplicarea functiei logice SI bit cu bit, asupra bitilor celor 2 operanzi
- `|` : operatorul SAU logic pe biti; returneaza o valoarea intreaga, reprezentata in cod complement fata de 2, generata prin aplicarea functiei logice SAU bit cu bit, asupra bitilor celor 2 operanzi
- `^` : operatorul XOR logic pe biti; returneaza o valoarea intreaga, reprezentata in cod complement fata de 2, generata prin aplicarea functiei logice XOR bit cu bit, asupra bitilor celor 2 operanzi
- `~` : operatorul negare logica pe biti; returneaza o valoarea intreaga, reprezentata in cod complement fata de 2, generata prin aplicarea functiei de negare logica, la nivelul fiecarui bit al operandului
- `<<` : operatorul deplasare la stanga; returneaza o valoarea intreaga, reprezentata in cod complement fata de 2, generata prin deplasarea la stanga a bitilor operandului, cu un numar de pozitii specificat printr-un intreg, in dreapta operatorului

- `>>` : operatorul deplasare la dreapta; returneaza o valoarea intreaga, reprezentata in cod complement fata de 2, generata prin deplasarea la dreapta a bitilor operandului, cu un numar de pozitii specificat printr-un intreg, in dreapta operatorului

- Sintaxa:

    a & b
    a | b
    a ^ b
      ~ a
    a << n
    a >> n

In [14]:

    # Exemplul 13: aplicarea operatorilor logici pe biti
    # creare variabile
    a , b = 1 , 2

    # aplicare operatori logici pe biti:
    aANDb = a & b
    aORb  = a | b
    aXORb = a ^ b
    notA  = ~ a
    aRightShift = a << 1
    aLeftShift  = a >> 1

    # afisare rezultate in cod binar
    print('aANDb:'      , aANDb)
    print('aORb:'       , aORb)
    print('aXORb:'      , aXORb)
    print('notA:'       , notA)
    print('aRightShift:', aRightShift)
    print('aLeftShift:' , aLeftShift)

    aANDb: 0
    aORb: 3
    aXORb: 3
    notA: -2
    aRightShift: 2
    aLeftShift: 0

### Determinarea codului binar al valorilor intregi¶

Limbajul Python pune la dispozitia programatorului functia `bin()` care returneaza codul binar al intregului, furnizat ca argument functiei.

- Sintaxa:

      bin(intreg)  # returneaza codul binar al intregului furnizat ca argument

In [15]:

    # Exemplul 14: aplicarea operatorilor logici pe biti; utilizarea funtiei bin()

    # creare variabile
    a , b = 11, 14

    # conversia variabilelor in codul binar, corespunzator valorii acestora;
    a_2_bin = bin(a)
    b_2_bin = bin(b)

    # testare operatori logici pe biti:
    aANDb = a & b
    aORb  = a | b
    aXORb = a ^ b
    notA  = ~ a
    aRightShift = a << 1
    aLeftShift  = a >> 1

    # afisare rezultate in cod binar
    print(f'a: {a_2_bin:>24}')
    print(f'b: {b_2_bin:>24}')
    print('_'*27)
    print(f'aANDb:{bin(aANDb):>21}')
    print(f'aORb: {bin(aORb):>21}')
    print(f'aXORb:{bin(aXORb):>21}')
    print(f'notA: {bin(notA):>21}')
    print(f'aRightShift: {bin(aRightShift):>14}')
    print(f'aLeftShift:  {bin(aLeftShift):>14}')

    a:                   0b1011
    b:                   0b1110
    ___________________________
    aANDb:               0b1010
    aORb:                0b1111
    aXORb:                0b101
    notA:               -0b1100
    aRightShift:        0b10110
    aLeftShift:           0b101

# 8. Operatorul de testare a identitatii obiectelor¶

Acest operator este utilizat pentru testarea identitatii operanzilor utilizati in expresia rezultata prin utilizarea sa. Operatorul compara operanzii, care sunt 2 obiecte (2 variabile) si returneaza `True` daca operanzii reprezinta acelasi obiect (ocupa aceeasi locatie de memorie) si `False` in caz contrar; acest operator nu compara daca operanzii sunt egali! Operatorii de testare a identitatii obiectelor, definiti in limbajul Python sunt urmatorii:

- `is` : returneaza `True` daca obiectele a si b reprezinta acelasi obiect; `False` in caz contrar
- `is not` : returneaza `True` daca obiectele a si b NU reprezinta acelasi obiect; `False` in caz contrar

- Sintaxa:

      a is b        # returneaza True daca obiectele a si b reprezinta acelasi obiect; False in caz contrar

- Sintaxa:

      a is not b    # returneaza True daca obiectele a si b NU reprezinta acelasi obiect; False in caz contrar

In [16]:

    # Exemplul 15: utilizarea operatorului de testare a identitatii obiectelor
    # crearea a 2 obiecte (variabile) initializate cu aceeasi valoare
    a = 0  # inlocuieste cu o valoare din ext. domeniului [-5, 256]
    b = 0  # inlocuieste cu o valoare din ext. domeniului [-5, 256]

    # test: verificare daca a si b reprezinta acelasi obiect (aceeasi variabila)
    same_obj = a is b

    # test: verificare daca a si b NU reprezinta acelasi obiect
    diff_obj = a is not b

    # printing the results:
    print(f'Q: Are the same  object,  2 objects with equal values ?  A: {same_obj}' )
    print(f'Q: Are different objects, 2 objects with equal values?   A: {diff_obj}' )

    Q: Are the same  object,  2 objects with equal values ?  A: True
    Q: Are different objects, 2 objects with equal values?   A: False

## 9. Operatori pentru testarea apartenentei¶

Sunt utilizati in scopul testarii apartenentei unui element, la o colectie de elemente. Operatorii de testare a apartenentei unui element la o colectie de elemente, definiti in Python sunt urmatorii:

- `in` : returneaza `True` daca elementul apartine obiectului si `False` in caz contrar

- `not in` : returneaza `True` daca elementul NU apartine obiectului si `False` in caz contrar

- Sintaxa:

      element in colectie          # returneaza True daca element apartine obiectului;
                                 # False in caz contrar

- Sintaxa:

      element not in colectie      # returneaza True daca element NU apartine obiectului;
                                 # False in caz contrar

In [17]:

    # Exemplul 16: utilizarea operatorului de testare a apartenentei unui element la o colectie

    # creating 2 string variables
    command   = 'turn right'  # 'turn_left'
    message   = 'Robot command: turn right'

    # cheking if the command is executed
    is_running      = command in message
    is_not_running  = command not in message

    # printing results:
    print(f'The command is running:      {is_running}'     )
    print(f'The command is not running:  {is_not_running}' )

    The command is running:      True
    The command is not running:  False

## 10. Operatorul conditional (operatorul ternar)¶

Sintaxa:

    segment_cod_True if conditie else segment_cod_False

Modul de executie al instructiunii de decizie:

- daca conditie este evaluat ca `True` atunci se executa segment_cod_True.
- altfel, se executa segment_cod_False

In [18]:

    # Exemplul 17: filtrarea unei valori de intrare

    value = float(input('Enter the robot speed: '))

    # test validare valoare variabila:
    speed = value if speed > 0 else 0

    # iesire program: afisare rezultat
    print(speed)

    Enter the robot speed: 60
    60.0