Алгоритмические структуры в Python (циклы, списки, типы…)

5 (100%) 6 vote[s]

В четвертом занятии рассмотрим алгоритмические структуры — логические типы, разветвления if .. else, if .. elif .., списки, цикл обхода последовательности for, универсальный цикл while.

Логический (или булевый) тип данных

Алгоритмические структуры включают логический тип. Он имеет всего 2 возможных значения: True и False — истина и ложь. Эти значения возникают, прежде всего, как результат проверки (вычисления) любых условиях в программе.

Например, результатом проверки 10> 0 будет True, 91 <0 — False. Когда условие содержит переменные, ее значение, соответственно, зависит от значений этих переменных на момент проверки условия (в цикле или разветвлении).

  1. num = raw_input('input N:')
  2. if num == '7':
  3.     print 'Lucky number!'

В данном случае после ввода значения пользователем выполняется проверка: если введена переменная равна ‘7 «(напомним, что по умолчанию введенные значения считаются строками), логическое выражение примет значение True, условие сбудется и интерпретатор перейдет во вложенный блок кода. Если переменная не равна ‘7’, выражение примет значение False, то есть «ложь» и условие не сбудется.

Вот это значение условия True или False имеет свой собственный тип данных, что позволяет нам создавать переменные этого типа и вообще использовать его за пределами разветвлений и циклов.

Например, мы можем вычислить логическое выражение заблаговременно:

  1. num = raw_input('input N:')
  2. is_seven = num == '7'
  3. if is_seven:
  4.     print 'Lucky number!'

Или (это используется гораздо чаще) создать логическую переменную-флаг, который будет сигнализировать нам о том, состоялось ли определенное событие. Например, пусть нам необходимо убедиться, существуют ли на интервале от 1 до n целые числа, которые делятся без остатка одновременно на 11 и 2:

  1. n = int(raw_input('input N:'))
  2. flag = False
  3. for i in range(n):
  4.     if (i+1) % 11 == 0:
  5.         if (i+1) % 2 == 0:
  6.             flag = True
  7. print flag

Алгоритмические структуры: простые и сложные логические выражения

Автоматически же значение логического типа возникают при наличии операций сравнения в выражении. Для некоторой пары значений a и b это:

    • a <b — равно True, если a меньше b, иначе — False,
    • a <= b — равно True, если a меньше или равно b, иначе — False,
    • a == b — равно True, если a равно b, иначе — False,
    • a! = b, a <> b — равно True, если a не равно b, иначе — False,
    • a> = b — равно True, если a больше или равно b, иначе — False,
    • a> b — равно True, если a больше b, иначе — False.

Они являются простыми логическими выражениями (условиями). В качестве a и b могут использоваться любые переменные, выражения или функции.

На практике часто приходится проверять сложные случаи и создавать разветвленные алгоритмические структуры , когда должны удовлетворяться несколько различных условий.  Для этого можно использовать целый ряд проверок — последовательных или вложенных друг в друга, как мы это только что сделали, но такая запись является громоздкой. Поэтому для этого используются сложные логические выражения, включающие несколько простых, объединенных логическими связями:

    • x or y — равно True, если хоть 1 из x или y равно True, иначе — False,
    • x and y — равно True, если x и y оба равны True, иначе — False,
    • not x — равно True, если x не равно True, иначе — False.

При этом x и y могут быть как простыми, так и сложными выражениями, позволяет строить логические выражения любой сложности. А предыдущий пример можно переписать следующим образом:

  1. n = int(raw_input('input N:'))
  2. flag = False
  3. for i in range(n):
  4.     if (i+1) % 11 == 0 and (i+1) % 2 == 0:
  5.         flag = True
  6. print flag

Алгоритмические структуры включают логические операции. Они могут применяться в одном выражении с математическими. При этом математические имеют более высокий приоритет выполнения, следовательно, будут просчитаны раньше. Далее полученные значения будут сравнению между собой, а затем результаты сравнения «объединены» логическими связями-операциями.

Первыми в выражении вычисляются значения всех «модификаторов» not, затем and слева направо, затем or — также слева направо. Так же, как и в арифметических выражениях, круглые скобки меняют порядок выполнения операций. Но, при наличии в одном выражении различных типов связь, советую всегда использовать скобки — так проще отслеживать порядок вычисления сложных выражений.

Пусть нам необходимо проверить, есть ли заданный год високосным . Для этого он должен делиться нацело на 4, но не делиться на 100, или делиться на 400:

  1. year = int(raw_input('input year:'))
  2. if (year % 4 == 0) and (not(year % 100 == 0) or (year % 400 == 0)):
  3.     print 'is leap'
  4. else:
  5.     print 'is not leap'

А если отказаться от «хорошего» текстового ответа, можно прямо вывести значение условия, то есть логического выражения, который ее составляет:

  1. year = int(raw_input('input year:'))
  2. print (year % 4 == 0) and (not(year % 100 == 0) or (year % 400 == 0))

Преобразование типов данных

True и False могут быть легко превращены в строки. Результатом будут «True» и «False» соответственно.

Также логические значения преобразуются в числа. Это может быть не так очевидно, но True соответствует единице, а False — нулю. Это работает как для целых, так и для действительных чисел:

  1. int(True) == 1
  2. int(False) == 0
  3. float(True) == 1.0
  4. float(False) == 0.0
  5. str(True) ==True
  6. str(False) ==False

В обратном порядке преобразования работает несколько иначе, но запомнить очень просто: любые «непустые» значение конвертируются в True, любые «нулевые» — в False. Для принудительного приведения значения к логическому типу используется встроенная функция bool:

  1. bool(None) == False
  2. bool (0) == False
  3. bool(0.0) == False
  4. bool('') == False

Все остальные значения известных нам типов — истинные:

  1. bool(1) == True
  2. bool(10) == True
  3. bool(-1.1) == True
  4. bool('False') == True
  5. bool(-100500) == True

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

  1. if x&gt;0 and y and z:

вместо

  1. if x&gt;0 and bool(y) and bool(z):

Например, это позволяет записать выражение с високосным годом еще одним образом:

  1. year = int(raw_input('input year:'))
  2. print not(year % 4) and ((year % 100) or not(year % 400))

Список

Алгоритмические структуры включают списки. Список — сложный тип данных, упорядоченная последовательность значений любых типов.

Это значит, что переменная-список содержит не одно значение, как число или логическая переменная, а сразу несколько. Причем это могут быть любые значения (строки, числа, логические переменные, другие списки) и их порядок четко определен. Следовательно у каждого значения в списке есть порядковый номер — индекс, по которому можно обратиться к отдельному элементу списка, чтобы прочитать или записать значение.

Для определения списка его элементы берутся в квадратные скобки:

  1. example_list = ['one', 1, 2.0, True, [0.1, 0.2, 0.3]]
  2. example_list[0] == 'one'
  3. example_list[1] == 1
  4. example_list[4][1] == 0.2
  5. example_list[5] = '5!' # присвоили значение новому элементу

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

  1. print len(example_list)

Срезы

С индексами все просто и понятно: если значение состоит из других значений, то необходим какой-то доступ к его составляющих.

Более интересной возможностью списков является взятие «среза»: помимо того, чтобы обращаться к отдельным элементам, можно выбирать целые фрагменты последовательности, образуя при необходимости новые списки.

    • example_list [i: j] — выберет все элементы списка с i-го (включительно) по j-й (исключая),
    • example_list [i:] — выберет все элементы списка с i-го (включительно) до конца,
    • example_list [: j] — выберет все элементы списка с января по j-й (исключая).

Если i или j отрицательные, отсчет для них будет проводиться с конца последовательности (кстати, то же касается отрицательных индексов). Проверьте, что выведут:

print example_list [-1]
example_list [1: 4]
example_list [1: 13]
example_list [4: 1]
example_list [: - 1]
example_list [-2:]

Также операцию среза можно применять и с 3 аргументами:

    • example_list [i: j: k] — выберет каждый k-й элемент списка с i-го (включительно) по j-й (исключая),
    • example_list [i :: k] — выберет каждый k-й элемент списка с i-го (включительно) до конца,
    • example_list [: j: k] — выберет каждый k-й элемент списка с января по j-й (исключительно),
    • example_list [:: k] — выберет каждый k-й элемент списка.

k также может быть отрицательным, что приведет к формированию нового списка с обратным порядком элементов. Проверьте сами: example_list [:: 2], example_list [4: 3], example_list [1 :: — 1], example_list [3: 0: -1].

Есть еще одна функция, которая работает похожим образом — это уже частично знакома вам range (), которая по сути создает список-срез последовательности целых чисел:

    • range (i) — возвращает список с числами от 0 (включительно) до i (исключая, то есть до и-1),
    • range (i, j) — возвращает список с числами от i (включительно) до j (исключая, то есть до j-1),
    • range (i, j, k) — возвращает список, содержащий каждое k-е число от и (включительно) до j (исключая, то есть до j-1).

Аналогично, i, j, k могут быть отрицательными числами.

Список аргументов командной строки. Возвращение

Вы уже знакомы с крайней мере одним списком. Это список аргументов sys.argv. Он содержит все значения, которые были записаны в командной строке для вызова программы, и, как это всегда бывает в программировании, начинает нумерацию своих элементов с 0.

Под номером (индексом) 0 находится имя запущенного файла. Под номером 1 — первое значение, под номером 2 — второе и др. Аргументы-значения отделяются пробелами и состоят интерпретатором в список sys.argv как строки. Если вам необходимо работать с ними как с данными другого типа, следует принудительно конвертировать тип данных. В случае если необходимо передать значение-строки, содержащие пробелы или другие знаки препинания, которые могут быть восприняты консолью или интерпретатором неадекватно, такие строки берутся в двойные кавычки.

Вы уже знакомы с крайней мере одним списком. Это список аргументов sys.argv. Он содержит все значения, которые были записаны в командной строке для вызова программы, и, как это всегда бывает в программировании, начинает нумерацию своих элементов с 0.

Под номером (индексом) 0 находится имя запущенного файла. Под номером 1 — первое значение, под номером 2 — второе и др. Аргументы-значения отделяются пробелами и состоят интерпретатором в список sys.argv как строки. Если вам необходимо работать с ними как с данными другого типа, следует принудительно конвертировать тип данных. В случае если необходимо передать значение-строки, содержащие пробелы или другие знаки препинания, которые могут быть восприняты консолью или интерпретатором неадекватно, такие строки берутся в двойные кавычки.

  1. import sys
  2. print sys.argv

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

  1. import sys
  2. sum = 0
  3. for arg in sys.argv[1:]: # перебрать все аргументы, исключив нулевой
  4.     sum = sum + int(arg) # не забыть конвертировать в число для прибавления
  5. print sum

Или определить количество переданных аргументов и вывести сообщение об ошибке в случае их недостатка:

  1. import sys
  2. if len(sys.argv) != 4:
  3.     print 'triangle should have 3 sides, please input 3 numbers'
  4. else:
  5.     print 'OK'

Циклы и разветвления

Цикл for

Пока он выглядел примерно так, и это, условно говоря, был цикл для того, чтобы повторить действие n раз:

  1. n = 10
  2. for i in range(n):
  3.     print i

Но, после рассмотрения списков и функции range (), становится понятно, что назначение цикла for несколько более общее — это обход последовательностей, например списков. Или строк. Так, строки представляют собой упорядоченные последовательности букв и работают похожим образом.

Так что нам не обязательно ограничиваться числами от 0 до N. Мы можем подготовить заранее любой список или строку и взять поэлементно. При этом на каждой итерации переменная-счетчик цикла приобретать значение следующего элемента последовательности:

  1. # letter последовательно получает значения каждого символа строки
  2. for letter in 'qwertyuiopasdfghjkl': 
  3.     print letter
  4. list_to_iterate = [1, 2, 3, 4, 8, 2, 43, 12, 31, 20]
  5. # element последовательно получает значения каждого символа списка
  6. for element in list_to_iterate: 
  7.     print element
  8. # element последовательно получает значения каждого второго элемента списка
  9. for element in list_to_iterate[::2]: 
  10.     print element

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

Хотя, если очень захотеть, и это, казалось бы, логичное ограничение можно обойти (но сделать это случайно труднее чем для цикла while):

  1. l = [0]
  2. for i in l:
  3.     l.append(i+1)

Цикл while

Цикл while позволяет так же перебирать последовательности:

  1. n = 10
  2. i = 0
  3. while i < 10:
  4.     print i
  5.     i = i + 1

или

  1. n = 10
  2. list_to_iterate = [1, 2, 3, 4, 8, 2, 43, 12, 31, 20]
  3. i = 0
  4. while i < len(list_to_iterate):
  5.     print list_to_iterate[i]
  6.     i = i + 1

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

  1. sum = 0
  2. i = 0
  3. while sum < 100:
  4.     i = i + 1
  5.     sum = sum + i

Цикл while продолжает повторять блок кода, пока значение условия равно True. И вы всегда должны быть уверены, что когда-то условие изменит свое значение и цикл закончится. Потому пропустить увеличение счетчика или просто ошибиться в условии намного проще чем «случайно» растянуть конечную последовательность в бесконечной.

Разветвления if .. else

Сокращенная форма if .. elif .. позволяет построить разветвления более чем на 2 ветви, не создавая для этого дополнительных уровней вложенности в коде программы.

  1. n = int(raw_input('Input n: '))
  2. if n &gt; 100:
  3.     print 'so large number!'
  4. elif n &gt; 10:
  5.     print 'ok, not bad'
  6. elif n == 0:
  7.     print 'tricky!'
  8. else:
  9.     print 'hey, what are you doing?'

Полезные функции, упрощенный вариант реализации шифра Цезаря

len (x) — возвращает длину последовательности x (списка или строки).

  1. print len('qweqweqweqw qwe qr qr ')
  2. print len([123.1, 32, 66, 23, 'q', 55, 2342])

range (x) — генерирует список целых значений от 0 до x-1.

range (x, y) — генерирует список целых значений от x до y-1.

range (x, y, z) — генерирует список целых значений от x до y-1 с шагом z.

  1. print range(1, 5, 2)  # [1, 3]
  2. print range(10, -5, -3) # [10, 7, 4, 1, -2]
  3. print range(10)  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  4. print range(66, 68)  # [66, 67]

x. append (y) — добавляет значение y в конец списка x.

  1. x = []
  2. x.append('first!')
  3. print x # ['first!']

x. reverse () — изменяет порядок элементов списка x на обратный.

  1. x = [1, 2, 3]
  2. x.reverse()
  3. print x # [3, 2, 1]

x. upper () — изменяет регистр всех символов строки x на верхней.

  1. print 'String'.upper() # 'STRING'

x. lower () — изменяет регистр всех символов строки x на нижней.

  1. print 'String'.lower() # 'string'

x. replace (substring_old, substring_new) — заменяет все вхождения фрагмента substring_old в строке x на substring_new

x.replace (substring_old, substring_new, count) — заменяет первые count вхождений фрагмента substring_old в строке x на substring_new

  1. message = "Good morning, man. What are you doing?"
  2. print message.replace("ng", "n’")
  3. # "Good mornin’, man. What are you doin’?"

x. find (substring) — возвращает позицию вхождения (индекс первого символа) фрагмента substring в строке x или -1, если фрагмент не найдены.

x.find (substring, start_pos)  — возвращает позицию вхождения (индекс первого символа) фрагмента substring в строке x начиная с позиции start_pos, или -1, если фрагмент не найдены.

  1. str1 = "this is string example....wow!!!"
  2. print str1.find("exam")
  3. print str1.find("exam", 10)

Пример на закрепление

Напишем программу, которая будет кодировать заданное сообщение шифром Цезаря  с заданным смещением. Для упрощения проигнорируем регистр символов и приведем весь текст к нижнему регистру.

# импорт модуля sys для чтения аргументов командной строки
import sys

# сохраним алфавит языка для поиска в нем и подстановки новых букв
alphabet = 'abcdefghijklmnopqrstuvwxyz'
# читаем текст, который следует закодировать; сразу меняем регистр
text = sys.argv[1].lower()
# читаем смещение для кодирования
shift = int(sys.argv[2])
# объявляем переменные для закодированного текста, закодированной отдельной буквы, и номера буквы в алфавите
coded_text = ''
new_letter = ''
letter_position = None

# пробегаем весь исходный текст
for letter in text:
    # ищем текущий символ в алфавите
    letter_position = alphabet.find(letter)
# если он там присутствует, высчитываем позицию закодированной буквы - со смещением - и выбираем букву алфавита с новым номером
    if letter_position != -1:
        new_letter = alphabet[(letter_position + shift) % len(alphabet)]
    # иначе оставляем символ без изменений (пробелы, знаки препинания и др.)
    else:
        new_letter = letter
    # добавляем символ к закодированного сообщения
    coded_text = coded_text + new_letter
# выводим
print coded_text

Вариант реализации шифра Цезаря на Pyton смотрите в другой нашей статье.

Задание 1

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

Результат работы : строка «YES», если полученная строка является палиндромом, или «NO» — если нет. Строка считается палиндромом, если он все равно читается как слева направо, так и справа налево. Отличием регистров и пробелами пренебречь.

Например:
Входные данные: 0 
Пример вызова: python lab4_1.py 0 
Результат: YES 
Входные данные: puppy 
Пример вызова: python lab4_1.py puppy 
Результат: NO 
Входные данные: «mystring1Gni rts ym» 
Пример вызова: python lab4_1.py «mystring1Gni rts ym » 
Результат: YES

Смотреть ответ:

Задание 2

Входные данные : произвольное, отличное от нуля, количество значений — аргументов командной строки. Значениями-аргументами могут быть числа или строки, состоящие из цифр и букв латинского алфавита без пробелов.

Результат работы : строка, состоящая из полученных значений в обратном порядке, записанных через пробел. Пробел в конце строки отсутствует.

Например
Входные данные: 1 
Пример вызова: python lab4_3.py 1 
Результаты: 1 
Входные данные: qwe asd zxc 123 
Пример вызова: python lab4_3.py qwe asd zxc 123 
Результат: 123 zxc asd qwe 
Входные данные: padawan young my HAVE MUST YOU PATIENCE 
пример вызова: python lab4_3.py padawan young my HAVE MUST YOU PATIENCE 
Результат: PATIENCE YOU MUST HAVE my young padawan

Смотреть ответ:

Задание 3

Входные данные : строка, состоящая из открывающих и закрывающих круглых скобок — аргумент командной строки. Для передачи в качестве строки последовательность берется в кавычки.

Результат работы : строка «YES», если входная строка содержит правильную скобочную последовательность; или строку «NO», если последовательность является неправильной. Скобочный последовательность считается правильной, если все скобки можно разбить попарно «открывающая» — «закрывающая», причем в каждой паре закрывающая скобка следует после открывающей.

Помощь для математиков: 
«» (пустая строка) — правильная скобочная последовательность (ПДП) 
«(ПДП)» — также ПДП 
«ПДППДП» (две ПДП записаны рядом) — также ПДП

Например
Входные данные: «) (» 
Пример вызова: python lab4_3.py «) (» 
Результат: NO 
Входные данные: «(() (()» 
Пример вызова: python lab4_3.py «(() (()» 
Результат: NO 
Входные данные: «(() (() () )) » 
Пример вызова: python lab4_3.py «(() (() () )) » 
Результат: YES 
Входные данные: «()) () (() ()) (() » 
Пример вызова: python lab4_3.py» ()) () (() ()) (() » 
Результат: NO

Смотреть ответ:

Задание 4

Задача предполагает поиск «счастливых» билетов. «Счастливым» называется такой троллейбусный билет, в котором сумма первых трех цифр равна сумме последних трех. Например 030111 (0 + 3 + 0 = 1 + 1 + 1), 902326 (9 + 0 + 2 = 3 + 2 + 6), 001100 (0 + 0 + 1 = 1 + 0 + 0).

Входные данные : два целых неотрицательных числа (0 <= a1 <= a2 <= 999999) — аргументы командной строки.

Результат работы : количество «счастливых билетов», чьи номера лежат в промежутке от a1 до a2 включительно. Если число в промежутке имеет менее 6 разрядов, считать, что в его начале дописываются нули в необходимом количестве, как это и происходит при нумерации билетов. Выводить номера билетов не надо.

Например
Входные данные: 0 1000 
Пример вызова: python lab4_4.py 0 1000 
Результаты: 1 
Пояснение: номер 000000 
Входные данные: 1001 1122 
Пример вызова: python lab4_4.py 1001 1122 
Результат: 3 
Пояснение: номера 001001, 001010, 001100 
Входные данные: 222222 222333 
Пример вызова: python lab4_4.py 222222 222333 
Результат: 7 
Пояснение: номера 222222, 222231, 222240, 222303, 222312, 222321, 222330

Смотреть ответ:

Читайте больше по теме:

Подписаться
Уведомление о
guest
0 комментариев
Inline Feedbacks
View all comments
Просмотры: 1145

Популярные записи