Instructiunile repetitive (buclele) executa in mod repetat aceeasi actiune, descrisa intr-un segment de cod. Fiecare repetitie a actiunii (segmentului de cod) se numeste iteratie. In limbajul Python sunt definite 2 tipuri de bucle, clasificate in functie de modul in care numarul de iteratii este controlat:

- bucla `while`: bucla conditionala (conditional loop), in care numarul de iteratii depinde de validare unei conditii
- bucla `for`: bucla definita (definite loop), in care numarul de iteratii este predefinit

# 1. Bucla `while`¶

Este utilizata atunci cand numarul de iteratii nu este predictibil, acesta depinzand de validarea unei conditii booleene. La acest tip de bucla, iteratiile se executa atat timp cat conditia utilizata ca test este adevarata. In cazul in care conditia utilizata ca test nu mai este validata, executia codului sursa trece la urmatoarea instructiune, plasata dupa instructiunea `while`.

Sintaxa:

    while conditie:
        iteratie
    else:              # optional
        iesire         # optional

unde in mod uzual, conditie reprezinta o expresie booleeana, iteratie reprezinta un segment de cod, care descrie o actiune repetitiva, iar iesire reprezinta un segment de cod, care descrie o actiune care se executa la iesirea din bucla. Clauza `else` este optionala si este utilizata numai atunci cand este necesar ca la iesirea din bucla sa fie executata o actiune specifica.

Modul de executie al buclei `while`:

- daca expresia conditie este evaluata ca `True` atunci se executa iteratie, dupa care se revine la etapa de evaluare a expresiei conditie; actiunea se repeta atat timp cat expresia conditie este evaluata ca `True`;
- in cazul in care expresia conditie este evaluata ca `False`, iteratie nu se mai executa si:
  - daca bucla `while` nu contine clauza `else`, fluxul de executie al codului trece la instructiunea plasate pe urmatoarea linie de cod, dupa instructiunea `while`
  - daca bucla `while` contine clauza `else`, se executa iesire, dupa care fluxul de executie al codului trece la instructiunea plasata pe urmatoarea linie de cod, dupa instructiunea `while`

Observatie:
In cazul in care este utilizata incorect, bucla `while` poate genera o bucla infinita: o bucla in care iteratiile se repeta in mod continuu, fara a exista o cale logica pentru iesirea din bucla respectiva. Bucla infinita este generata atunci cand conditia utilizata ca test este validata permanent. Aceasta reprezinta o eroare de logica in crearea programului. Pentru evitarea sa, este necesar ca programatorul sa asigure in codul sursa o cale logica care sa invalideze conditia utilizata ca test in bucla.
De multe ori, solutia pentru evitarea generarii buclei infinite consta fie in includerea in conditia care este utilizata ca test a unei variabile numerice de tip contor (sau index), care contorizeaza numarul iteratiilor (valoarea sa fiind actualizata la fiecare iteratie), fie utilizarea unei variabile booleene de tip santinela, care se mentine la o valoarea care valideaza conditia de test, atat timp cat utilizatorul sau programul nu intervine si ii modifica valoarea astfel incat conditia de test sa devina invalida.

In [1]:

    # Exemplul 1: utilizarea buclei while - utilizarea unei variabile contor - controlul deplasarii unui robot

    # intrare in program: citire si filtrare distanta punct oprire robot

    input_value = int(input('Enter the distance: '))
    distance = input_value if input_value > 0 else 0

    # algoritm: control deplasare robot pana in punctul de oprire

    while distance > 0:
        print(f'the current distance: {distance}; command = RUN')
        distance -= 1

    print(f'the current distance: {distance}; command = STOP')

    Enter the distance: 20
    the current distance: 20; command = RUN
    the current distance: 19; command = RUN
    the current distance: 18; command = RUN
    the current distance: 17; command = RUN
    the current distance: 16; command = RUN
    the current distance: 15; command = RUN
    the current distance: 14; command = RUN
    the current distance: 13; command = RUN
    the current distance: 12; command = RUN
    the current distance: 11; command = RUN
    the current distance: 10; command = RUN
    the current distance: 9; command = RUN
    the current distance: 8; command = RUN
    the current distance: 7; command = RUN
    the current distance: 6; command = RUN
    the current distance: 5; command = RUN
    the current distance: 4; command = RUN
    the current distance: 3; command = RUN
    the current distance: 2; command = RUN
    the current distance: 1; command = RUN
    the current distance: 0; command = STOP

In [2]:

    # Exemplul 2: utilizarea buclei while - utilizarea unei variabile santinela - controlul deplasarii unui robot = v2

    # intrare in program: citire si filtrare distanta punct oprire robot
    input_value = int(input('Enter the distance: '))
    distance = input_value if input_value > 0 else 0

    sentinel = True

    # algoritm: control deplasare robot pana in punctul de oprire

    while sentinel:
        print(f'the current distance: {distance}; command = RUN')
        distance -= 1
        if not distance:       # daca distance > 0 => distance - evaluat True; daca distance = 0 => distance - evaluat False
            sentinel = False

    print(f'the current distance: {distance}; command = STOP')

    Enter the distance: 20
    the current distance: 20; command = RUN
    the current distance: 19; command = RUN
    the current distance: 18; command = RUN
    the current distance: 17; command = RUN
    the current distance: 16; command = RUN
    the current distance: 15; command = RUN
    the current distance: 14; command = RUN
    the current distance: 13; command = RUN
    the current distance: 12; command = RUN
    the current distance: 11; command = RUN
    the current distance: 10; command = RUN
    the current distance: 9; command = RUN
    the current distance: 8; command = RUN
    the current distance: 7; command = RUN
    the current distance: 6; command = RUN
    the current distance: 5; command = RUN
    the current distance: 4; command = RUN
    the current distance: 3; command = RUN
    the current distance: 2; command = RUN
    the current distance: 1; command = RUN
    the current distance: 0; command = STOP

In [3]:

    # Exemplul 3: utilizarea buclei while cu clauza else - controlul deplasarii unui robot = v3

    # intrare in program: citire si filtrare distanta punct oprire robot

    input_value = int(input('Enter the distance: '))
    distance = input_value if input_value > 0 else 0

    # algoritm: control deplasare robot pana in punctul de oprire

    while distance > 0:
        print(f'the current distance: {distance}; command = RUN')
        distance -= 1
    else:
        print(f'the current distance: {distance}; command = STOP')

    print('The robot is waiting a new command.')

    Enter the distance: 20
    the current distance: 20; command = RUN
    the current distance: 19; command = RUN
    the current distance: 18; command = RUN
    the current distance: 17; command = RUN
    the current distance: 16; command = RUN
    the current distance: 15; command = RUN
    the current distance: 14; command = RUN
    the current distance: 13; command = RUN
    the current distance: 12; command = RUN
    the current distance: 11; command = RUN
    the current distance: 10; command = RUN
    the current distance: 9; command = RUN
    the current distance: 8; command = RUN
    the current distance: 7; command = RUN
    the current distance: 6; command = RUN
    the current distance: 5; command = RUN
    the current distance: 4; command = RUN
    the current distance: 3; command = RUN
    the current distance: 2; command = RUN
    the current distance: 1; command = RUN
    the current distance: 0; command = STOP
    The robot is waiting a new command.

# 2. Bucla `for`¶

Este utilizata in cazul in care numarul de iteratii este cunoscut. In limbajul Python, bucla `for` este foarte utila in iterarea continutului colectiilor (string-uri, containere, etc.).

Sintaxa:

    for item in secventa:
        iteratie
    else:                 # optional
        iesire            # optional

unde, in mod uzual, secventa reprezinta o colectie de elemente (item-uri), iar iteratie reprezinta un segment de cod, care descrie actiunea repetitiva.
Modul de executie al buclei `for`:

- la fiecare iteratie, item preia din secventa valoarea corespunzatoare iteratiei curente si se executa iteratie, dupa care se se trece automat la urmatorul item din secventa
- dupa ce au fost parcurse toate elementele din secventa,
  - daca bucla `for` nu contine clauza `else`, se trece direct la executia instructiunii plasate pe urmatoarea linie de cod, dupa instructiunea `for` (fara ca iesire sa se execute)
  - daca bucla `for` contine clauza `else`, se executa iesire, dupa care se trece la executia instructiunii plasate pe urmatoarea linie de cod, dupa instructiunea `for`

Numarul de iteratii depinde de dimensiunea (lungimea) secventei.

In [4]:

    # Exemplul 4: utilizarea buclei for - parcurgerea caracterelor unui string si afisarea codurilor UNICODE corespunzatoare

    message = 'A drone is flying.'

    for char in message:
        print(f'{char}:  {ord(char)}' )

    A:  65
     :  32
    d:  100
    r:  114
    o:  111
    n:  110
    e:  101
     :  32
    i:  105
    s:  115
     :  32
    f:  102
    l:  108
    y:  121
    i:  105
    n:  110
    g:  103
    .:  46

In [6]:

    # Exemplul 5: utilizarea buclei for cu clauza else

    flying_message  = 'The drone is flying.'
    landing_message = 'The drone is landing.'

    for i in flying_message[0:9]:  # i ia pe rand valorile 'T' 'h' 'e' ' ' si este utilizat
                                   # pentru controlul numarului de ieteratii
                                   # (valoarea sa nu este utilizata in iteratii)
        print(flying_message)
    else:
        print(landing_message)

    print('The drone is waiting a new command.')

    The drone is flying.
    The drone is flying.
    The drone is flying.
    The drone is flying.
    The drone is flying.
    The drone is flying.
    The drone is flying.
    The drone is flying.
    The drone is flying.
    The drone is landing.
    The drone is waiting a new command.

# 3. Instructiunea `continue`¶

Instructiunea `continue` determina abandonarea executiei iteratiei curente, si trecerea automata la urmatoarea iteratie. Este utilizata atunci cand, in anumite iteratii, este necesar ca iteratie sa nu se execute.
Instructiunea `continue` se introduce in segmentul de cod iteratie al buclei, in mod uzual in interiorul unei instructiunii de decizie `if`.

### Includerea instructiunii `continue` in bucla `while`¶

Sintaxa:

    while conditie:
        #  segment de cod
        if conditie:
            # segment de cod
            continue

    else:              # optional
        iesire         # optional

### Includerea instructiunii `continue` in bucla `for`¶

Sintaxa:

    for item in secventa:
        #  segment de cod
        if conditie:
            # segment de cod
            continue

    else:              # optional
        iesire         # optional

Modul de executie al buclelor `while` si `for`, care includ instructiunea `continue` este identic cu cel prezentat anterior, cu exceptia faptului ca atunci cand este satisfacuta conditia care controleaza instructiunea `continue`, se abandoneaza executia iteratiei curente si se trece automat la urmatoarea iteratie.

# 4. Instructiunea `break`¶

Instructiunea `break` determina abandonarea executiei iteratiei curente, iesirea din bucla si trecerea automata la instructiunea urmatoare plasata in cod dupa bucla. Este utilizata atunci cand anumite iteratii genereaza conditii de iesire din bucla.
Instructiunea `break` se introduce in segmentul de cod iteratie al buclei, in mod uzual in interiorul unei instructiunii de decizie `if` (similar instructiunii `continue`).

### Includerea instructiunii `break` in bucla `while`¶

Sintaxa:

    while conditie:
        #  segment de cod
        if conditie:
            # segment de cod
            break

    else:              # optional
        iesire         # optional

### Includerea instructiunii `break` in bucla `for`¶

Sintaxa:

    for item in secventa:
        #  segment de cod
        if conditie:
            # segment de cod
            break

    else:              # optional
        iesire         # optional

Modul de executie al buclelor `while` si `for`, care includ instructiunea `break` este identic cu cel prezentat anterior, cu exceptia faptului ca atunci cand este satisfacuta conditia care controleaza instructiunea `break`, se abandoneaza executia iteratiei curente si se trece automat la urmatoarea iteratie.

In [7]:

    # Exemplul 6: utilizarea buclei while cu instructiunile continue si break - controlul directiei de deplasare a unui robot

    # setare control deplasare
    CONTROL_F = 'MOVE FORWARD'
    CONTROL_B = 'MOVE BACKWARD'
    CONTROL_L = 'TURNING LEFT'
    CONTROL_R = 'TURNING RIGHT'
    CONTROL_S = 'STOP MOVING'

    # setare comenzi deplasare
    comm_f = f'F: {CONTROL_F}'
    comm_b = f'B: {CONTROL_B}'
    comm_l = f'L: {CONTROL_L}'
    comm_r = f'R: {CONTROL_R}'
    comm_s = f'S: {CONTROL_S}'

    # afisare menu comenzi deplasare

    print('Keyboard command menu:', end = '\n' + '.'*22 + '\n' )
    print(comm_f, comm_b, comm_l, comm_r, comm_s, sep = '\n', end = '\n' + '.'*22 + '\n'  )

    # setare variabila santinela pentru bucla while

    running =  True

    # initializare control robot

    control =  ''

    # algoritm:

    while running:
        command = input('COMMAND: ').lower()
        if command == 'f':
            control = CONTROL_F
        elif command == 'b':
            control = CONTROL_B
        elif command == 'l':
            control = CONTROL_L
        elif command == 'r':
            control = CONTROL_R
        elif command == 's':
            control = CONTROL_S
            break
        else:
           continue
        print(f'ACTION: {control}')

    print(f'ACTION: {control}')

    Keyboard command menu:
    ......................
    F: MOVE FORWARD
    B: MOVE BACKWARD
    L: TURNING LEFT
    R: TURNING RIGHT
    S: STOP MOVING
    ......................
    COMMAND: F
    ACTION: MOVE FORWARD
    COMMAND: f
    ACTION: MOVE FORWARD
    COMMAND: f
    ACTION: MOVE FORWARD
    COMMAND: F
    ACTION: MOVE FORWARD
    COMMAND: L
    ACTION: TURNING LEFT
    COMMAND: L
    ACTION: TURNING LEFT
    COMMAND: F
    ACTION: MOVE FORWARD
    COMMAND: F
    ACTION: MOVE FORWARD
    COMMAND: R
    ACTION: TURNING RIGHT
    COMMAND: R
    ACTION: TURNING RIGHT
    COMMAND: B
    ACTION: MOVE BACKWARD
    COMMAND: B
    ACTION: MOVE BACKWARD
    COMMAND: L
    ACTION: TURNING LEFT
    COMMAND: S
    ACTION: STOP MOVING

# 5. Functia `len()`¶

Functia predefinita `len()` returneaza valoarea lungimii unei colectii de elemente. Lungimea unei colectii de elemente este egala cu numarul de elemente care apartin colectiei respective.
In cazul buclelor `while`, functia `len()` poate fi utilizata pentru controlul numarului de iteratii.

Sintaxa:

    len(colectie)     # returneaza numarul de elemente dintr-o colectie (secventa)

In [8]:

    # Exemplul 7 - afisarea informatiilor despre functia len

    help(len)

    Help on built-in function len in module builtins:

    len(obj, /)
        Return the number of items in a container.

In [16]:

    # Exemplul 8 - exemplu de utilizare a functiei len() pentru controlul buclei while

    # creare colectie de caractere = un sir de caractere
    message = 'Start robot'

    index = 0
    while index < len(message):
        if message[index] == ' ':
            print(chr(0x1F60E))
        else:
            print(message[index])
        index += 1

    S
    t
    a
    r
    t
    😎
    r
    o
    b
    o
    t

# 6. Functia `range()`¶

Functia predefinita `range()` genereaza un obiect care contine o secventa de numere intregi, care apartin unuin interval de valori, cu pas specificat. In cazul buclelor `for`, functia `range()` poate fi utilizata pentru generarea colectiei care urmeaza a fi iterata la executia buclei.

Sintaxa:

    range(start, stop, step)   # returneaza un obiect care genereaza o colectie (secventa) de numere intregi

Functia `range()` returneaza un obiect care contine o colectie de numere intregi, in intervalul [start, stop) cu pasul step; valoarea stop nu este inclusa in colectie.

Moduri de utilizare:

    range(j)                     # returneaza o colectie de intregi 0, 1, 2, ..., j-1
                                 # start = 0
                                 # stop  = j
                                 # step  = 1

    range(i, j)                  # conditie necesara: i < j
                                 # returneaza o colectie de intregi i, i+1, i+2, ..., i+j-1
                                 # start = i
                                 # stop  = j
                                 # step  = 1

    range(i, j, k)               # conditie necesara: i < j
                                 # returneaza o colectie de intregi i, i+k, i+2k, ..., i+j-k (daca i+j-k < j)
                                 # start = i
                                 # stop  = j
                                 # step  = k

    range(i, j, -k)              # conditie necesara: i > j
                                 # returneaza o colectie de intregi i, i-k, i-2k, ..., i+j-k (daca i+j-k > j)
                                 # start = i
                                 # stop  = j
                                 # step  = k

In [17]:

    # Exemplul 9 - afisarea informatiilor despre functia range

    help(range)

    Help on class range in module builtins:

    class range(object)
     |  range(stop) -> range object
     |  range(start, stop[, step]) -> range object
     |
     |  Return an object that produces a sequence of integers from start (inclusive)
     |  to stop (exclusive) by step.  range(i, j) produces i, i+1, i+2, ..., j-1.
     |  start defaults to 0, and stop is omitted!  range(4) produces 0, 1, 2, 3.
     |  These are exactly the valid indices for a list of 4 elements.
     |  When step is given, it specifies the increment (or decrement).
     |
     |  Methods defined here:
     |
     |  __bool__(self, /)
     |      self != 0
     |
     |  __contains__(self, key, /)
     |      Return key in self.
     |
     |  __eq__(self, value, /)
     |      Return self==value.
     |
     |  __ge__(self, value, /)
     |      Return self>=value.
     |
     |  __getattribute__(self, name, /)
     |      Return getattr(self, name).
     |
     |  __getitem__(self, key, /)
     |      Return self[key].
     |
     |  __gt__(self, value, /)
     |      Return self>value.
     |
     |  __hash__(self, /)
     |      Return hash(self).
     |
     |  __iter__(self, /)
     |      Implement iter(self).
     |
     |  __le__(self, value, /)
     |      Return self<=value.
     |
     |  __len__(self, /)
     |      Return len(self).
     |
     |  __lt__(self, value, /)
     |      Return self<value.
     |
     |  __ne__(self, value, /)
     |      Return self!=value.
     |
     |  __reduce__(...)
     |      Helper for pickle.
     |
     |  __repr__(self, /)
     |      Return repr(self).
     |
     |  __reversed__(...)
     |      Return a reverse iterator.
     |
     |  count(...)
     |      rangeobject.count(value) -> integer -- return number of occurrences of value
     |
     |  index(...)
     |      rangeobject.index(value) -> integer -- return index of value.
     |      Raise ValueError if the value is not present.
     |
     |  ----------------------------------------------------------------------
     |  Static methods defined here:
     |
     |  __new__(*args, **kwargs) from builtins.type
     |      Create and return a new object.  See help(type) for accurate signature.
     |
     |  ----------------------------------------------------------------------
     |  Data descriptors defined here:
     |
     |  start
     |
     |  step
     |
     |  stop

In [2]:

    # Exemplul 8: utilizarea buclei FOR cu instructiunile continue si break - controlul directiei de deplasare a unui robot

    # setare control deplasare
    CONTROL_F = 'MOVE FORWARD'
    CONTROL_L = 'TURNING LEFT'
    CONTROL_R = 'TURNING RIGHT'
    CONTROL_S = 'STOP MOVING'

    # setare comenzi deplasare
    comm_f = f'F: {CONTROL_F}'
    comm_l = f'L: {CONTROL_L}'
    comm_r = f'R: {CONTROL_R}'
    comm_s = f'S: {CONTROL_S}'

    # afisare menu comenzi deplasare
    print('Keyboard command menu:', end = '\n' + '.'*22 + '\n' )
    print(comm_f, comm_l, comm_r, comm_s, sep = '\n', end = '\n' + '.'*22 + '\n'  )

    # initializare control robot
    DISTANCE =  20
    STEP = 1
    TRACE = '*'
    left =  50
    right = 50

    # algoritm:
    print(' '*left + TRACE + ' '*right )
    for i in range(DISTANCE):
        command = input(': ').lower()
        if command == 'f':
            pass
        elif command == 'l':
            left  -= STEP
            right += STEP
        elif command == 'r':
            left  += STEP
            right -= STEP
        elif command == 's':
            break
        else:
           continue
        print(' '*left + TRACE + ' '*right )

    print(CONTROL_S)

    Keyboard command menu:
    ......................
    F: MOVE FORWARD
    L: TURNING LEFT
    R: TURNING RIGHT
    S: STOP MOVING
    ......................
                                                      *
    : F
                                                      *
    : F
                                                      *
    : F
                                                      *
    : L
                                                     *
    : L
                                                    *
    : L
                                                   *
    : L
                                                  *
    : L
                                                 *
    : L
                                                *
    : R
                                                 *
    : R
                                                  *
    : R
                                                   *
    : R
                                                    *
    : F
                                                    *
    : F
                                                    *
    : R
                                                     *
    : R
                                                      *
    : F
                                                      *
    : L
                                                     *
    : L
                                                    *
    STOP MOVING

In [5]:

    # Exemplul 9: utilizarea buclei FOR pentru monitorizarea traiectoriei unui robot

    # importare modul time
    import time

    DELAY  = 0.3
    left = 50
    right = 50

    for i in range(37):
        print(' '*left + str(i) +' '*right)
        step = 4
        if i < 5:
            left  += step
            right -= step
        elif 5 <= i < 10:
            left  -= step
            right += step
        elif 10 <= i < 15:
            left  += step
            right -= step
        elif 15 <= i < 20:
            left  -= step
            right += step
        else:
            left  += step
            right -= step
    # temporizare executie cod
        time.sleep(DELAY)

                                                      0
                                                          1
                                                              2
                                                                  3
                                                                      4
                                                                          5
                                                                      6
                                                                  7
                                                              8
                                                          9
                                                      10
                                                          11
                                                              12
                                                                  13
                                                                      14
                                                                          15
                                                                      16
                                                                  17
                                                              18
                                                          19
                                                      20
                                                          21
                                                              22
                                                                  23
                                                                      24
                                                                          25
                                                                              26
                                                                                  27
                                                                                      28
                                                                                          29
                                                                                              30
                                                                                                  31
                                                                                                      32
                                                                                                          33
                                                                                                              34
                                                                                                                  35
                                                                                                                      36