Главная страница
Навигация по странице:

  • 8.8. Пользовательские альбомы

  • УПРАЖНЕНИЯ 8.9. Сообщения

  • 8.10. Отправка сообщений

  • 8.11. Архивированные сообщения

  • ПРИМЕЧАНИЕ

  • Мэтиз. Изучаем Python. Crash course2 n d e d i t i o na h a n d s o n, p r o j e c t b a s e d i n t r o d u c t i o n t o p r o g r a m m i n g


    Скачать 6.2 Mb.
    НазваниеCrash course2 n d e d i t i o na h a n d s o n, p r o j e c t b a s e d i n t r o d u c t i o n t o p r o g r a m m i n g
    Дата28.06.2022
    Размер6.2 Mb.
    Формат файлаpdf
    Имя файлаМэтиз. Изучаем Python.pdf
    ТипДокументы
    #618322
    страница18 из 52
    1   ...   14   15   16   17   18   19   20   21   ...   52
    eric
    Last name: matthes
    Hello, Eric Matthes!
    Please tell me your name:
    (enter 'q' at any time to quit)
    First name: q

    156 Глава 8 • Функции
    УПРАЖНЕНИЯ
    8.6. Названия городов: напишите функцию city_country()
    , которая получает название го- рода и страну. Функция должна возвращать строку в формате "Santiago,
    Chile"
    . Вызовите свою функцию по крайней мере для трех пар «город — страна» и выведите возвращенное значение.
    8.7. Альбом: напишите функцию make_album()
    , которая строит словарь с описанием му- зыкального альбома. Функция должна получать имя исполнителя и название альбома и возвращать словарь, содержащий эти два вида информации. Используйте функцию для создания трех словарей, представляющих разные альбомы. Выведите все возвращае- мые значения, чтобы показать, что информация правильно сохраняется во всех трех сло- варях.
    Добавьте в make_album()
    дополнительный параметр для сохранения количества дорожек в альбоме, имеющий значение по умолчанию
    None
    . Если в строку вызова включено значе- ние количества дорожек, добавьте это значение в словарь альбома. Создайте как минимум один новый вызов функции с передачей количества дорожек в альбоме.
    8.8. Пользовательские альбомы: начните с программы из упражнения 8.7. Напишите цикл while
    , в котором пользователь вводит исполнителя и название альбома. Затем в цикле вы- зывается функция make_album()
    для введенных пользователей и выводится созданный сло- варь. Не забудьте предусмотреть признак завершения в цикле while.
    Передача списка
    Часто при вызове функции удобно передать список — имен, чисел или более сложных объектов (например, словарей). При передаче списка функция получает прямой доступ ко всему его содержимому. Мы воспользуемся функциями для того, чтобы сделать работу со списком более эффективной.
    Допустим, вы хотите вывести приветствие для каждого пользователя из списка.
    В следующем примере список имен передается функции greet_users()
    , которая выводит приветствие для каждого пользователя по отдельности:
    greet_users.py
    def greet_users(names):
    """Вывод простого приветствия для каждого пользователя в списке."""
    for name in names:
    msg = f"Hello, {name.title()}!"
    print(msg)

    usernames = ['hannah', 'ty', 'margot']
    greet_users(usernames)
    В соответствии со своим определением функция greet_users()
    рассчитывает полу- чить список имен, который сохраняется в параметре names
    . Функция перебирает полученный список и выводит приветствие для каждого пользователя. В точке  мы определяем список пользователей usernames
    , который затем передается greet_
    users()
    в вызове функции:

    Передача списка 157
    Hello, Hannah!
    Hello, Ty!
    Hello, Margot!
    Результат выглядит именно так, как ожидалось. Каждый пользователь получает персональное сообщение, и эту функцию можно вызвать для каждого нового на- бора пользователей.
    Изменение списка в функции
    Если вы передаете список функции, код функции сможет изменить список. Все изменения, внесенные в список в теле функции, закрепляются, что позволяет эф- фективно работать со списком даже при больших объемах данных.
    Допустим, компания печатает на 3D-принтере модели, предоставленные пользо- вателем. Проекты хранятся в списке, а после печати перемещаются в отдельный список. В следующем примере приведена реализация, не использующая функции:
    printing_models.py
    # Список моделей, которые необходимо напечатать.
    unprinted_designs = ['phone case', 'robot pendant', 'dodecahedron']
    completed_models = []
    # Цикл последовательно печатает каждую модель до конца списка.
    # После печати каждая модель перемещается в список completed_models.
    while unprinted_designs:
    current_design = unprinted_designs.pop()
    print(f"Printing model: {current_design}")
    completed_models.append(current_design)
    # Вывод всех готовых моделей.
    print("\nThe following models have been printed:")
    for completed_model in completed_models:
    print(completed_model)
    В начале программы создается список моделей и пустой список completed_models
    , в который каждая модель перемещается после печати. Пока в unprinted_designs остаются модели, цикл while имитирует печать каждой модели: модель удаляется из конца списка, сохраняется в current_design
    , а пользователь получает сообщение о том, что текущая модель была напечатана. Затем модель перемещается в список напечатанных. После завершения цикла выводится список напечатанных моделей:
    Printing model: dodecahedron
    Printing model: robot pendant
    Printing model: phone case
    The following models have been printed: dodecahedron robot pendant phone case

    158 Глава 8 • Функции
    Мы можем изменить структуру этого кода: для этого следует написать две функции, каждая из которых решает одну конкретную задачу. Большая часть кода останется неизменной; просто программа становится более эффективной.
    Первая функция занимается печатью, а вторая выводит сводку напечатанных моделей:

    def print_models(unprinted_designs, completed_models):
    """
    Имитирует печать моделей, пока список не станет пустым.
    Каждая модель после печати перемещается в completed_models.
    """
    while unprinted_designs:
    current_design = unprinted_designs.pop()
    print(f"Printing model: {current_design}")
    completed_models.append(current_design)

    def show_completed_models(completed_models):
    """Выводит информацию обо всех напечатанных моделях."""
    print("\nThe following models have been printed:")
    for completed_model in completed_models:
    print(completed_model)
    unprinted_designs = ['phone case', 'robot pendant', 'dodecahedron']
    completed_models = []
    print_models(unprinted_designs, completed_models)
    show_completed_models(completed_models)
    В точке  определяется функция print_models()
    с двумя параметрами: список моделей для печати и список готовых моделей. Функция имитирует печать каждой модели, последовательно извлекая модели из первого списка и перемещая их во второй список. В точке  определяется функция show_completed_models()
    с одним параметром: списком напечатанных моделей. Функция show_completed_models()
    получает этот список и выводит имена всех напечатанных моделей.
    Программа выводит тот же результат, что и версия без функций, но структура кода значительно улучшилась. Код, выполняющий большую часть работы, разнесен по двум разным функциям; это упрощает чтение основной части программы. Теперь любому разработчику будет намного проще просмотреть код программы и понять, что делает программа:
    unprinted_designs = ['phone case', 'robot pendant', 'dodecahedron']
    completed_models = []
    print_models(unprinted_designs, completed_models)
    show_completed_models(completed_models)
    Программа создает список моделей для печати и пустой список для готовых моде- лей. Затем, поскольку обе функции уже определены, остается вызвать их и передать правильные аргументы. Мы вызываем print_models()
    и передаем два необходимых списка; как и ожидалось, print_models()
    имитирует печать моделей. Затем вызы-

    Передача списка 159
    вается функция 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 заполняется именами напечатанных моделей, как и в предыдущем случае, но исходный список функцией не изменяется.

    160 Глава 8 • Функции
    Несмотря на то что передача копии позволяет сохранить содержимое списка, обыч- но функциям следует передавать исходный список (если у вас нет веских причин для передачи копии). Работа с существующим списком более эффективна, потому что программе не приходится тратить время и память на создание отдельной копии
    (лишние затраты особенно заметны при работе с большими списками).
    УПРАЖНЕНИЯ
    8.9. Сообщения: создайте список с серией коротких сообщений. Передайте список функ- ции show_messages()
    , которая выводит текст каждого сообщения в списке.
    8.10. Отправка сообщений: начните с копии вашей программы из упражнения 8.9. На- пишите функцию send_messages()
    , которая выводит каждое сообщение и перемещает его в новый список с именем sent_messages
    . После вызова функции выведите оба списка и убе- дитесь в том, что перемещение прошло успешно.
    8.11. Архивированные сообщения: начните с программы из упражнения 8.10. Вызовите функцию send_messages()
    для копии списка сообщений. После вызова функции выведите оба списка и убедитесь в том, что в исходном списке остались все сообщения.
    Передача произвольного набора аргументов
    В некоторых ситуациях вы не знаете заранее, сколько аргументов должно быть передано функции. К счастью, 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 упаковывает аргументы в кортеж даже в том случае, если функция получает всего одно значение:
    ('pepperoni',)
    ('mushrooms', 'green peppers', 'extra cheese')

    Передача списка 161
    Теперь команду print можно заменить циклом, который перебирает список топ- пингов и выводит описание заказанной пиццы:
    def make_pizza(*toppings):
    """Выводит описание пиццы."""
    print("\nMaking a pizza with the following toppings:")
    for topping in toppings:
    print(f"- {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(f"\nMaking a {size}-inch pizza with the following toppings:")
    for topping in toppings:
    print(f"- {topping}")
    make_pizza(16, 'pepperoni') make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
    В определении функции Python сохраняет первое полученное значение в параметре size
    . Все остальные значения, следующие за ним, сохраняются в кортеже toppings
    В вызовах функций на первом месте располагается аргумент для параметра size
    , а за ним следуют сколько угодно дополнений.

    162 Глава 8 • Функции
    В итоге для каждой пиццы указывается размер и количество дополнений, и каждый фрагмент информации выводится в положенном месте: сначала размер, а потом топпинги:
    Making a 16-inch pizza with the following toppings:
    - pepperoni
    Making a 12-inch pizza with the following toppings:
    - mushrooms
    - green peppers
    - extra cheese
    ПРИМЕЧАНИЕ В программах часто используется имя обобщенного параметра *args для хранения произвольного набора позиционных аргументов .
    Использование произвольного набора именованных аргументов
    Иногда программа должна получать произвольное количество аргументов, но вы не знаете заранее, какая информация будет передаваться функции. В таких случаях можно написать функцию, получающую столько пар «ключ-значение», сколько указано в команде вызова. Один из возможных примеров — построение пользовательских профилей: вы знаете, что вы получите информацию о пользова- теле, но не знаете заранее, какую именно. Функция build_profile()
    в следующем примере всегда получает имя и фамилию, но также может получать произвольное количество именованных аргументов:
    user_profile.py
    def build_profile(first, last, **user_info):
    """Строит словарь с информацией о пользователе."""

    user_info['first_name'] = first user_info['last_name'] = last return user_info user_profile = build_profile('albert', 'einstein',
    location='princeton',
    field='physics')
    print(user_profile)
    Определение build_profile()
    ожидает получить имя и фамилию пользователя, а также позволяет передать любое количество пар «имя-значение». Две звездочки перед параметром
    **user_info заставляют Python создать пустой словарь с име- нем user_info и упаковать в него все полученные пары «имя-значение». Внутри функции вы можете обращаться к парам «имя-значение» из user_info точно так же, как в любом словаре.
    В теле build_profile()
    в словарь user_info добавляются имя и фамилия, пото- му что эти два значения всегда передаются пользователем  и они еще не были помещены в словарь. Затем словарь user_info возвращается в точку вызова функции.

    Хранение функций в модулях 163
    Вызовем функцию build_profile()
    и передадим ей имя 'albert'
    , фами- лию 'einstein'
    и еще две пары «ключ-значение» — location='princeton'
    и field='physics'
    . Программа сохраняет возвращенный словарь в user_profile и выводит его содержимое:
    {'location': 'princeton', 'field': 'physics',
    'first_name': 'albert', 'last_name': 'einstein'}
    Возвращаемый словарь содержит имя и фамилию пользователя, а в данном случае еще и местонахождение и область исследований. Функция будет работать, сколько бы дополнительных пар «ключ-значение» ни было передано при вызове функции.
    При написании функций допускаются самые разнообразные комбинации пози- ционных, именованных и произвольных значений. Полезно знать о существова- нии всех этих типов аргументов, потому что они часто будут встречаться вам при чтении чужого кода. Только с практическим опытом вы научитесь правильно ис- пользовать разные типы аргументов и поймете, когда следует применять каждый тип; а пока просто используйте самый простой способ, который позволит решить задачу. С течением времени вы научитесь выбирать наиболее эффективный вариант для каждой конкретной ситуации.
    ПРИМЕЧАНИЕ В программах часто используется имя обобщенного параметра
    **kwargs для хранения произвольного набора ключевых аргументов .
    УПРАЖНЕНИЯ
    8.12. Сэндвичи: напишите функцию, которая получает список компонентов сэндвича.
    Функция должна иметь один параметр для любого количества значений, переданных при вызове функции, и выводить описание заказанного сэндвича. Вызовите функцию три раза с разным количеством аргументов.
    8.13. Профиль: начните с копии программы user_profile .py
    (с. 162). Создайте собственный профиль вызовом build_profile()
    , укажите имя, фамилию и три другие пары «ключ- значение» для вашего описания.
    1   ...   14   15   16   17   18   19   20   21   ...   52


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