Главная страница

Книга Изучаем Python


Скачать 4.68 Mb.
НазваниеКнига Изучаем Python
Дата10.12.2022
Размер4.68 Mb.
Формат файлаpdf
Имя файлаErik_Metiz_Izuchaem_Python_Programmirovanie_igr_vizualizatsia_da.pdf
ТипКнига
#837531
страница18 из 53
1   ...   14   15   16   17   18   19   20   21   ...   53
150 Глава 8 • Функции
Программа создает список моделей для печати и пустой список для готовых моде- лей. Затем, поскольку обе функции уже определены, остается вызвать их и передать правильные аргументы. Мы вызываем print_models()
и передаем два необходимых списка; как и ожидалось, print_models()
имитирует печать моделей. Затем вызыва- ется функция show_completed_models()
, и ей передается список готовых моделей, чтобы функция могла вывести информацию о напечатанных моделях. Благодаря содержательным именам функций другой разработчик сможет прочитать этот код и понять его даже без комментариев.
Вдобавок эта программа создает меньше проблем с расширением и сопровождени- ем, чем версия без функций. Если позднее потребуется напечатать новую партию моделей, достаточно снова вызвать print_models()
. Если окажется, что код печати необходимо модифицировать, изменения достаточно внести в одном месте, и они автоматически распространятся на все вызовы функции. Такой подход намного эффективнее независимой правки кода в нескольких местах программы.
Этот пример также демонстрирует принцип, в соответствии с которым каждая функция должна решать одну конкретную задачу. Первая функция печатает каждую модель, а вторая выводит информацию о готовых моделях. Такой подход предпочтительнее решения обеих задач в функции. Если вы пишете функцию и видите, что она решает слишком много разных задач, попробуйте разделить ее код на две функции.
Помните, что функции всегда можно вызывать из других функций. Эта возмож- ность может пригодиться для разбиения сложных задач на серию составляющих.
Запрет изменения списка в функции
Иногда требуется предотвратить изменение списка в функции. Допустим, у вас имеется список моделей для печати, и вы пишете функцию для перемещения их в список готовых моделей, как в предыдущем примере. Возможно, даже после пе- чати всех моделей исходный список нужно оставить для отчетности. Но, поскольку все имена моделей были перенесены из списка unprinted_designs
, остался только пустой список; исходная версия списка потеряна. Проблему можно решить пере- дачей функции копии списка вместо оригинала. В этом случае все изменения, вносимые функцией в список, будут распространяться только на копию, а оригинал списка остается неизменным.
Чтобы передать функции копию списка, можно поступить так:
имя_функции(имя_списка[:])
Синтаксис среза
[:]
создает копию списка для передачи функции. Если удаление элементов из списка unprinted_designs в print_models .py нежелательно, функцию print_models()
можно вызвать так:
print_models(unprinted_designs[:], completed_models)
Функция print_models()
может выполнить свою работу, потому что она все равно получает имена всех ненапечатаных моделей. Но на этот раз она получает не сам список unprinted_designs
, а его копию. Список completed_models заполняется

Передача списка 151
именами напечатанных моделей, как и в предыдущем случае, но исходный список функцией не изменяется.
Несмотря на то что передача копии позволяет сохранить содержимое списка, обыч- но функциям следует передавать исходный список (если у вас нет веских причин для передачи копии). Работа с существующим списком более эффективна, потому что программе не приходится тратить время и память на создание отдельной копии
(лишние затраты особенно заметны при работе с большими списками).
УПРАЖНЕНИЯ
8-9 . Фокусники: создайте список с именами фокусников . Передайте список функции show_
magicians(), которая выводит имя каждого фокусника в списке .
8-10 . Великие фокусники: начните с копии вашей программы из упражнения 8-9 . Напишите функцию make_great(), которая изменяет список фокусников, добавляя к имени каждого фокусника приставку «Great» . Вызовите функцию show_magicians() и убедитесь в том, что список был успешно изменен .
8-11 . Фокусники без изменений: начните с программы из упражнения 8-10 . Вызовите функ- цию make_great() и передайте ей копию списка имен фокусников . Поскольку исходный список остался неизменным, верните новый список и сохраните его в отдельном списке .
Вызовите функцию show_magicians() с каждым списком, чтобы показать, что в одном спи- ске остались исходные имена, а в другом к имени каждого фокусника добавилась приставка
«Great» .
Передача произвольного набора аргументов
В некоторых ситуациях вы не знаете заранее, сколько аргументов должно быть передано функции. К счастью, Python позволяет функции получить произвольное количество аргументов из вызывающей команды.
Для примера рассмотрим функцию для создания пиццы. Функция должна полу- чить набор дополнений к пицце, но вы не знаете заранее, сколько дополнений за- кажет клиент. Функция в следующем примере получает один параметр
*toppings
, но этот параметр объединяет все аргументы, заданные в командной строке:
pizza.py
def make_pizza(*toppings):
"""Вывод списка заказанных дополнений."""
print(toppings)
make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')
Звездочка в имени параметра
*toppings приказывает Python создать пустой кор- теж с именем toppings и упаковать в него все полученные значения. Результат команды print в теле функции показывает, что Python успешно справляется и с вызовом функции с одним значением, и с вызовом с тремя значениями.
Разные вызовы обрабатываются похожим образом. Обратите внимание: Python упаковывает аргументы в кортеж даже в том случае, если функция получает всего одно значение:

152 Глава 8 • Функции
('pepperoni',)
('mushrooms', 'green peppers', 'extra cheese')
Теперь команду print можно заменить циклом, который перебирает список дополнений и выводит описание заказанной пиццы:
def make_pizza(*toppings):
"""Выводит описание пиццы."""
print("\nMaking a pizza with the following toppings:")
for topping in toppings:
print("- " + topping)
make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')
Функция реагирует соответственно независимо от того, сколько значений она получила — одно или три:
Making a pizza with the following toppings:
- pepperoni
Making a pizza with the following toppings:
- mushrooms
- green peppers
- extra cheese
Этот синтаксис работает независимо от количества аргументов, переданных функции.
Позиционные аргументы с произвольными наборами аргументов
Если вы хотите, чтобы функция могла вызываться с разными количествами аргу- ментов, параметр для получения произвольного количества аргументов должен стоять на последнем месте в определении функции. Python сначала подбирает со- ответствия для позиционных и именованных аргументов, а потом объединяет все остальные аргументы в последнем параметре.
Например, если функция должна получать размер пиццы, этот параметр должен стоять в списке до параметра
*toppings
:
def make_pizza(size, *toppings):
"""Выводит описание пиццы."""
print("\nMaking a " + str(size) +
"-inch pizza with the following toppings:") for topping in toppings: print("- " + topping) make_pizza(16, 'pepperoni') make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
В определении функции Python сохраняет первое полученное значение в параметре size
. Все остальные значения, следующие за ним, сохраняются в кортеже toppings
В вызовах функций на первом месте располагается аргумент для параметра size
, а за ним следует сколько угодно дополнений.

Передача списка 153
В итоге для каждой пиццы указывается размер и количество дополнений, и каждый фрагмент информации выводится в положенном месте: сначала размер, а потом дополнения:
Making a 16-inch pizza with the following toppings:
- pepperoni
Making a 12-inch pizza with the following toppings:
- mushrooms
- green peppers
- extra cheese
Использование произвольного набора именованных аргументов
Иногда программа должна получать произвольное количество аргументов, но вы не знаете заранее, какая информация будет передаваться функции. В таких случаях можно написать функцию, получающую столько пар «ключ—значение», сколько указано в команде вызова. Один из возможных примеров — построение пользова- тельских профилей: вы знаете, что вы получите информацию о пользователе, но не знаете заранее, какую именно. Функция build_profile()
в следующем примере всегда получает имя и фамилию, но также может получать произвольное количе- ство именованных аргументов:
user_profile.py
def build_profile(first, last, **user_info):
"""Строит словарь с информацией о пользователе."""
profile = {}
 profile['first_name'] = first profile['last_name'] = last
 for key, value in user_info.items():
profile[key] = value return profile user_profile = build_profile('albert', 'einstein',
location='princeton',
field='physics')
print(user_profile)
Определение build_profile()
ожидает получить имя и фамилию пользователя, а также позволяет передать любое количество пар «имя—значение». Две звездочки перед параметром
**user_info заставляют Python создать пустой словарь с име- нем user_info и упаковать в него все полученные пары «имя—значение». Внутри функции вы можете обращаться к парам «имя–значение» из user_info точно так же, как в любом словаре.
В теле build_profile()
создается пустой словарь с именем profile для хранения профиля пользователя. В точке  в словарь добавляется имя и фамилия, потому что эти два значения всегда передаются пользователем. В точке  функция пере- бирает дополнительные пары «ключ—значение» в словаре user_info и добавляет каждую пару в словарь profile
. Наконец, словарь profile возвращается в точку вызова функции.

154 Глава 8 • Функции
Вызовем функцию build_profile()
и передадим ей имя 'albert'
, фами- лию 'einstein'
, и еще две пары «ключ—значение» location='princeton'
и field='physics'
. Программа сохраняет возвращенный словарь в user_profile и выводит его содержимое:
{'first_name': 'albert', 'last_name': 'einstein',
'location': 'princeton', 'field': 'physics'}
Возвращаемый словарь содержит имя и фамилию пользователя, а в данном случае еще и местонахождение и область исследований. Функция будет работать, сколько бы дополнительных пар «ключ—значение» ни было передано при вызове функции.
При написании функций допускаются самые разнообразные варианты смешения позиционных, именованных и произвольных значений. Полезно знать о существо- вании всех этих типов аргументов, потому что они часто будут встречаться вам при чтении чужого кода. Только с опытом вы научитесь правильно использовать разные типы аргументов и поймете, когда следует применять каждый тип; а пока просто используйте самый простой способ, который позволит решить задачу.
С течением времени вы научитесь выбирать наиболее эффективный вариант для каждой конкретной ситуации.
УПРАЖНЕНИЯ
8-12 . Сэндвичи: напишите функцию, которая получает список компонентов сэндвича . Функ- ция должна иметь один параметр для любого количества значений, переданных при вызове функции, и выводить описание заказанного сэндвича . Вызовите функцию три раза с разны- ми количествами аргументов .
8-13 . Профиль: начните с копии программы user_profile .py . Создайте собственный профиль вызовом build_profile(), укажите имя, фамилию и три другие пары «ключ—значение» для вашего описания .
8-14 . Автомобили: напишите функцию для сохранения информации об автомобиле в слова- ре . Функция всегда должна возвращать производителя и название модели, но при этом она может получать произвольное количество именованных аргументов . Вызовите функцию с передачей обязательной информации и еще двух пар «имя—значение» (например, цвет и комплектация) . Ваша функция должна работать для вызовов следующего вида:
car = make_car(‘subaru’, ‘outback’, color=’blue’, tow_package=True)
Выведите возвращаемый словарь и убедитесь в том, что вся информация была сохранена правильно .
Хранение функций в модулях
Одно из преимуществ функций заключается в том, что они отделяют блоки кода от основной программы. Если для функций были выбраны содержательные имена, ваша программа будет намного проще читаться. Можно пойти еще дальше и сохра- нить функции в отдельном файле, называемом модулем, а затем импортировать модуль в свою программу. Команда import сообщает Python, что код модуля дол- жен быть доступен в текущем выполняемом программном файле.
Хранение функций в отдельных файлах позволяет скрыть второстепенные детали кода и сосредоточиться на логике более высокого уровня. Кроме того, функции

Хранение функций в модулях 155
можно использовать во множестве разных программ. Функции, хранящиеся в от- дельных файлах, можно передать другим программистам без распространения полного кода программы. А умение импортировать функции позволит вам исполь- зовать библиотеки функций, написанные другими программистами.
Существует несколько способов импортирования модулей; все они кратко рас- сматриваются ниже.
Импортирование всего модуля
Чтобы заняться импортированием функций, сначала необходимо создать модуль.
Модуль представляет собой файл с расширением
.py
, содержащий код, который вы хотите импортировать в свою программу. Давайте создадим модуль с функци- ей make_pizza()
. Для этого из файла pizza .py следует удалить все, кроме функции make_pizza()
:
pizza.py
def make_pizza(size, *toppings):
"""Выводит описание пиццы."""
print("\nMaking a " + str(size) +
"-inch pizza with the following toppings:")
for topping in toppings:
print("- " + topping)
Теперь создайте отдельный файл с именем making_pizzas .py в одном каталоге с pizza .
py
. Файл импортирует только что созданный модуль, а затем дважды вызывает make_pizza()
:
making_pizzas.py
import pizza
 pizza.make_pizza(16, 'pepperoni')
pizza.make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
В процессе обработки этого файла строка import pizza приказывает Python от- крыть файл pizza .py и скопировать все функции из него в программу. Вы не види- те, как происходит копирование, потому что Python копирует код незаметно для пользователя во время выполнения программы. Вам необходимо знать одно: любая функция, определенная в pizza .py
, будет доступна в making_pizzas .py
Чтобы вызвать функцию из импортированного модуля, укажите имя модуля
(
pizza
), точку и имя функции (
make_pizza()
), как показано в строке . Код вы- дает тот же результат, что и исходная программа, в которой модуль не импорти- ровался:
Making a 16-inch pizza with the following toppings:
- pepperoni
Making a 12-inch pizza with the following toppings:
- mushrooms
- green peppers
- extra cheese

156 Глава 8 • Функции
Первый способ импортирования, при котором записывается команда import с име- нем модуля, открывает доступ программе ко всем функциям из модуля:
имя_модуля.имя_функции()
Импортирование конкретных функций
Также возможно импортировать конкретную функцию из модуля. Общий синтак- сис выглядит так:
from имя_модуля import имя_функции
Вы можете импортировать любое количество функций из модуля, разделив их имена запятыми:
from имя_модуля import функция_0, функция_1, функция_2
Если ограничиться импортированием только той функции, которую вы намерева- етесь использовать, пример making_pizzas .py будет выглядеть так:
from pizza import make_pizza make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
При таком синтаксисе использовать точечную запись при вызове функции не обя- зательно. Так как функция make_pizza()
явно импортируется в команде import
, при использовании ее можно вызывать прямо по имени.
Назначение псевдонима для функции
Если имя импортируемой функции может конфликтовать с именем существующей функции или функция имеет слишком длинное имя, его можно заменить коротким уникальным псевдонимом (alias) — альтернативным именем для функции. Псевдо- ним назначается функции при импортировании.
В следующем примере функции make_pizza()
назначается псевдоним mp()
, для чего при импортировании используется конструкция make_pizza as mp
. Ключевое слово as переименовывает функцию, используя указанный псевдоним:
from pizza import make_pizza as mp mp(16, 'pepperoni')
mp(12, 'mushrooms', 'green peppers', 'extra cheese')
Команда import в этом примере назначает функции make_pizza()
псевдоним mp()
для этой программы. Каждый раз, когда потребуется вызвать make_pizza()
, доста- точно включить вызов mp()
— Python выполнит код make_pizza()
без конфликтов с другой функцией make_pizza()
, которую вы могли включить в этот файл про- граммы.
Общий синтаксис назначения псевдонима выглядит так:
from имя_модуля import имя_функции as псевдоним

Хранение функций в модулях 157
Назначение псевдонима для модуля
Псевдоним также можно назначить для всего модуля. Назначение короткого имени для модуля — скажем, p
для pizza
— позволит вам быстрее вызывать функ- ции модуля. Вызов p.make_pizza()
получается более компактным, чем pizza.
make_pizza()
:
import pizza as p p.make_pizza(16, 'pepperoni')
p.make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
Модулю pizza в команде import назначается псевдоним p
, но все функции модуля сохраняют свои исходные имена. Вызов функций в записи p.make_
pizza()
не только компактнее pizza.make_pizza()
; он также отвлекает внима- ние от имени модуля и помогает сосредоточиться на содержательных именах функций. Эти имена функций, четко показывающие, что делает каждая функ- ция, важнее для удобочитаемости вашего кода, чем использование полного имени модуля.
Общий синтаксис выглядит так:
import имя_модуля as псевдоним
Импортирование всех функций модуля
Также можно приказать Python импортировать каждую функцию в модуле; для этого используется оператор
*
:
from pizza import *
make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
Звездочка в команде import приказывает Python скопировать каждую функцию из модуля pizza в файл программы. После импортирования всех функций вы сможете вызывать каждую функцию по имени без точечной записи. Тем не менее лучше не использовать этот способ с большими модулями, написанными дру- гими разработчиками; если модуль содержит функцию, имя которой совпадает с существующим именем из вашего проекта, возможны неожиданные результа- ты. Python обнаруживает несколько функций или переменных с одинаковыми именами, и вместо импортирования всех функций по отдельности происходит замена этих функций.
В таких ситуациях лучше всего импортировать только нужную функцию или функ- ции или же импортировать весь модуль с последующим применением точечной записи. При этом создается чистый код, легко читаемый и понятный. Я включил этот раздел только для того, чтобы вы понимали команды import вроде следующей, когда вы встретите их в чужом коде:
from имя_модуля import *

1   ...   14   15   16   17   18   19   20   21   ...   53


написать администратору сайта