Вы здесь

Python. 1.3 Контроль хода программы

До сих пор, весь код выполнялся последовательно - все строки скрипта выполнялись в том порядке, в котором они записаны в файле. В этом разделе рассматриваются возможности Python в управлении ходом программы:

- ответвления в ходе программы с помощью конструкции if/elif/else
- повторение действий в цикле с помощью конструкций for и while
- обработка ошибок с помощью конструкции try/except

if/elif/else

Конструкция if/elif/else позволяет делать ответвления в ходе программы. Программа уходит в ветку при выполнении определенного условия.

В этой конструкции только if является обязательным, elif и else опциональны:

- Проверка if всегда идет первой.
- После оператора if должно быть какое-то условие: если это условие выполняется (возвращает True), то действия в блоке if выполняются.
- С помощью elif можно сделать несколько разветвлений, то есть, проверять входящие данные на разные условия.
- Блок elif это тот же if, но только следующая проверка. Грубо говоря, это «а если …»
- Блоков elif может быть много.
- Блок else выполняется в том случае, если ни одно из условий if или elif не было истинным.

Пример конструкции:
python_11_ciscomaster.ru.jpg

Условия

Конструкция if построена на условиях: после if и elif всегда пишется условие. Блоки if/elif выполняются только когда условие возвращает True

True и False

В Python, кроме очевидных значений True и False, всем остальным объектам также соответствует ложное или истинное значение:

  • истинное значение
    - любое ненулевое число
    - любая непустая строка
    - любой непустой объект
  • ложное значение
    - 0
    - None
    - пустая строка
    - пустой объект

Примеры:

In [4]: list_to_test = 1, 2, 3 In [5]: if list_to_test: ...: print("В списке есть объекты") ...: В списке есть объекты

тот же результат получим:

In [6]: if len(list_to_test) != 0: ...: print("В списке есть объекты") ...: В списке есть объекты

Операторы сравнения

> ,

Пример:
python_12_ciscomaster.ru.jpg

Оператор in

Оператор in позволяет выполнять проверку на наличие элемента в последовательности (например, элемента в списке или подстроки в строке):

In [8]: 'Fast' in 'FastEthernet' Out[8]: True In [9]: 'Gigabit' in 'FastEthernet' Out[9]: False In [10]: vlan = [10, 20, 30, 40] In [11]: 10 in vlan Out[11]: True In [12]: 50 in vlan Out[12]: False

При использовании со словарями условие in выполняет проверку по ключам словаря:

In [15]: r1 = { ....: 'IOS': '15.4', ....: 'IP': '10.255.0.1', ....: 'hostname': 'london_r1', ....: 'location': '21 New Globe Walk', ....: 'model': '4451', ....: 'vendor': 'Cisco'} In [16]: 'IOS' in r1 Out[16]: True In [17]: '4451' in r1 Out[17]: False

Операторы and, or, not

В условиях могут также использоваться логические операторы and, or, not:

In [15]: r1 = { ....: 'IOS': '15.4', ....: 'IP': '10.255.0.1', ....: 'hostname': 'london_r1', ....: 'location': '21 New Globe Walk', ....: 'model': '4451', ....: 'vendor': 'Cisco'} In [18]: vlan = [10, 20, 30, 40] In [19]: 'IOS' in r1 and 10 in vlan Out[19]: True In [20]: '4451' in r1 and 10 in vlan Out[20]: False In [21]: '4451' in r1 or 10 in vlan Out[21]: True In [22]: not '4451' in r1 Out[22]: True In [23]: '4451' not in r1 Out[23]: True

Пример использования конструкции if/elif/else

Пример скрипта check_password.py, который проверяет длину пароля и есть ли в пароле имя пользователя:
python_13_ciscomaster.ru.jpg

python_14_ciscomaster.ru.jpg

Тернарное выражение (Ternary expression)

Иногда удобнее использовать тернарный оператор, нежели развернутую форму:

s = [1, 2, 3, 4] result = True if len(s) > 5 else False

Этим лучше не злоупотреблять, но в простых выражениях такая запись может быть полезной.

FOR

Очень часто одно и то же действие надо выполнить для набора однотипных данных.

Цикл for перебирает по одному элементы указанной последовательности и выполняет действия, которые указаны в блоке for, для каждого элемента.

Примеры последовательностей элементов, по которым может проходиться цикл for:

- строка
- список
- словарь
- Функция range
- любой Итерируемый объект

Пример преобразования строк в списке в верхний регистр

words = ['list', 'dict', 'tuple'] upper_words = [] for word in words: upper_words.append(word.upper()) print (upper_words)

Проект pythontutor может очень помочь в понимании циклов. Там есть специальная визуализация кода, которая позволяет увидеть, что происходит на каждом этапе выполнения кода, что особенно полезно на первых порах с циклами. На сайте pythontutor можно загружать свой код, но для примера, по этой ссылке можно посмотреть пример выше.

Аналогичным образом for работает с кортежами.

При работе со строками, цикл for перебирает символы строки, например:

In [1]: for letter in 'Test string': ...: print(letter)

Иногда в цикле необходимо использовать последовательность чисел. В этом случае, лучше всего использовать функцию Функция range

In [2]: for i in range(10): ...: print(f'interface FastEthernet0/{i}')

Ещё пример цикла:

In [3]: vlans = [10, 20, 30, 40, 100] In [4]: for vlan in vlans: ...: print(f'vlan {vlan}') ...: print(f' name VLAN_{vlan}') ...: vlan 10 name VLAN_10 vlan 20 name VLAN_20 vlan 30 name VLAN_30 vlan 40 name VLAN_40 vlan 100 name VLAN_100

Когда цикл идет по словарю, то фактически он проходится по ключам:

r1 = { 'ios': '15.4', 'ip': '10.255.0.1', 'hostname': 'london_r1', 'location': '21 New Globe Walk', 'model': '4451', 'vendor': 'Cisco'} for k in r1: print(k)

Если необходимо выводить пары ключ-значение в цикле, можно делать так:

for key in r1: print(key + ' => ' + r1[key])

Или воспользоваться методом items, который позволяет проходиться в цикле сразу по паре ключ-значение:

for key, value in r1.items(): print(key + ' => ' + value)

Метод items возвращает специальный объект view, который отображает пары ключ-значение:

In [38]: r1.items() Out[38]: dict_items([('ios', '15.4'), ('ip', '10.255.0.1'), ('hostname', 'london_r1'), ('location', '21 New Globe Walk'), ('model', '4451'), ('vendor', 'Cisco')])

Вложенные FOR

Циклы for можно вкладывать друг в друга.
В этом примере в списке commands хранятся команды, которые надо выполнить для каждого из интерфейсов в списке fast_int:

In [7]: commands = ['switchport mode access', 'spanning-tree portfast', 'spanning-tree bpduguard enable'] In [8]: fast_int = ['0/1','0/3','0/4','0/7','0/9','0/10','0/11'] In [9]: for intf in fast_int: ...: print('interface FastEthernet {}'.format(intf)) ...: for command in commands: ...: print(' {}'.format(command)) ...: interface FastEthernet 0/1 switchport mode access spanning-tree portfast spanning-tree bpduguard enable interface FastEthernet 0/3 switchport mode access spanning-tree portfast spanning-tree bpduguard enable interface FastEthernet 0/4 switchport mode access spanning-tree portfast spanning-tree bpduguard enable

Совмещение for и if

Файл generate_access_port_config.py:

access_template = ['switchport mode access', 'switchport access vlan', 'spanning-tree portfast', 'spanning-tree bpduguard enable'] access = {'0/12': 10, '0/14': 11, '0/16': 17, '0/17': 150} for intf, vlan in access.items(): print('interface FastEthernet' + intf) for command in access_template: if command.endswith('access vlan'): print(' {} {}'.format(command, vlan)) else: print(' {}'.format(command))

Комментарии к коду:

В первом цикле for перебираются ключи и значения во вложенном словаре access
Текущий ключ, на данный момент цикла, хранится в переменной intf
Текущее значение, на данный момент цикла, хранится в переменной vlan
Выводится строка interface FastEthernet с добавлением к ней номера интерфейса
Во втором цикле for перебираются команды из списка access_template
Так как к команде switchport access vlan надо добавить номер VLAN:
внутри второго цикла for проверяются команды
если команда заканчивается на access vlan
выводится команда, и к ней добавляется номер VLAN
во всех остальных случаях просто выводится команда

Результат выполнения скрипта:

$ python generate_access_port_config.py interface FastEthernet0/12 switchport mode access switchport access vlan 10 spanning-tree portfast spanning-tree bpduguard enable interface FastEthernet0/14 switchport mode access switchport access vlan 11 spanning-tree portfast spanning-tree bpduguard enable interface FastEthernet0/16 switchport mode access switchport access vlan 17 spanning-tree portfast spanning-tree bpduguard enable interface FastEthernet0/17 switchport mode access switchport access vlan 150 spanning-tree portfast spanning-tree bpduguard enable

while

Цикл while - это еще одна разновидность цикла в Python.

В цикле while, как и в выражении if, надо писать условие. Если условие истинно, выполняются действия внутри блока while. При этом, в отличие от if, после выполнения кода в блоке, while возвращается в начало цикла.

При использовании циклов while необходимо обращать внимание на то, будет ли достигнуто такое состояние, при котором условие цикла будет ложным.

In [1]: a = 5 In [2]: while a > 0: ...: print(a) ...: a -= 1 # Эта запись равнозначна a = a - 1 ...: 5 4 3 2 1

Файл check_password_with_while.py:
python_25_ciscomaster.ru.jpg

Оператор break

Оператор break позволяет досрочно прервать цикл:
- break прерывает текущий цикл и продолжает выполнение следующих выражений
- если используется несколько вложенных циклов, break прерывает внутренний цикл и продолжает выполнять выражения, следующие за блоком * break может использоваться в циклах for и while
python_26_ciscomaster.ru.jpg

Пример с циклом while:
python_27_ciscomaster.ru.jpg

Использование break в примере с запросом пароля (файл check_password_with_while_break.py):
python_28_ciscomaster.ru.jpg

Оператор continue

Оператор continue возвращает управление в начало цикла. То есть, continue позволяет «перепрыгнуть» оставшиеся выражения в цикле и перейти к следующей итерации.

In [4]: for num in range(5): ...: if num == 3: ...: continue ...: else: ...: print(num) ...: 0 1 2 4
In [5]: i = 0 In [6]: while i

Использование continue в примере с запросом пароля (файл check_password_with_while_continue.py):
python_29_ciscomaster.ru.jpg

Тут выход из цикла выполнятся с помощью проверки флага password_correct. Когда был введен правильный пароль, флаг выставляется равным True, и с помощью continue выполняется переход в начало цикла, перескочив последнюю строку с запросом пароля.

Оператор pass

Оператор pass ничего не делает. Фактически, это такая заглушка для объектов.

Например, pass может помочь в ситуации, когда нужно прописать структуру скрипта. Его можно ставить в циклах, функциях, классах. И это не будет влиять на исполнение кода.

Пример использования pass:
python_10_ciscomaster.ru.jpg

for/else, while/else

for/else

- блок else выполняется в том случае, если цикл завершил итерацию списка
- но else не выполняется, если в цикле был выполнен break

Пример цикла for с else (блок else выполняется после завершения цикла for):

In [1]: for num in range(5): ....: print(num) ....: else: ....: print("Числа закончились") ....: 0 1 2 3 4 Числа закончились

Пример цикла for с else и break в цикле (из-за break блок else не выполняется):

In [2]: for num in range(5): ....: if num == 3: ....: break ....: else: ....: print(num) ....: else: ....: print("Числа закончились") ....: 0 1 2

Пример цикла for с else и continue в цикле (continue не влияет на блок else):

In [3]: for num in range(5): ....: if num == 3: ....: continue ....: else: ....: print(num) ....: else: ....: print("Числа закончились") ....: 0 1 2 4 Числа закончились

while/else

В цикле while:

- блок else выполняется в том случае, если цикл завершил итерацию списка
- но else не выполняется, если в цикле был выполнен break
Пример цикла while с else (блок else выполняется после завершения цикла while):
python_08_ciscomaster.ru.jpg

Пример цикла while с else и break в цикле (из-за break блок else не выполняется):
python_09_ciscomaster.ru.jpg

Работа с исключениями try/except/else/finally
try/except

Даже если код синтаксически написан правильно, могут возникать ошибки. В Python эти ошибки называются исключения (exceptions).

Примеры исключений:

In [1]: 2/0 ----------------------------------------------------- ZeroDivisionError: division by zero In [2]: 'test' + 2 ----------------------------------------------------- TypeError: must be str, not int

Python позволяет работать с исключениями. Их можно перехватывать и выполнять определенные действия в том случае, если возникло исключение.
Для работы с исключениями используется конструкция try/except:

In [3]: try: ...: 2/0 ...: except ZeroDivisionError: ...: print("You can't divide by zero") ...: You can't divide by zero

Конструкция try работает таким образом:
- сначала выполняются выражения, которые записаны в блоке try
- если при выполнения блока try не возникло никаких исключений, блок except пропускается, и выполняется дальнейший код
- если во время выполнения блока try в каком-то месте возникло исключение, оставшаяся часть блока try пропускается
- если в блоке except указано исключение, которое возникло, выполняется код в блоке except
- если исключение, которое возникло, не указано в блоке except, выполнение программы прерывается и выдается ошибка

Обратите внимание, что строка Cool! в блоке try не выводится:

In [4]: try: ...: print("Let's divide some numbers") ...: 2/0 ...: print('Cool!') ...: except ZeroDivisionError: ...: print("You can't divide by zero") ...: Let's divide some numbers You can't divide by zero

В конструкции try/except может быть много except, если нужны разные действия в зависимости от типа ошибки.

Например, скрипт divide.py делит два числа введенных пользователем:

# -*- coding: utf-8 -*- try: a = input("Введите первое число: ") b = input("Введите второе число: ") print("Результат: ", int(a)/int(b)) except ValueError: print("Пожалуйста, вводите только числа") except ZeroDivisionError: print("На ноль делить нельзя")

Если нет необходимости выводить различные сообщения на ошибки ValueError и ZeroDivisionError, можно сделать так (файл divide_ver2.py):

# -*- coding: utf-8 -*- try: a = input("Введите первое число: ") b = input("Введите второе число: ") print("Результат: ", int(a)/int(b)) except (ValueError, ZeroDivisionError): print("Что-то пошло не так...")

try/except/else

В конструкции try/except есть опциональный блок else. Он выполняется в том случае, если не было исключения.

Например, если необходимо выполнять в дальнейшем какие-то операции с данными, которые ввел пользователь, можно записать их в блоке else (файл divide_ver3.py):

# -*- coding: utf-8 -*- try: a = input("Введите первое число: ") b = input("Введите второе число: ") result = int(a)/int(b) except (ValueError, ZeroDivisionError): print("Что-то пошло не так...") else: print("Результат в квадрате: ", result**2)

Пример выполнения:

$ python divide_ver3.py Введите первое число: 10 Введите второе число: 2 Результат в квадрате: 25 $ python divide_ver3.py Введите первое число: werq Введите второе число: 3 Что-то пошло не так...

try/except/finally

Блок finally - это еще один опциональный блок в конструкции try. Он выполняется всегда, независимо от того, было ли исключение или нет.

Сюда ставятся действия, которые надо выполнить в любом случае. Например, это может быть закрытие файла.

Файл divide_ver4.py с блоком finally:

# -*- coding: utf-8 -*- try: a = input("Введите первое число: ") b = input("Введите второе число: ") result = int(a)/int(b) except (ValueError, ZeroDivisionError): print("Что-то пошло не так...") else: print("Результат в квадрате: ", result**2) finally: print("Вот и сказочке конец, а кто слушал - молодец.")

Проверка:

$ python divide_ver4.py Введите первое число: 10 Введите второе число: 2 Результат в квадрате: 25 Вот и сказочке конец, а кто слушал - молодец. $ python divide_ver4.py Введите первое число: qwerewr Введите второе число: 3 Что-то пошло не так... Вот и сказочке конец, а кто слушал - молодец. $ python divide_ver4.py Введите первое число: 4 Введите второе число: 0 Что-то пошло не так... Вот и сказочке конец, а кто слушал - молодец.

Когда использовать исключения

Как правило, один и тот же код можно написать и с использованием исключений, и без них.
Например, этот вариант кода:

while True: a = input("Введите число: ") b = input("Введите второе число: ") try: result = int(a)/int(b) except ValueError: print("Поддерживаются только числа") except ZeroDivisionError: print("На ноль делить нельзя") else: print(result) break

Можно переписать таким образом без try/except (файл try_except_divide.py):

while True: a = input("Введите число: ") b = input("Введите второе число: ") if a.isdigit() and b.isdigit(): if int(b) == 0: print("На ноль делить нельзя") else: print(int(a)/int(b)) break else: print("Поддерживаются только числа")

Далеко не всегда аналогичный вариант без использования исключений будет простым и понятным.
Важно в каждой конкретной ситуации оценивать, какой вариант кода более понятный, компактный и универсальный - с исключениями или без.
Если вы раньше использовали какой-то другой язык программирования, есть вероятность, что в нём использование исключений считалось плохим тоном. В Python это не так.

raise

Иногда в коде надо сгенерировать исключение, это можно сделать так:

raise ValueError("При выполнении команды возникла ошибка")

Встроенные исключения

В Python есть много встроенных исключений, каждое из которых генерируется в определенной ситуации.

Например, TypeError обычно генерируется когда ожидался один тип данных, а передали другой

In [1]: "a" + 3 --------------------------------------------------------------------------- TypeError Traceback (most recent call last) in ----> 1 "a" + 3 TypeError: can only concatenate str (not "int") to str

Задания

  1. Задание 6.1

    Список mac содержит MAC-адреса в формате XXXX:XXXX:XXXX. Однако, в оборудовании cisco MAC-адреса используются в формате XXXX.XXXX.XXXX.

    Написать код, который преобразует MAC-адреса в формат cisco и добавляет их в новый список result. Полученный список result вывести на стандартный поток вывода (stdout) с помощью print.

    mac = ["aabb:cc80:7000", "aabb:dd80:7340", "aabb:ee80:7000", "aabb:ff80:7000"]

    Решение
    task_6_1.py

  2. Задание 6.2

    - Запросить у пользователя ввод IP-адреса в формате 10.0.1.1
    - В зависимости от типа адреса (описаны ниже), вывести на стандартный поток вывода:
    «unicast» - если первый байт в диапазоне 1-223
    «multicast» - если первый байт в диапазоне 224-239
    «local broadcast» - если IP-адрес равен 255.255.255.255
    «unassigned» - если IP-адрес равен 0.0.0.0
    «unused» - во всех остальных случаях

    Решение
    task_6_2.py

  3. Задание 6.2a

    Сделать копию скрипта задания 6.2.

    Добавить проверку введенного IP-адреса. Адрес считается корректно заданным, если он:
    - состоит из 4 чисел (а не букв или других символов)
    - числа разделенны точкой
    - каждое число в диапазоне от 0 до 255

    Если адрес задан неправильно, выводить сообщение: «Неправильный IP-адрес». Сообщение «Неправильный IP-адрес» должно выводиться только один раз, даже если несколько пунктов выше не выполнены.
    Решение
    task_6_2a.py

  4. Задание 6.2b

    Сделать копию скрипта задания 6.2a.
    Дополнить скрипт: Если адрес был введен неправильно, запросить адрес снова.

    Решение
    task_6_2b.py

  5. Задание 6.3

    В скрипте сделан генератор конфигурации для access-портов. Сделать аналогичный генератор конфигурации для портов trunk.

    В транках ситуация усложняется тем, что VLANов может быть много, и надо понимать, что с ним делать. Поэтому в соответствии каждому порту стоит список и первый (нулевой) элемент списка указывает как воспринимать номера VLAN, которые идут дальше.

    Пример значения и соответствующей команды:
    [«add», «10», «20»] - команда switchport trunk allowed vlan add 10,20
    [«del», «17»] - команда switchport trunk allowed vlan remove 17
    [«only», «11», «30»] - команда switchport trunk allowed vlan 11,30

    Задача для портов 0/1, 0/2, 0/4:
    - сгенерировать конфигурацию на основе шаблона trunk_template
    - с учетом ключевых слов add, del, only

    Код не должен привязываться к конкретным номерам портов. То есть, если в словаре trunk будут другие номера интерфейсов, код должен работать.

    Для данных в словаре trunk_template вывод на стандартный поток вывода должен быть таким:

    interface FastEthernet 0/1 switchport trunk encapsulation dot1q switchport mode trunk switchport trunk allowed vlan add 10,20 interface FastEthernet 0/2 switchport trunk encapsulation dot1q switchport mode trunk switchport trunk allowed vlan 11,30 interface FastEthernet 0/4 switchport trunk encapsulation dot1q switchport mode trunk switchport trunk allowed vlan remove 17

    python_31_ciscomaster.ru.jpg

Решение
task_6_3.py

Добавить комментарий

Filtered HTML

  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Допустимые HTML-теги: <a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Строки и абзацы переносятся автоматически.

Plain text

  • HTML-теги не обрабатываются и показываются как обычный текст
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Строки и абзацы переносятся автоматически.
CAPTCHA
Этот вопрос задается для того, чтобы выяснить, являетесь ли Вы человеком или представляете из себя автоматическую спам-рассылку.
Target Image