ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 05.12.2023
Просмотров: 868
Скачиваний: 3
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
СОДЕРЖАНИЕ
Глава 10. Работа с датой и временем
205 10.5.3. Другие полезные функции
Модуль calendar предоставляет еще несколько функций, которые позволяют вывести тек- стовый календарь без создания экземпляра соответствующего класса и получить дополни- тельную информацию о дате:
setfirstweekday(<Первый день недели>)
— устанавливает первый день недели для ка- лендаря. В качестве параметра указывается число от
0
(для понедельника) до
6
(для вос- кресенья). Вместо чисел можно использовать встроенные константы:
MONDAY
,
TUESDAY
,
WEDNESDAY
,
THURSDAY
,
FRIDAY
,
SATURDAY
или
SUNDAY
. Получить текущее значение параметра можно с помощью функции firstweekday()
.\
Установим воскресенье первым днем недели:
>>> import calendar
>>> calendar.firstweekday() # По умолчанию 0 0
>>> calendar.setfirstweekday(6) # Изменяем значение
>>> calendar.firstweekday() # Проверяем установку
6
month(<Год>, <Месяц>[, <Ширина поля с днем>[, <Количество символов перевода стро- ки>]])
— возвращает текстовый календарь на указанный месяц в году. Третий параметр позволяет указать ширину поля с днем, а четвертый параметр — количество символов перевода строки между строками.
Выведем календарь на ноябрь 2017 года:
>>> calendar.setfirstweekday(0)
>>> print(calendar.month(2017, 11)) # Ноябрь 2017 года
November 2017
Mo Tu We Th Fr Sa Su
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
prmonth(<Год>, <Месяц>[, <Ширина поля с днем>[, <Количество символов перевода строки>]])
— аналогична функции month()
, но не возвращает календарь в виде строки, а сразу выводит его.
Выведем календарь на ноябрь 2017 года:
>>> calendar.prmonth(2017, 11) # Ноябрь 2017 года
monthcalendar(<Год>, <Месяц>)
— возвращает двумерный список всех дней в указанном месяце, распределенных по дням недели. Дни, выходящие за пределы месяца, будут представлены нулями.
Выведем массив для ноября 2017 года:
>>> calendar.monthcalendar(2017, 11)
[[0, 0, 1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11, 12], [13, 14, 15, 16, 17, 18, 19],
[20, 21, 22, 23, 24, 25, 26], [27, 28, 29, 30, 0, 0, 0]]
monthrange(<Год>, <Месяц>)
— возвращает кортеж из двух элементов: номера дня неде- ли, приходящегося на первое число указанного месяца, и количества дней в месяце:
206
Часть I. Основы языка Python
>>> print(calendar.monthrange(2017, 11))
(2, 30)
>>> # Ноябрь 2017 года начинается со среды (2) и включает 30 дней
calendar(<Год>[, w][, l][, c][, m])
— возвращает текстовый календарь на указанный год. Параметры имеют следующее предназначение:
• w
— ширина поля с днем (по умолчанию
2
);
• l
— количество символов перевода строки между строками (по умолчанию
1
);
• c
— количество пробелов между месяцами (по умолчанию
6
);
• m
— количество месяцев на строке (по умолчанию
3
).
Значения можно указать через запятую в порядке следования параметров или присвоить значение названию параметра.
Для примера выведем календарь на 2017 год так, чтобы на одной строке выводилось сразу четыре месяца, установив при этом количество пробелов между месяцами:
>>> print(calendar.calendar(2017, m=4, c=2))
prcal(<Год>[, w][, l][, c][, m])
— аналогична функции calendar()
, но не возвращает календарь в виде строки, а сразу выводит его.
Для примера выведем календарь на 2017 год по два месяца на строке, расстояние между месяцами установим равным 4-м символам, ширину поля с датой — равной 2-м симво- лам, а строки разделим одним символом перевода строки:
>>> calendar.prcal(2017, 2, 1, 4, 2)
weekheader(
— возвращает строку, которая содержит аббревиатуры дней недели с учетом текущей локали, разделенные пробелами. Единственный параметр задает длину каждой аббре- виатуры в символах:
>>> calendar.weekheader(4)
'Mon Tue Wed Thu Fri Sat Sun '
>>> calendar.weekheader(2)
'Mo Tu We Th Fr Sa Su'
>>> import locale # Задаем другую локаль
>>> locale.setlocale(locale.LC_ALL, "Russian_Russia.1251")
'Russian_Russia.1251'
>>> calendar.weekheader(2)
'Пн Вт Ср Чт Пт Сб Вс'
isleap(<Год>)
— возвращает значение
True
, если указанный год является високосным, в противном случае —
False
:
>>> calendar.isleap(2017), calendar.isleap(2016)
(False, True)
leapdays(<Год1>, <Год2>)
— возвращает количество високосных лет в диапазоне от
<Год1>
до
<Год2>
(
<Год2>
не учитывается):
>>> calendar.leapdays(2013, 2016) # 2016 не учитывается
0
>>> calendar.leapdays(2010, 2016) # 2012 — високосный год
1
>>> calendar.leapdays(2010, 2017) # 2012 и 2016 — високосные года
2
Глава 10. Работа с датой и временем
207
weekday(<Год>, <Месяц>, <День>)
— возвращает номер дня недели (
0
— для понедель- ника,
6
— для воскресенья):
>>> calendar.weekday(2017, 11, 22)
2
timegm(<Объект struct_time>)
— возвращает число, представляющее количество се- кунд, прошедших с начала эпохи. В качестве параметра указывается объект struct_time с датой и временем, возвращаемый функцией gmtime()
из модуля time
:
>>> import calendar, time
>>> d = time.gmtime(1511348777.0) # Дата 22-11-2017
>>> d time.struct_time(tm_year=2017, tm_mon=11, tm_mday=22, tm_hour=11, tm_min=6, tm_sec=17, tm_wday=2, tm_yday=326, tm_isdst=0)
>>> tuple(d)
(2017, 11, 22, 11, 6, 17, 2, 326, 0)
>>> calendar.timegm(d)
1511348777
>>> calendar.timegm((2017, 11, 22, 11, 6, 17, 2, 326, 0))
1511348777
Модуль calendar также предоставляет несколько атрибутов:
day_name
— список полных названий дней недели в текущей локали:
>>> [i for i in calendar.day_name]
['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday',
'Saturday', 'Sunday']
>>> import locale # Настройка локали
>>> locale.setlocale(locale.LC_ALL, "Russian_Russia.1251")
'Russian_Russia.1251'
>>> [i for i in calendar.day_name]
['понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота',
'воскресенье']
day_abbr
— список аббревиатур названий дней недели в текущей локали:
>>> [i for i in calendar.day_abbr]
['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
>>> import locale # Настройка локали
>>> locale.setlocale(locale.LC_ALL, "Russian_Russia.1251")
'Russian_Russia.1251'
>>> [i for i in calendar.day_abbr]
['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс']
month_name
— список полных названий месяцев в текущей локали:
>>> [i for i in calendar.month_name]
['', 'January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December']
>>> import locale # Настройка локали
>>> locale.setlocale(locale.LC_ALL, "Russian_Russia.1251")
'Russian_Russia.1251'
>>> [i for i in calendar.month_name]
['', 'Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль',
'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь']
208
Часть I. Основы языка Python
month_abbr
— список аббревиатур названий месяцев в текущей локали:
>>> [i for i in calendar.month_abbr]
['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug',
'Sep', 'Oct', 'Nov', 'Dec']
>>> import locale # Настройка локали
>>> locale.setlocale(locale.LC_ALL, "Russian_Russia.1251")
'Russian_Russia.1251'
>>> [i for i in calendar.month_abbr]
['', 'янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен',
'окт', 'ноя', 'дек']
10.6. Измерение времени выполнения фрагментов кода
Модуль timeit позволяет измерить время выполнения небольших фрагментов кода с целью оптимизации программы. Прежде чем использовать модуль, необходимо подключить его с помощью инструкции: from timeit import Timer
Измерения производятся с помощью класса
Timer
. Конструктор класса имеет следующий формат:
Timer([stmt='pass'][, setup='pass'][, timer=
В параметре stmt указывается код (в виде строки), время выполнения которого предполага- ется измерить. Параметр setup позволяет указать код, который будет выполнен перед изме- рением времени выполнения кода в параметре stmt
1 ... 15 16 17 18 19 20 21 22 ... 83
. Например, в параметре setup можно подключить модуль.
Получить время выполнения можно с помощью метода timeit([number=1000000])
. В пара- метре number указывается количество повторений.
Для примера просуммируем числа от
1
до
10000
тремя способами и выведем время выпол- нения каждого способа (листинг 10.3).
Листинг 10.3. Измерение времени выполнения
# -*- coding: utf-8 -*- from timeit import Timer code1 = """\ i, j = 1, 0 while i < 10001: j += i i += 1
""" t1 = Timer(stmt=code1) print("while:", t1.timeit(number=10000)) code2 = """\ j = 0 for i in range(1, 10001): j += i
Глава 10. Работа с датой и временем
209
""" t2 = Timer(stmt=code2) print("for:", t2.timeit(number=10000)) code3 = """\ j = sum(range(1, 10001))
""" t3 = Timer(stmt=code3) print("sum:", t3.timeit(number=10000)) input()
Примерный результат выполнения (зависит от мощности компьютера): while: 10.487761735853875 for: 6.378136742560729 sum: 2.2042291718107094
Сразу видно, что цикл for работает почти в два раза быстрее цикла while
, а функция sum()
в данном случае вне конкуренции.
Метод repeat([repeat=3][, number=1000000])
вызывает метод timeit()
указанное в пара- метре repeat количество раз и возвращает список значений. Аргумент number передается в качестве параметра методу timeit()
Для примера создадим список со строковыми представлениями чисел от
1
до
10000
: в пер- вом случае для создания списка используем цикл for и метод append()
, а во втором — гене- ратор списков (листинг 10.4).
Листинг 10.4. Использование метода repeat()
# -*- coding: utf-8 -*- from timeit import Timer code1 = """\ arr1 = [] for i in range(1, 10001): arr1.append(str(i))
""" t1 = Timer(stmt=code1) print("append:", t1.repeat(repeat=3, number=2000)) code2 = """\ arr2 = [str(i) for i in range(1, 10001)]
""" t2 = Timer(stmt=code2) print("генератор:", t2.repeat(repeat=3, number=2000)) input()
Примерный результат выполнения: append: [6.27173358307843, 6.222750011887982, 6.239843531272257] генератор: [4.6601598507632325, 4.648098189899006, 4.618446638727157]
Как видно из результата, генераторы списков выполняются быстрее.
ГЛ А В А
11
Пользовательские функции
Функция — это фрагмент кода, который можно вызвать из любого места программы. В пре- дыдущих главах мы уже не один раз использовали встроенные функции языка Python — например, с помощью функции len()
получали количество элементов последовательности.
В этой главе мы рассмотрим создание пользовательских функций, которые позволят уменьшить избыточность программного кода и повысить его структурированность.
11.1. Определение функции и ее вызов
Функция создается (или, как говорят программисты, определяется) с помощью ключевого слова def в следующем формате: def <Имя функции>([<Параметры>]):
[""" Строка документирования """]
<Тело функции>
[return <Результат>]
Имя функции должно быть уникальным идентификатором, состоящим из латинских букв, цифр и знаков подчеркивания, причем имя функции не может начинаться с цифры. В ка- честве имени нельзя использовать ключевые слова, кроме того, следует избегать совпаде- ний с названиями встроенных идентификаторов. Регистр символов в названии функции также имеет значение.
После имени функции в круглых скобках можно указать один или несколько параметров через запятую, а если функция не принимает параметры, указываются только круглые скоб- ки. После круглых скобок ставится двоеточие.
Тело функции представляет собой составную конструкцию. Как и в любой составной кон- струкции, инструкции внутри функции выделяются одинаковым количеством пробелов слева. Концом функции считается инструкция, перед которой находится меньшее количест- во пробелов. Если тело функции не содержит инструкций, то внутри ее необходимо размес- тить оператор pass
, который не выполняет никаких действий. Этот оператор удобно ис- пользовать на этапе отладки программы, когда мы определили функцию, а тело решили дописать позже. Вот пример функции, которая ничего не делает: def func(): pass
Необязательная инструкция return позволяет вернуть из функции какое-либо значение в качестве результата. После исполнения этой инструкции выполнение функции будет остановлено, и последующие инструкции никогда не будут выполнены:
Глава 11. Пользовательские функции
211
>>> def func(): print("Текст до инструкции return") return "Возвращаемое значение" print("Эта инструкция никогда не будет выполнена")
>>> print(func()) # Вызываем функцию
Результат выполнения:
Текст до инструкции return
Возвращаемое значение
Инструкции return может не быть вообще. В этом случае выполняются все инструкции внутри функции, и в качестве результата возвращается значение
None
Для примера создадим три функции (листинг 11.1).
Листинг 11.1. Определение функций def print_ok():
""" Пример функции без параметров """ print("Сообщение при удачно выполненной операции") def echo(m):
""" Пример функции с параметром """ print(m) def summa(x, y):
""" Пример функции с параметрами, возвращающей сумму двух переменных """ return x + y
При вызове функции значения ее параметров указываются внутри круглых скобок через запятую. Если функция не принимает параметров, оставляются только круглые скобки. Не- обходимо также заметить, что количество параметров в определении функции должно сов- падать с количеством параметров при вызове, иначе будет выведено сообщение об ошибке.
Вызвать функции из листинга 11.1 можно способами, указанными в листинге 11.2.
Листинг 11.2. Вызов функций print_ok() # Вызываем функцию без параметров echo("Сообщение") # Функция выведет сообщение x = summa(5, 2) # Переменной x будет присвоено значение 7 a, b = 10, 50 y = summa(a, b) # Переменной y будет присвоено значение 60
Как видно из последнего примера, имя переменной в вызове функции может не совпадать с именем соответствующего параметра в определении функции. Кроме того, глобальные переменные x
и y
не конфликтуют с одноименными переменными, созданными в определе- нии функции, т. к. они расположены в разных областях видимости. Переменные, указанные в определении функции, являются локальными и доступны только внутри функции. Более подробно области видимости мы рассмотрим в разд. 11.9.
212
Часть I. Основы языка Python
Оператор
+
, используемый в функции summa()
, служит не только для сложения чисел, но и позволяет объединить последовательности. То есть функция summa()
может использоваться не только для сложения чисел. В качестве примера выполним конкатенацию строк и объ- единение списков (листинг 11.3).
Листинг 11.3. Многоцелевая функция def summa(x, y): return x + y print(summa("str", "ing")) # Выведет: string print(summa([1, 2], [3, 4])) # Выведет: [1, 2, 3, 4]
Как вы уже знаете, все в языке Python представляет собой объекты: строки, списки и даже сами типы данных. Не являются исключением и функции. Инструкция def создает объект, имеющий тип function
, и сохраняет ссылку на него в идентификаторе, указанном после инструкции def
. Таким образом, мы можем сохранить ссылку на функцию в другой пере- менной — для этого название функции указывается без круглых скобок. Сохраним ссылку в переменной и вызовем функцию через нее (листинг 11.4).
Листинг 11.4. Сохранение ссылки на функцию в переменной def summa(x, y): return x + y f = summa # Сохраняем ссылку в переменной f v = f(10, 20) # Вызываем функцию через переменную f
Можно также передать ссылку на функцию другой функции в качестве параметра (лис- тинг 11.5). Функции, передаваемые по ссылке, обычно называются функциями обратного вызова.
Листинг 11.5. Функции обратного вызова def summa(x, y): return x + y def func(f, a, b):
""" Через переменную f будет доступна ссылка на функцию summa() """ return f(a, b) # Вызываем функцию summa()
# Передаем ссылку на функцию в качестве параметра v = func(summa, 10, 20)
Объекты функций поддерживают множество атрибутов, обратиться к которым можно, ука- зав атрибут после названия функции через точку. Например, через атрибут
__name__
можно получить имя функции в виде строки, через атрибут
__doc__
— строку документирования и т. д. Для примера выведем названия всех атрибутов функции с помощью встроенной функции dir()
:
Глава 11. Пользовательские функции
213
>>> def summa(x, y):
""" Суммирование двух чисел """ return x + y
>>> dir(summa)
['__annotations__', '__call__', '__class__', '__closure__', '__code__',
'__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__',
'__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__',
'__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__']
>>> summa.__name__
'summa'
>>> summa.__code__.co_varnames
('x', 'y')
>>> summa.__doc__
' Суммирование двух чисел '
11.2. Расположение определений функций
Все инструкции в программе выполняются последовательно. Это означает, что прежде чем использовать в программе идентификатор, его необходимо предварительно определить, присвоив ему значение. Поэтому определение функции должно быть расположено перед вызовом функции.
Правильно: def summa(x, y): return x + y v = summa(10, 20) # Вызываем после определения. Все нормально
Неправильно: v = summa(10, 20) # Идентификатор еще не определен. Это ошибка!!! def summa(x, y): return x + y
В последнем случае будет выведено сообщение об ошибке:
NameError: name 'summa' is not defined
. Чтобы избежать ошибки, определение функции размещают в самом начале программы после подключения модулей или в отдельном модуле (о них речь пойдет в главе 12).
С помощью оператора ветвления if можно изменить порядок выполнения программы — например, разместить внутри условия несколько определений функций с одинаковым на- званием, но разной реализацией (листинг 11.6).
Листинг 11.6. Определение функции в зависимости от условия
# -*- coding: utf-8 -*- n = input("Введите 1 для вызова первой функции: ") if n == "1": def echo(): print("Вы ввели число 1")
214
Часть I. Основы языка Python else: def echo(): print("Альтернативная функция") echo() # Вызываем функцию input()
При вводе числа 1 мы получим сообщение "Вы ввели число 1"
, в противном случае —
"Альтернативная функция"
Помните, что инструкция def всего лишь присваивает ссылку на объект функции иденти- фикатору, расположенному после ключевого слова def
. Если определение одной функции встречается в программе несколько раз, будет использоваться функция, которая была опре- делена последней:
>>> def echo(): print("Вы ввели число 1")
>>> def echo(): print("Альтернативная функция")
>>> echo() # Всегда выводит "Альтернативная функция"
11.3. Необязательные параметры и сопоставление по ключам
Чтобы сделать некоторые параметры функции необязательными, следует в определении функции присвоить этому параметру начальное значение. Переделаем функцию суммиро- вания двух чисел и сделаем второй параметр необязательным (листинг 11.7).
Листинг 11.7. Необязательные параметры def summa(x, y=2): # y — необязательный параметр return x + y a = summa(5) # Переменной a будет присвоено значение 7 b = summa(10, 50) # Переменной b будет присвоено значение 60
Таким образом, если второй параметр не задан, он получит значение
2
. Обратите внимание на то, что необязательные параметры должны следовать после обязательных, иначе будет выведено сообщение об ошибке.
До сих пор мы использовали позиционную передачу параметров в функцию: def summa(x, y): return x + y print(summa(10, 20)) # Выведет: 30
Переменной x
при сопоставлении будет присвоено значение
10
, а переменной y
— значе- ние
20
. Но язык Python позволяет также передать значения в функцию, используя сопостав- ление по ключам. Для этого при вызове функции параметрам присваиваются значения, причем последовательность указания параметров в этом случае может быть произвольной
(листинг 11.8).