Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

31 KiB

Отчёт по теме 7: Создание пользовательских функций

Филиппов Даниил Юрьевич, А-01-23

1. Запуск интерактивной оболочки IDLE

>>> import os
>>> os.chdir('C:\\Users\\danii\\Desktop\\FilippovDY\\python-labs\\TEMA7')

Пользовательская функция – это совокупность инструкций, которая выполняется при обращении к функции из любого места программы. Аргументы функции – это ссылки на объекты-источники данных, которые используются при её выполнении. Возвращаемые данные – это результаты вычисления функции, передаваемые в ту часть программы, из которой была вызвана функция.

2. Создание пользовательской функции

Создание функции предполагает выполнение трех операций: формирование функции, ее сохранение и использование. В общем виде функция в языке Python представляется так: def <Имя функции>([<Список аргументов >]): [<отступы>"""<Комментарий по назначению функции>"""] <отступы><Блок инструкций – тело функции> [<отступы>return <Значение или вычисляемое выражение>]

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

2.1 Функция без аргументов

>>> def uspeh():
... 	"""Подтверждение успеха операции"""
... 	print('Выполнено успешно!')
... 
... 	
>>> uspeh()
Выполнено успешно!
>>> type(uspeh)
<class 'function'> # Функция является объектом класса function.
>>> dir()          # Имя функции появилось в пространстве имён
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'os', 'uspeh']
>>> help(uspeh)
Help on function uspeh in module __main__:

uspeh()
    Подтверждение успеха операции

help вывело справку по функции uspeh в модуле main. Далее выведена документационная строка функции (то описание, которое было указано в тройных кавычках при её определении). Документационная строка позволяет кратко и понятно описывать назначение функции.

2.2 Функция с аргументами

>>> def sravnenie(a,b):
... 	"""Сравнение a и b"""
... 	if a>b:
... 		print(a,' больше ',b)
... 	elif a<b:
... 		print(a, ' меньше ',b)
... 	else:
... 		print(a, ' равно ',b)
... 
>>> n,m=16,5;sravnenie(n,m)
16  больше  5

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

>>> n,m='aaa', 'bbbb';sravnenie(n,m)
aaa  меньше  bbbb

2.3 Функция, содержащая return

>>> def logistfun(b,a):
... 	"""Вычисление логистической функции"""
... 	import math
... 	return a/(1+math.exp(-b))
... 
>>> v,w=1,0.7;z=logistfun(w,v)
>>> z
0.6681877721681662

Модуль импортированный внутри функции будет доступен только внутри этой же функции.

2.4 Сложение для разных типов аргументов

>>> def slozh(a1,a2,a3,a4):
... 	""" Сложение значений четырех аргументов"""
... 	return a1+a2+a3+a4
... 
...     
>>> slozh(1,2,3,4)   # Сложение чисел
10

>>> slozh('1','2','3','4')  # Сложение строк
'1234'

>>> b1=[1,2];b2=[-1,-2];b3=[0,2];b4=[-1,-1]
>>> q=slozh(b1,b2,b3,b4)  #Сложение списков
>>> q
[1, 2, -1, -2, 0, 2, -1, -1]
>>> c1=(1,2); c2=(-1,-2); c3= (0,2); c4=(-1,-1)

>>> q=slozh(c1,c2,c3,c4)  #Сложение кортежей
>>> q
(1, 2, -1, -2, 0, 2, -1, -1)
q = slozh({1,1}, {2,2}, {"abc"}, {3,3}) # Сложение множеств
Traceback (most recent call last):
  File "<pyshell#36>", line 1, in <module>
    q = slozh({1,1}, {2,2}, {"abc"}, {3,3})
  File "<pyshell#26>", line 3, in slozh
    return a1+a2+a3+a4
TypeError: unsupported operand type(s) for +: 'set' and 'set'

>>> dict1 = {'a': 1}; dict2 = {'b': 2}; dict3 = {'c': 3}; dict4 = {'d': 4} 
>>> slozh(dict1, dict2, dict3, dict4) # Сложение словарей
Traceback (most recent call last):
  File "<pyshell#38>", line 1, in <module>
    slozh(dict1, dict2, dict3, dict4)
  File "<pyshell#26>", line 3, in slozh
    return a1+a2+a3+a4
TypeError: unsupported operand type(s) for +: 'dict' and 'dict'

slozh(1, "а", 2, "b") # Сложение числа и строки
Traceback (most recent call last):
  File "<pyshell#39>", line 1, in <module>
    slozh(1, "а", 2, "b")
  File "<pyshell#26>", line 3, in slozh
    return a1+a2+a3+a4
TypeError: unsupported operand type(s) for +: 'int' and 'str'

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

2.5 Функция, реализующая модель некоторого устройства, на вход которого в текущий момент поступает сигнал х, на выходе получается сигнал y:

>>> def inerz(x,T,ypred):
... 	""" Модель устройства с памятью:
...     x- текущее значение вх.сигнала,
... 	T -постоянная времени,
... 	ypred - предыдущее значение выхода устройства"""
... 	y=(x+T*ypred)/(T+1)
... 	return y
... 
>>> sps=[0]+[1]*100 # Список с измерениями значений входного сигнала – в виде «ступеньки»
>>> spsy=[] #Заготовили список для значений выхода
>>> TT=20 #Постоянная времени
>>> yy=0  #Нулевое начальное условие
>>> for xx in sps:
... 	yy=inerz(xx,TT,yy)
... 	spsy.append(yy)
>>> import pylab as plt
>>> plt.plot(spsy, label = "Выходной сигнал")
[<matplotlib.lines.Line2D object at 0x000002AC6E77CB90>]
>>> plt.show()

График сохранён в файле Figure_1.png График

3. Функции как объекты

3.1 Получение списка атрибутов объекта-функции

>>> dir(inerz)
['__annotations__', '__builtins__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__getstate__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__type_params__']
>>> inerz.__doc__
'Модель устройства с памятью:\n        x- текущее значение вх.сигнала,\nT -постоянная времени,\nypred - предыдущее значение выхода устройства'
>>> help(inerz)
Help on function inerz in module __main__:

inerz(x, T, ypred)
    Модель устройства с памятью:
            x- текущее значение вх.сигнала,
    T -постоянная времени,
    ypred - предыдущее значение выхода устройства

Этот атрибут doc содержит значение docstring, если при инициализации функции он был задан. Если не был, то inerz.doc будет иметь значение None.

3.2 Сохранение ссылки на объект-функции в другой переменной

>>> fnkt=sravnenie
>>> v=16
>>> fnkt(v,23)
16  меньше  23

Функции можно передавать в переменные, как и любые другие объекты. После этого переменная fnkt ссылается на ту же самую функцию, что и sravnenie.

3.3 Возможность альтернативного определения функции в программе

>>> typ_fun=8
>>> if typ_fun==1:
... 	def func():
... 		print('Функция 1')
... else:
... 	def func():
... 		print('Функция 2')
... 
>>> func()
Функция 2

Программа выводит сообщение "Функция 2", потому что переменная typ_fun не равна 1, и выполняется блок else, в котором функция func определена как выводящая "Функция 2".

4. Аргументы функции

4.1 Возможность использования функции в качестве аргумента другой функции

>>> def fun_arg(fff,a,b,c):
... 	"""fff-имя функции, используемой 
... 	в качестве аргумента функции fun_arg"""
... 	return a+fff(c,b)
... 
>>> zz=fun_arg(logistfun,-3,1,0.7)
>>> zz
-2.3318122278318336

Python передаёт ссылку на объект функции logistfun в переменную fff. Внутри функции выполняется заданная операция.

4.2 Обязательные и необязательные аргументы

>>> def logistfun(a,b=1):   #Аргумент b – необязательный; значение по умолчанию=1
... 	"""Вычисление логистической функции"""
... 	import math
... 	return b/(1+math.exp(-a))
... 
...     
>>> logistfun(0.7)     #Вычисление со значением b по умолчанию
0.6681877721681662
>>> logistfun(0.7,2)  #Вычисление с заданным значением b
1.3363755443363323

4.3 Возможность обращения к функции с произвольным (непозиционным) расположением аргументов

При этом надо в обращении к функции указывать имена аргументов.

>>> logistfun(b=0.5,a=0.8)  # Ссылки на аргументы поменялись местами
0.34498724056380625

4.4 Пример со значениями аргументов функции, содержащимися в списке или кортеже

>>> b1234=[b1,b2,b3,b4]  # Список списков из п.2.4
>>> b1234
[[1, 2], [-1, -2], [0, 2], [-1, -1]]
>>> qq=slozh(*b1234)  #Перед ссылкой на список или кортеж надо ставить звездочку
>>> qq
[1, 2, -1, -2, 0, 2, -1, -1]

Со звёздочкой коллекции передаются как набор аргументов функции. Это - "оператор распаковки". Это было бы эквивалентно записи slozh(b1,b2,b3,b4).

4.5 Пример со значениями аргументов функции, содержащимися в словаре

>>> dic4={"a1":1,"a2":2,"a3":3,"a4":4}
>>> qqq=slozh(**dic4)  #Перед ссылкой на словарь надо ставить две звездочки
>>> qqq
10
>>> slozh(*dic4)
'a1a2a3a4'

Ключи на входе функции воспринимаются как значения позиционных переменных, а значения, как значения. Если поставить только одну звездочку, python попытается интерпретировать ключи, а не значения словаря как позиционные аргументы.

4.6 Смешанные ссылки

>>> e1=(-1,6);dd2={'a3':3,'a4':9}
>>> qqqq=slozh(*e1,**dd2)
>>> qqqq
17

4.7 Переменное число аргументов у функции

>>> def func4(*kort7):
... 	"""Произвольное число аргументов в составе кортежа"""
... 	smm=0
... 	for elt in kort7:
... 		smm+=elt
... 	return smm
... 
>>> func4(-1,2)  #Обращение к функции с 2 аргументами
1
>>> func4(-1,2,0,3,6)  #Обращение к функции с 5 аргументами
10

4.8 Комбинация аргументов

>>> def func4(a,b=7,*kort7): #Аргументы: a-позиционный, b- по умолчанию + кортеж
... 	"""Кортеж - сборка аргументов - должен быть последним!"""
... 	smm=0
... 	for elt in kort7:
... 		smm+=elt
... 	return a*smm+b
... 
>>> func4(-1,2,0,3,6)
-7

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

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

>>> def func4(a,b=7,**dct1): #Аргументы: a-позиционный, b- по умолчанию + кортеж
... 	"""Словарь - сборка аргументов - должен быть последним!"""
... 	smm=0
... 	smm = sum (dct1.values())
... 	return a*smm + b
...     
>>> func4(-1,2, x=3, y=4, z=5)
-10

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

*args всегда должно идти перед **kwargs.

4.9 Изменение значений объектов, используемых в качестве аргументов функции

Такое изменение возможно только у объектов изменяемого типа

>>> a=90    # Числовой объект – не изменяемый тип
>>> def func3(b):
... 	b=5*b+67
... 
>>> func3(a)
>>> a
90

Поскольку функция ничего не возвращает то вычисленное значение b = 5*b+67 существует только локально внутри нее и не выносится в глобальную область видимости.

Пример со списком:

>>> sps1=[1,2,3,4]  #Список – изменяемый тип объекта
>>> def func2(sps):
... 	sps[1]=99
... 
>>> func2(sps1)
>>> print(sps1)
[1, 99, 3, 4]

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

Пример с кортежем:

kort = (1,2,3,4)
func2(kort)
Traceback (most recent call last):
  File "<pyshell#113>", line 1, in <module>
    func2(kort)
  File "<pyshell#109>", line 2, in func2
    sps[1]=99
TypeError: 'tuple' object does not support item assignment

Кортеж - неизменяемая коллекция, так что переназначение в таком виде не работает.

5. Специальные типы пользовательских функций

5.1 Анонимные функции

Анонимные функции или по-другому их называют лямбда-функциями – это функции без имени, определяемые по следующей схеме: lambda [<Аргумент1>[,<Аргумент2>,…]]:<Возвращаемое значение или выражение> Анонимная функция возвращает ссылку на объект-функцию, которую можно присвоить другому объекту.

>>> import math
>>> anfun1=lambda: 1.5+math.log10(17.23)  #Анонимная функция без аргументов
>>> anfun1()   # Обращение к объекту-функции
2.7362852774480286
>>> anfun2=lambda a,b : a+math.log10(b)  #Анонимная функция с 2 аргументами
>>> anfun2(17,234)
19.369215857410143
>>> anfun3=lambda a,b=234: a+math.log10(b) #Функция с необязательным вторым аргументом
>>> anfun3(100)
102.36921585741014

Вызов лямбда-функции создает объект класса "функция", который потом можно положить в другую переменную и далее вызывать. Это необязательно, если она используется один раз, можно вызвать ее сразу. Внутри лямбда-функции не могут использоваться многострочные выражения, нельзя использовать if-else.

5.2 Функции-генераторы

Это – такие функции, которые используются в итерационных процессах, позволяя на каждой итерации получать одно из значений. Для этого в функцию включают инструкцию yield приостанавливающую её выполнение и возвращающую очередное значение. Данный оператор в отличие от return не останавливает полностью выполнение программы. Когда выполнение функции возобновляется после yield, оно продолжается с того места, где было приостановлено, до следующего оператора yield (или до конца функции).

>>> def func5(diap,shag):
... 	""" Итератор, возвращающий значения
... 	из диапазона от 1 до diap с шагом shag"""
... 	for j in range(1,diap+1,shag):
... 		yield j
... 
>>> for mm in func5(7,3):
	      print(mm)
...
...	
1
4
7

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

>>> alp=func5(7,3)
... 
>>> print(alp.__next__())
1
>>> print(alp.__next__())
4
>>> print(alp.__next__())
7
>>> print(alp.__next__())
Traceback (most recent call last):
  File "<pyshell#131>", line 1, in <module>
    print(alp.__next__())
StopIteration

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

6. Локализация объектов в функциях

По отношению к функции все объекты подразделяются на локальные и глобальные. Локальными являются объекты, которые создаются в функциях присваиванием им некоторых значений. Глобальные – это те объекты, значения которых заданы вне функции. Локализация может быть переопределена путем прямого объявления объектов как глобальных с помощью дескриптора global.

6.1 Примеры на локализацию объектов

Пример 1. Одноименные локальный и глобальный объекты:

>>> glb=10
>>> def func7(arg):
... 	loc1=15
... 	glb=8
... 	return loc1*arg
... 
>>> res=func7(glb)
>>> res
150
>>> glb
10

Внутри функции glb принял значение 8, но глобальная переменная при этом после выполнения функции значения не поменяла. Это происходит потому, что технически, локальный glb и глобальный glb - это два разных объекта.

Пример 2. Ошибка в использовании локального объекта.

>>> def func8(arg):
... 	loc1=15
... 	print(glb)  
... 	glb=8
... 	return loc1*arg
... 
...     
>>> res=func8(glb)
Traceback (most recent call last):
  File "<pyshell#9>", line 1, in <module>
    res=func8(glb)
  File "<pyshell#8>", line 3, in func8
    print(glb)
UnboundLocalError: cannot access local variable 'glb' where it is not associated with a value

Переменной glb присваивается значение внутри функции. Поэтому python решает, что glb - это локальная переменная для всей функции. Но когда выполнение доходит до строки 3 print(glb), локальная переменная glb еще не была инициализирована (это происходит только в строке 4).

Пример 3. Переопределение локализации объекта.

>>> glb=11
>>> def func7(arg):
... 	loc1=15
... 	global glb
... 	print(glb)
... 	glb=8
... 	return loc1*arg
... 
...     
>>> res=func7(glb)
11
>>> glb
8

Здесь мы явно указали, что в функции используем глобальную переменную, поэтому она изменилась.

6.2 Выявление локализации объекта с помощью функций locals() и globals() из builtins

Эти функции возвращают словари, ключами в которых будут имена объектов, являющихся, соответственно, локальными или глобальными на уровне вызова этих функций.

>>> globals().keys()  #Перечень глобальных объектов
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', 'os', 'glb', 'func7', 'res', 'func8'])
>>> locals().keys()  #Перечень локальных объектов
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', 'os', 'glb', 'func7', 'res', 'func8'])

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

>>> def func8(arg):
... 	loc1=15
... 	glb=8
... 	print(globals().keys())  #Перечень глобальных объектов «изнутри» функции
... 	print(locals().keys())  #Перечень локальных объектов «изнутри» функции
... 	return loc1*arg
... 
>>> hh=func8(glb)
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', 'os', 'glb', 'func7', 'res', 'func8']) # Глобальное glb
dict_keys(['arg', 'loc1', 'glb']) # Локальное glb
>>> 'glb' in globals().keys()
True

6.3 Локализация объектов при использовании вложенных функций

>>> def func9(arg2,arg3):
... 	def func9_1(arg1):
... 		loc1=15
... 		glb1=8
... 		print('glob_func9_1:',globals().keys())
... 		print('locl_func9_1:',locals().keys())
... 		return loc1*arg1
... 	loc1=5
... 	glb=func9_1(loc1)
... 	print('loc_func9:',locals().keys())
... 	print('glob_func9:',globals().keys())
... 	return arg2+arg3*glb
... 
...     
>>> kk=func9(10,1)
glob_func9_1: dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', 'os', 'glb', 'func7', 'res', 'func8', 'hh', 'func9'])
locl_func9_1: dict_keys(['arg1', 'loc1', 'glb1']) # # Содержит только объекты, определенные внутри func9_1, а также объект, переданный как аргумент функции
loc_func9: dict_keys(['arg2', 'arg3', 'func9_1', 'loc1', 'glb']) # # Содержит все то же, что и locl_func9_1, но еще и arg3, переданный func9, и саму func9_1
glob_func9: dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', 'os', 'glb', 'func7', 'res', 'func8', 'hh', 'func9'])

6.4 Моделирование системы

Моделирование системы, состоящей из последовательного соединения реального двигателя, охваченного отрицательной обратной связью с тахогенератором в ней, и нелинейного звена типа «зона нечувствительности», при подаче на неё синусоидального входного сигнала. Реальный двигатель: последовательное соединение усилителя с коэффициентом усиления k1,интегратора: y(t)=x(t)+y(t-1), и инерционного звена: y(t)=(x(t)+T*y(t-1)) / (T+1) с постоянной времени Т. Тахогенератор: последовательное соединение усилителя с коэффициентом усиления k2 и интегратора: y(t)=x(t)+y(t-1). Нелинейное звено типа «зона нечувствительности»: y=0 при -xm≤ x ≤xm, y=x-xm при x>xm, y=x+xm при x<-xm. Таким образом, система характеризуется параметрами: k1, T, k2, xm. Входной сигнал характеризуется параметрами: A (амплитуда синусоиды) и F (период синусоиды). Еще один параметр задачи : N – время (число тактов) подачи сигнала.

Решение задачи:

>>> znach=input('k1,T,k2,Xm,A,F,N=').split(',') # Запрос и введение параметров задачи
k1,T,k2,Xm,A,F,N=8,5,3,10,2,0.5,1000
>>> k1=float(znach[0]) # Распаковка значений из списка в отдельные объекты
>>> T=float(znach[1])
>>> k2=float(znach[2])
>>> Xm=float(znach[3])
>>> A=float(znach[4])
>>> F=float(znach[5])
>>> N=int(znach[6])
>>> import math
>>> vhod=[]
>>> for i in range(N): 
...         vhod.append(A*math.sin((2*i*math.pi)/F)) # Создание реализации входного сигнала
...
>>> vhod
[0.0, -9.797174393178826e-16, -1.959434878635765e-15, -2.9391523179536475e-15, -3.91886975727153e-15, -4.898587196589413e-15, -5.878304635907295e-15, -6.858022075225178e-15, -7.83773951454306e-15, -8.817456953860943e-15, -9.797174393178826e-15, -3.919860126290071e-14, -1.175660927181459e-14, 1.5685382719271533e-14, -1.3716044150450356e-14, -4.3117471020172244e-14, -1.567547902908612e-14, 1.1766512962000004e-14, -1.7634913907721887e-14, ...]

# Создание функций реализующие компоненты системы
>>> def realdvig(xtt,kk1,TT,yti1,ytin1):
... 		#Модель реального двигателя
... 		yp=kk1*xtt  #усилитель
... 		yti1=yp+yti1  #Интегратор
... 		ytin1=(yti1+TT*ytin1)/(TT+1)
... 		return [yti1,ytin1]
... 	    
>>> def tahogen(xtt,kk2,yti2):
... 		#Модель тахогенератора
... 		yp=kk2*xtt   #усилитель
... 		yti2=yp+yti2 #интегратор
... 		return yti2
... 	    
>>> def nechus(xtt,gran):
... #зона нечувствит
... 	if xtt<gran and xtt>(-gran):
... 		ytt=0
... 	elif xtt>=gran:
... 		ytt=xtt-gran
... 	elif xtt<=(-gran):
... 		ytt=xtt+gran
... 	return ytt
... 

# Реализуем соединение компонент в соответствии с заданием
>>> yi1=0;yin1=0;yi2=0
>>> vyhod=[]
>>> for xt in vhod:
... 		xt1=xt-yi2   #отрицательная обратная связь
... 		[yi1,yin1]=realdvig(xt1,k1,T,yi1,yin1)
... 		yi2=tahogen(yin1,k2,yi2)
... 		yt=nechus(yin1,Xm)
... 		vyhod.append(yt)
... 
>>> print('y=',vyhod)
y= [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1.0183086292055208, 0, 26.39885775889784, -36.65029553691161, -34.19982663883278, 196.29963397615063, -151.6919482160481, -388.32493988337274, 1057.8073200868555, -308.3186572590445, -2798.051869998873, 5004.749701095182, 1362.331454336744, ...]    

7. Завершение сеанса работы с IDLE