20 KiB
		
	
	
	
			
		
		
	
	Тема 5. Блоки инструкций, управляющие инструкции
Выполнил: Тимошенко А.А. Проверил: Козлюк Д. А.
Пункт 1.
>>> import os
>>> os.chdir("C:/Users/mapon/OneDrive/Рабочий стол/ПО АС/ТЕМА5")
Пункт 2. Ветвление по условию (if)
Общий вид выглядит так:
if <условие>: <отступы> <Блок инструкций, выполняемый, если условие истинно> [elif <условие2>: <отступы><Блок инструкций2, выполняемый, если условие2 истинно> ] [else: < отступы><Блок инструкций3, выполняемый, если условие ложно> ]
Причем elif и else вместе или по отдельности могут отсуствовать.
Пример:
>>> porog = 6
>>> rashod1 = 8
>>> rashod2 = 5
>>> if rashod1 >= porog:
	dohod = 12  # Это выполняется, если rashod1 >= porog
elif rashod2 == porog:
	dohod = 0   # Это выполняется, если первое условие ложно, но rashod2 == porog
else:
	dohod = -8  # Это выполняется, если ни первое, ни второе условие не были истинными
	
>>> dohod
12
Оператор rashod1 >= porog (например, в числах, 8 >= 5) возвращает логическое значение True, поэтому будет выполняться блок инструкций, соответствующий этому условию. Важно понимать, что в конструкции if-elif-else всегда выполняется только одна ветвь. Даже если условие в elif также истинно, оно не будет проверено и, соответственно, не выполнится, если до этого уже выполнился блок if. Это связано с тем, что после выполнения любого блока инструкции (будь то if, elif или else) остальные части конструкции игнорируются.
Перезададим некоторые значения и выполним другую управляющую инструкцию:
>>> rashod2 = 4
>>> porog = 4
>>> if rashod1 >= 3 and rashod2 == 4:  #Верно
	dohod = rashod1
	if rashod2 == porog or rashod1 < rashod2: #Тоже верно
		dohod = porog
>>> dohod
4
В данном случае выполняются оба if, потому что один находится в блоке инструкций другого вложенное условие). Вложенное условие будет проверяться в любом случае, если выполнилось внешнее.
>>> if porog == 3: #Неверно
	dohod = 1
elif porog == 4:   #Верно
	dohod = 2
elif porog == 5:   #Игнорируется
	dohod = 3
else:              #Игнорируется
	dohod = 0
>>> dohod
2
Еще одна форма записи условных управляющих инструкций - тернарный оператор (от лат. "тройной"):
<Объект> = <значение 1> if <условие> else <значение 2>
>>> dohod = 2 if porog >= 4 else 0
>>> dohod
2
Если в блоке инструкций всего одна строка, можно записать всё в одну строку:
>>> porog = 2
>>> if porog >= 5 : rashod1 = 6; rashod2 = 0
>>> rashod1
8
>>> rashod2
4
Поскольку сейчас значение porog было задано таким, чтобы не удовлетворять условию, то эта строка полностью не была выполнена и не повлияла на значения переменных. Но в другом случае:
>>> porog = 7
>>> if porog >= 5 : rashod1 = 6; rashod2 = 0
>>> rashod1
6
>>> rashod2
0
Выполняется условие и выполняются инструкции.
Пункт 3. Цикл по перечислению (for)
for <Объект-переменная цикла> in <объект>: <отступы> <Блок инструкций 1 – тело цикла> [else: <отступы> <Блок инструкций 2 – если в цикле не сработал break>]
В качестве объекта сойдёт любая коллекция или, например, диапазон range. Если сообщить словарь, то будут перебираться его ключи. Если сообщить множество, перебор будет осуществлен, но порядок будет неочевидным.
Пункт 3.1. Простой цикл.
>>> temperatura = 5
>>> for i in range(3,18,3):
	temperatura += i
>>> temperatura
50
Пункт 3.2. Более сложный цикл.
>>> sps=[2,15,14,8]
>>> for k in sps:
	if len(sps) <= 10: sps.append(sps[0])
	else: break
	
>>> sps
[2, 15, 14, 8, 2, 2, 2, 2, 2, 2, 2]
Как видно, в конец цикла добавляется двойка до тех пор, пока длина не превысит 10. Важно понимать, что sps - это и объект, по которому проходит k, и объект, изменяющийся внутри цикла. То есть k будет двигаться по циклу бесконечно, и выполнение останавливается именно из-за условия if - else. (При этом else в данном случае относится к if, а не к for (это можно понять не только по смыслу, но и по табуляции)
Рассмотрим другой вариант:
>>> sps=[2,15,14,8]
>>> for k in sps[:]:
	if len(sps)<=10:
		sps.append(sps[0])
	else: break
>>> sps
[2, 15, 14, 8, 2, 2, 2, 2]
Как видно, итог другой, и вот почему. Операция взятия среза sps[:] создает полную копию исходного списка (грубо говоря, срез от начала до конца включительно). Теперь список, по которому пробегается k, и список, изменяющийся внутри цикла - это объекты, имеющие разные адреса. Это можно проверить:
>>> id(sps)
1684034116672
>>> id(sps[:])
1684069134400
Следовательно, else не успеет сработать, потому что итерируемый в управляющей инструкции объект окажется короче и завершит цикл раньше:
Пункт 3.3
>>> import random as rn
>>> sps5 = []
>>> for i in range(10):
	sps5.append(rn.randint(1,100))
	ss = sum(sps5)
	if ss > 500: break
else:
	print(ss)
Программа ничего не вывела. Посмотрим, почему именно:
>>> ss
501
>>> sps5
[25, 66, 4, 30, 8, 97, 87, 11, 51, 57, 65]
После того, как прошло одиннадцать итераций, сумма элементов списка уже была больше 500, поэтому цикл закончился из-за if, а не из-за окончания диапазона range(10).
Попробуем обнулить список и выполнить ту же программу еще раз:
>>> sps5 = []
>>> for i in range(10):
	sps5.append(rn.randint(1,100))
	ss = sum(sps5)
	if ss > 500: break
else:
	print(ss)
436
В этот раз программа вывела ответ самостоятельно, потому что сработал else, потому что за все десять итераций цикла так и не успел выполниться break по условию if.
Примечание: Рассмотрим строку >>> import random as rn Если мы попробуем вызвать функцию из этого модуля по ее исходному названию, ничего не выйдет:
>>> random.randint(4,7)
Traceback (most recent call last):
  File "<pyshell#105>", line 1, in <module>
    random.randint(4,7)
NameError: name 'random' is not defined
Так происходит потому, что на этапе преобразования программы в байт-код python связывает модуль random, найденный где-то в каталогах, принадлежащих python, с именем rs. Модуль random становится объектом в пространстве имен, создаётся ссылка на объект модуля random и ему присваивается имя rn. Но имя random ему НЕ присваивается, поэтому обратиться к методам и атрибутам по имени random нельзя.
Пункт 3.4. Пример с символьной строкой
>>> stroka = 'Это – автоматизированная система'
>>> stroka1 = ""
>>> for ss in stroka:
	stroka1 += " " + ss
	
>>> stroka1
' Э т о   –   а в т о м а т и з и р о в а н н а я   с и с т е м а'
Переменная ss проходит по всему строковому объекту, на каждой итерации принимая значение одного знака. Этот знак с предшествующим пробелом дописывается в конец другой, изначально пустой строки. Цикл закончится, когда закончится исходная строка.
Пункт 3.5. Запись цикла в строке
>>> import math
>>> sps2=[math.sin(i*math.pi/5+2) for i in range(100)]
>>> sps2
[0.9092974268256817, 0.49103209793281005, -0.11479080280322804, -0.6767675184643197, -0.9802420445539634, -0.9092974268256817, -0.49103209793281016, 0.11479080280322791, 0.6767675184643196, 0.9802420445539634, 0.9092974268256818, 0.4910320979328103, -0.1147908028032278, -0.6767675184643196, -0.9802420445539632, -0.9092974268256818, -0.4910320979328104, 0.11479080280322768, 0.6767675184643195, 0.9802420445539632, 0.9092974268256819, 0.4910320979328105, -0.11479080280322579, -0.6767675184643194, -0.9802420445539632, -0.9092974268256819, -0.4910320979328106, 0.11479080280322743, 0.6767675184643193, 0.9802420445539632, 0.909297426825682, 0.49103209793281066, -0.1147908028032273, -0.6767675184643192, -0.9802420445539632, -0.909297426825682, -0.4910320979328108, 0.11479080280322719, 0.6767675184643192, 0.9802420445539631, 0.9092974268256822, 0.491032097932814, -0.11479080280322707, -0.676767518464319, -0.9802420445539625, -0.9092974268256822, -0.491032097932811, 0.11479080280323047, 0.6767675184643189, 0.9802420445539625, 0.9092974268256822, 0.4910320979328142, -0.11479080280322682, -0.6767675184643215, -0.9802420445539631, -0.9092974268256808, -0.4910320979328112, 0.11479080280322317, 0.6767675184643187, 0.9802420445539624, 0.9092974268256823, 0.4910320979328082, -0.11479080280322658, -0.6767675184643213, -0.980242044553963, -0.9092974268256838, -0.49103209793281144, 0.11479080280322293, 0.6767675184643186, 0.9802420445539637, 0.9092974268256824, 0.49103209793280844, -0.11479080280322633, -0.6767675184643158, -0.980242044553963, -0.9092974268256839, -0.49103209793281166, 0.11479080280322974, 0.6767675184643184, 0.9802420445539637, 0.9092974268256825, 0.4910320979328149, -0.11479080280321903, -0.6767675184643209, -0.9802420445539629, -0.909297426825681, -0.4910320979328119, 0.11479080280322244, 0.6767675184643129, 0.9802420445539636, 0.9092974268256826, 0.49103209793281505, -0.11479080280322584, -0.6767675184643155, -0.9802420445539644, -0.9092974268256812, -0.49103209793281205, 0.1147908028032222, 0.6767675184643127, 0.980242044553965]
Такая конструкция называется list comprehention (генератор списков). В общем виде она выглядит так:
<итоговый список> = [<выражение> for <элемент> in <исходный объект> if <условие>]
Эту синусоиду можно отобразить на графике:
>>> import pylab
>>> pylab.plot(sps2, label='Синусоидальный сигнал', color = 'green')
[<matplotlib.lines.Line2D object at 0x0000018834CBB460>]
>>> pylab.show()
Полученный график корректен и и сохранен в файле Figure_1
Пункт 4. Цикл "пока истинно условие" (while)
Общий вид:
while <Условие>:
<отступы><Блок инструкций 1 – тело цикла>
[else:
<отступы><Блок инструкций 2 – если в цикле не сработал break>]
break и else работают аналогично предыдущему случаю.
Пункт 4.1. Цикл со счетчиком
>>> rashod = 300
>>> while rashod:
	print("Расход =",rashod)
	rashod -= 50
Расход = 300
Расход = 250
Расход = 200
Расход = 150
Расход = 100
Расход = 50
Как именно произошло завершение цикла? Нужно вспомнить, что все числа, кроме нуля, при конвертации в логический тип данных имеют логическое значение True:
>>> bool(50)
True
И только нуль имеет значение False:
>>> bool(0)
False
Сравниваемая в управляющей инструкции переменная уменьшается в самом цикле, поэтому, когда строка со сравнением обнаружит 0, то воспримет это как False, и действия по выводу и уменьшению числа выполняться больше не будут.
Пункт 4.2. Пример с символьной строкой
>>> import math
>>> stroka='Расчет процесса в объекте регулирования'
>>> i=0
>>> sps2=[]
>>> while i<len(stroka):
	r=1-2/(1+math.exp(0.1*i))
	sps2.append(r)
	print('Значение в момент',i,"=",r)
	i+=1
	
Значение в момент 0 = 0.0
Значение в момент 1 = 0.049958374957880025
Значение в момент 2 = 0.09966799462495568
Значение в момент 3 = 0.14888503362331795
...
Значение в момент 37 = 0.9517459571646616
Значение в момент 38 = 0.9562374581277391
У цикла 38 повторений, по числу элементов в строке, но на 1 меньше. На каждой итерации значение i на единицу меньше, чем в предыдущей.
>>> pylab.plot(sps2, label='Сигнал выхода', color='red')
[<matplotlib.lines.Line2D object at 0x00000188336D9FA0>]
>>> pylab.title("Сигнал на выходе инерционного звена")
Text(0.5, 1.0, 'Сигнал на выходе инерционного звена')
>>> pylab.show()
График сохранен под именем Figure_2.
Пункт 4.3. Определение, является ли число простым (делится только на самого себя или 1).
>>> chislo = 267
>>> kandidat = chislo // 2
>>> while kandidat > 1:
	if chislo % kandidat == 0:
		print(chislo, ' имеет множитель ', kandidat)
		break
	kandidat -= 1
else:
	print(chislo, ' является простым!')
	
267  имеет множитель  89
Программа работает так: переменная kandidat отвечает за потенциальный делитель заданного числа. Изначально мы задаем половину от заданного числа, потому что у числа не может быть делителя большего, чем половина от него. Далее мы последовательно уменьшаем потенциальный множитель, каждый раз проверяя, получилось ли поделить без остатка. Если получилось, то число непростое, и цикл можно прекращать досрочно. Если цикл отработал до конца, не прервавшись, то число простое.
Дополниим программу так, чтобы она проверяла все числа от 250 до 300.
>>> chislo = [x for x in range (250, 301)]
>>> for now in chislo:
	kandidat = now // 2
	while kandidat > 1:
		if now % kandidat == 0:
			print(now, ' имеет множитель ', kandidat)
			break
		kandidat -= 1
	else:               #ОБЯЗАТЕЛЬНО относится не к if и не к for, а к while
		print(now, " является простым!")
		
250  имеет множитель  125
251  является простым!
252  имеет множитель  126
253  имеет множитель  23
254  имеет множитель  127
255  имеет множитель  85
256  имеет множитель  128
257  является простым!
258  имеет множитель  129
259  имеет множитель  37
260  имеет множитель  130
261  имеет множитель  87
262  имеет множитель  131
263  является простым!
264  имеет множитель  132
265  имеет множитель  53
266  имеет множитель  133
267  имеет множитель  89
268  имеет множитель  134
269  является простым!
270  имеет множитель  135
271  является простым!
272  имеет множитель  136
273  имеет множитель  91
274  имеет множитель  137
275  имеет множитель  55
276  имеет множитель  138
277  является простым!
278  имеет множитель  139
279  имеет множитель  93
280  имеет множитель  140
281  является простым!
282  имеет множитель  141
283  является простым!
284  имеет множитель  142
285  имеет множитель  95
286  имеет множитель  143
287  имеет множитель  41
288  имеет множитель  144
289  имеет множитель  17
290  имеет множитель  145
291  имеет множитель  97
292  имеет множитель  146
293  является простым!
294  имеет множитель  147
295  имеет множитель  59
296  имеет множитель  148
297  имеет множитель  99
298  имеет множитель  149
299  имеет множитель  23
300  имеет множитель  150
Пункт 4.4. Инструкция continue.
Она используется, когда надо при определенном условии не завершить весь цикл, а завершить только текущую итерацию.
Пример (вывести только положительные числа):
>>> nums = [rn.randint(-30, 30) for x in range(15)]
>>> nums
[-11, -1, 25, -11, 12, 24, -28, -16, -2, 15, -25, -2, -15, 9, -4]
>>> for now in nums:
	if now < 0: continue
	print(now, " > 0")
else: print("все числа обработаны")
25  > 0
12  > 0
24  > 0
15  > 0
9  > 0
все числа обработаны