Функции
Удобство: форматные строки
Проблема повторного использования
- Почему копипаста это плохо ☺
- тиражирование исправлений и изменений
- параметры
Пример: сумма площадей двух треугольников по их сторонам.
- Одна и та же формула для разных переменных
- Двойная проверка на неравенство треугольника
Функция
Именованная запись алгоритма с параметрами и результатом:
Функция обычно возвращает результат, который можно использовать в выражениях. Результат возвращается из функции немедленно при выполнении оператора return в теле функции.
Вычислить площадь треугольника по трём сторонам, а если треугольника не существует, то вернуть 0
TODO
Именование параметров
Определение функции содержит формальные параметры — имена, которые будут использоваться для алгоритма на время работы функции
Вызов функции содержит фактические параметры — выражения, которые будут вычислены, а результаты — переданы в функцию, чтобы она их там поименовала и работала с ними.
Пример
Пространство имён — место где лежат имена :). Возвращается dir()
Видимость имён: локальные locals() ~= dir() и глобальные globals()
- Пространства имён не сообщаются!
Пример на pythontutor ⇒ Локальные и глобальные переменные могут называться одинаково
Правило поиска имён внутри функции
- В локальном пространстве
Если это имя не найдено, и не участвует в связывании (в функции не написано имя = что-то) — в глобальном
(Иначе — только в локальном). Например, c в примере
Пример с площадями треугольников
Duck typing
Объекты в Python строго типизируемы. Нет возможности проделать операцию над объектом некоторого типа, если для него она не определена, даже если для объектов другого типа она есть
- Например, нельзя непосредственно сложить строку с числом, хотя есть преобразование строки в число и сложение двух строк — оба действия надо делать явно
Имена в Python не типизируемы и могут связывать какие угодно объекты
Хотя считается плохим стилем называть одним именем в одном и том же контексте сначала объекты одного типа, а затем другого
Функция в Python — это запись алгоритма, в которой (без использования hints) упоминаются только имена объектов и операции над ними
⇒ В качестве параметров функции годятся любые объекты, поддерживающие операции, которые использованы в функции
⇒ О том, что объекты не годятся, вы узнаете только когда уже вызовите функцию, и неподдерживаемая операция начнёт выполняться
Если вам нужно проверить тип объекта, проверяйте (как минимум type(object) == int, или в общей форме isinstance(объект, тип)
Собственно duck typing, она же утиная типизация, она же неявная динамическая типизация:
- Если для вас утка — это то, что крякает и плавает, то всё, что крякает и плавает — это утка!
- …даже если оно при этом громыхает и пускает лазер из глаз!
Пример:
1 >>> def fun(a, b):
2 ... return a * 2 + b
3 ...
4 >>> fun(3, 4)
5 10
6 >>> fun("QWE", "xxcv")
7 'QWEQWExxcv'
8 >>> fun((1, 2, "QQ"), ((6, 7), "ZZ"))
9 (1, 2, 'QQ', 1, 2, 'QQ', (6, 7), 'ZZ')
10 >>> fun(23, "QW")
11 Traceback (most recent call last):
12 File "<stdin>", line 1, in <module>
13 File "<stdin>", line 2, in fun
14 TypeError: unsupported operand type(s) for +: 'int' and 'str'
Именные параметры и умолчания
Параметрам можно задать значения по умолчанию, тогда они становятся необязательными:
- Необязательные параметры передавать не обязательно
- Но можно и передавать
- Не обязательно все
- Необязательно подряд (но тогда обязательно по имени)
Функции как объекты
- Именование — такое же
- пример
- Передача как параметр — такая же
- пример
Возврат как возвращаемого значения — почти такой же (см. лекцию на ВМК
- пример без объяснения сути замыкания
Введение в Tkinter
(посложнее: стандартная документация tk и tk.html и справочник)
Принципы работы:
Сначала открывается главное окно приложения — window = tkinter.Tk()
Все элементы приложения — виджеты — располагаются в этом окне или друг в друге. При создании виджета его хозяин указывается первым параметром — L = tkinter.Label(window, другие_параметры…)
Элементы приложения не отобразятся, пока их не разместили явно внутри хозяина в воображаемой прямоугольной сетке с помощью метода .grid() — L.grid(column=0, row=0)
Параметры grid() необязательны
Вдобавок к явному указанию строки и столбца, есть columnspan=сколько-то и rowspan=сколько-то в случае, если виджет должен занимать более одного столбца и/или строки
- Есть ещё всякое управление геометрией (например, резиновые столбцы с коэффициентом растяжения)
- Различные свойства элементов (например, надпись) можно задать тремя способами
При создании элемента — L = tkinter.Label(window, text="Надпись")
После создания элемента с помощью метода .configure() — L.configure(text = "Надпись")
С помощью операции индексирования: L["text"] = "надпись"
Для полноценного запуска приложения в конце программы должен стоять вызов метода .mainloop() из основного окна — window.mainloop()
У разных виджетов есть ещё разные свойства (например, .get() у tkinter.Entry или действие command для tkinter.Button
Пример: приложение с кнопкой, полем ввода и надписью, которое выводит на терминал содержимое поля ввода и надписи при нажатии на кнопку:
1 import tkinter
2
3 def showit():
4 print(label["text"], entry.get())
5
6 app = tkinter.Tk()
7 app.title("Введите!")
8 label = tkinter.Label(app, text="Введите что-то:")
9 label.grid()
10 entry = tkinter.Entry(app)
11 entry.grid()
12 button = tkinter.Button(app, text="Показать", command=showit)
13 button.grid()
14 app.mainloop()
Д/З
Внимание! Часть домашнего задания надо оформлять как функцию. Просьба внимательно прочитать правила и спрашивать, если что не так.
- Прочитать и прощёлкать:
про форматные строки в tutorial (или в русском переводе)
про функции на pythontutor(рекурсию можно не трогать)
про базовые инструменты tkinter в копипасте из Morioh
EJudge: DummyFunction 'Примитивная функция'
Это примитивная задача типа «написать функцию». Она нужна для того, чтобы освоить такой тип задач. Написать функцию divides(a, b), которая для целых a и b возвращает целый результат деления a на b, если a делится на b, или же деления b на a, если b делится на a, или 0 в противном случае. На 0, понятно, ничего не делится.
print(divides(1000,10), divides(64, 32768), divides(1024, 12345))
100 512 0
EJudge: ArsakSequence 'Конечная последовательность'
(Ж. Арсак) Написать функцию seq(n), которая последовательно вычисляет значения последовательности $$ {P_i} $$ для натурального n по формуле ниже, до тех пор, пока очередной член этой последовательности не станет равен 1, и возвращает наибольший элемент такой последовательности. Формула:
$$ P_0=n $$
$$ P_(i+1)=P_i/2 $$, если $$ P_i $$ чётно
$$ P_(i+1)=3P_i+1 $$, если $$ P_i $$ нечётно
print(seq(27), seq(1), seq(16), seq(101))
9232 1 16 304
EJudge: LongRepeat 'Блаблабла'
Написать функцию blah(S, P), которая проверяет, встречается ли в строке S шаблон P, и возвращает наибольшую длину подстроки, образованной повторением шаблона P, которая встречается в S. Если шаблон встречается в строке, но без повторений, возвращается 1, а если и шаблона нет — 0.
print(blah("Hey blah, blahblahblah, more than blahblah, blah-blah!", "blah"))
12
EJudge: TkinterSum 'Сумматор'
Пользуясь статьёй про Tkinter, написать простейшее приложение (программу), в котором будет два поля ввода A1 и A2 типа tkinter.Entry, одно текстовое поле L типа tkinter.Label и одна кнопка B типа tkinter.Button. При нажатии кнопки в текстовом поле должна появляться сумма чисел, находящихся в полях ввода. Если хотя бы одна из строк в полях ввода не является числом, содержимое L не меняется. С самого начала поля ввода пусты, а в L записана строка "0". Условие: функция, которая считывает значения из A, проверяет их правильность и записывает результат в L, должна быть зарегистрирована при создании кнопки B как её свойство command. Внимание!. Программа должна использовать оператор import tkinter, как в примере из лекции, (а не from tkinter import *, как в статье).
23 и 456 в полях ввода A1 и A2
479 в поле вывода L
- Обратите также внимание на то, что тестированием такой программы (она ничего не вводит со стандартного ввода и ничего не выводит на стандартный вывод) занимается специальный робот. Робот тупой — мы с вами куда хитрее, так что если тесты не проходят, сигнальте мне: возможно, вы просто его перехитрили
Выглядеть должно примерно так: