Разное

Python 3 функции: Встроенные функции | Python 3 для начинающих и чайников

Содержание

Топ-3 функции Python, о которых вы не знали (Наверное) / Хабр

Привет, Хабр! Представляю вашему вниманию перевод статьи «Top 3 Python Functions You Don’t Know About (Probably)» автора Dario Radečić.

Будучи одним из самых популярных языков 21-го века, Python, безусловно, обладает множеством интересных функций, которые стоит изучить подробно. Три из них будут рассмотрены сегодня, каждая — теоретически, а потом и на практических примерах.


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

Вот функции, которые будут рассмотрены в статье:

1. map()

2. filter()

3. reduce()

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

Итак, без лишних слов… Давайте начнем!

map()

Функция «map()» принимает в качестве параметра другую функцию наряду с каким-либо массивом. Идея состоит в том, чтобы применить функцию (переданную в качестве аргумента) к каждому элементу в массиве.

Это пригодится по двум причинам:

  1. Вам не нужно писать цикл
  2. Это быстрее, чем цикл

Давайте посмотрим на это в действии. Я объявлю функцию «num_func()», которая принимает одно число в качестве параметра. Это число возводится в квадрат, делится на 2 и возвращается как таковое. Обратите внимание, что операции были выбраны произвольно, вы можете делать все что угодно внутри функции:

А теперь давайте объявим массив чисел, к которому мы хотим применить «num_func()». Обратите внимание, что «map()» сама вернет объект-отображение, поэтому вам необходимо преобразовать его в список:

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

filter()

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

Как и в случае с «map()», мы можем заранее объявить функцию, а затем передать ее в «filter()» вместе с итерируемым объектом (например, списком).

Давайте посмотрим на это в действии. Я пошел дальше и объявил функцию «more_than_15 ()», которая, как следует из названия, вернет «true», если элемент, заданный в качестве параметра, больше 15:

Далее мы объявляем массив чисел и передаем их в качестве второго параметра в функцию «filter()»:

Как и ожидалось, только три значения удовлетворяют данному условию. Еще раз, ничего революционного здесь, но выглядит намного лучше, чем цикл.

reduce()

Теперь «reduce()». Она немного отличается от предыдущих двух. Для начала мы должны импортировать его из модуля functools. Основная идея заключается в том, что она будет применять данную функцию к массиву элементов и в результате будет возвращать одно значение.

Последняя часть имеет решающее значение — «reduce()» не возвращает массив элементов, он всегда возвращает одно значение. Давайте посмотрим на схему, чтобы конкретизировать эту концепцию:

Вот логика, написанная на случай, если диаграмма не ясна на 100%:

  1. 5 добавляется к 10, результаты в 15
  2. 15 добавляется к 12, результаты в 27
  3. 27 добавляется к 18, результат 45
  4. 45 добавляется к 25, результат 70

И 70 это значение, которое возвращается. Чтобы начать с реализации кода, давайте импортируем функцию уменьшения из модуля functools и объявим функцию, которая возвращает сумму двух чисел:

Теперь мы можем вернуться к диаграмме в коде и убедиться, что все работает как надо:

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

Прежде, чем вы уйдете:

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

Если у вас есть другие примеры, не стесняйтесь поделиться ими в разделе комментариев.

Спасибо за прочтение.

Как сделать функции на Python еще лучше

Собственно, заголовок этой замечательной статьи от Джеффа Кнаппа (Jeff Knupp), автора книги «Writing Idiomatic Python» полностью отражает ее суть. Читайте внимательно и не стесняйтесь комментировать.

Поскольку очень не хотелось оставлять в тексте важный термин латиницей, мы позволили себе перевести слово «docstring» как «докстрока», обнаружив этот термин в нескольких русскоязычных источниках.


В Python, как и в большинстве современных языков программирования, функция – это основной метод абстрагирования и инкапсуляции. Вы, будучи разработчиком, вероятно, написали уже сотни функций. Но функции функциям – рознь. Причем, если писать «плохие» функции, это немедленно скажется на удобочитаемости и поддержке вашего кода. Итак, что же такое «плохая» функция, а еще важнее – как сделать из нее «хорошую»?

Освежим тему

Математика изобилует функциями, правда, припомнить их сложно. Так что давайте вернемся к нашей излюбленной дисциплине: анализу. Вероятно, вам доводилось видеть формулы вроде f(x) = 2x + 3. Это функция под названием f, принимающая аргумент x, а затем «возвращающая» дважды x + 3. Хотя, она и не слишком похожа на те функции, к которым мы привыкли в Python, она совершенно аналогична следующему коду:

def f(x):
    return 2*x + 3

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

Секреты хорошей функции

Что отличает «хорошую» функцию Python от посредственной? Вы удивитесь, как много трактовок допускает слово «хорошая». В рамках этой статьи я буду считать функцию Python «хорошей», если она удовлетворяет большинству пунктов из следующего списка (выполнить все пункты для конкретной функции порой невозможно):

  • Она внятно названа
  • Соответствует принципу единственной обязанности
  • Содержит докстроку
  • Возвращает значение
  • Состоит не более чем из 50 строк
  • Она идемпотентная и, если это возможно, чистая

Многим из вас эти требования могут показаться чрезмерно суровыми. Однако, обещаю: если ваши функции будут соответствовать этим правилам, то получатся настолько прекрасны, что пробьют на слезу даже единорога. Ниже я посвящу по разделу каждому из элементов вышеприведенного списка, а затем завершу повествование, рассказав, как они гармонируют друг с другом и помогают создавать хорошие функции.

Именование

Вот моя любимая цитата на эту тему, часто ошибочно приписываемая Дональду, а на самом деле принадлежащая Филу Карлтону:

В компьютерных науках есть две сложности: инвалидация кэша и именование.

Как бы глупо это ни звучало, именование – действительно сложная штука. Вот пример «плохого» названия функции:

def get_knn_from_df(df):

Теперь плохие названия попадаются мне практически повсюду, но данный пример взят из области Data Science (точнее, машинного обучения), где практикующие специалисты обычно пишут код в блокноте Jupyter, а потом пытаются собрать из этих ячеек удобоваримую программу.

Первая проблема с названием этой функции – в нем используются аббревиатуры. Лучше использовать полные английские слова, а не аббревиатуры и не малоизвестные сокращения. Единственная причина, по которой хочется сокращать слова — не тратить сил на набор лишнего текста, но в любом современном редакторе есть функция автозавершения, поэтому вам придется набрать полное название функции всего один раз. Аббревиатура – это проблема, поскольку зачастую она специфична для предметной области. В вышеприведенном коде knn означает «K-ближайшие соседи», а df означает «DataFrame», структуру данных, повсеместно используемую в библиотеке pandas. Если код будет читать программист, не знающий этих сокращений, то он практически ничего не поймет в названии функции.

Еще в названии этой функции есть два более мелких недочета. Во-первых, слово "get" избыточно. В большинстве грамотно поименованных функций сразу понятно, что данная функция что-то возвращает, что конкретно – отражено в имени. Элемент from_df также не нужен. Либо в докстроке функции, либо (если она находится на периферии) в аннотации типа будет описан тип параметра, если эта информация и так не очевидна из названия параметра.

Так как же нам переименовать эту функцию? Просто:

def k_nearest_neighbors(dataframe):

Теперь даже неспециалисту понятно, что вычисляется в этой функции, а имя параметра (dataframe) не оставляет сомнений, какой аргумент ей следует передавать.

Единственная ответственность

Развивая мысль Боба Мартина, скажу, что Принцип единственной ответственности касается функций не меньше, чем классов и модулей (о которых изначально и писал господин Мартин). Согласно этому принципу (в нашем случае) у функции должна быть единственная ответственность. То есть, она должна делать одну и только одну вещь. Один из самых веских доводов в пользу этого: если функция делает всего одну вещь, то и переписывать ее придется в единственном случае: если эту самую вещь придется делать по-новому. Также становится ясно, когда функцию можно удалить; если, внеся изменения где-то в другом месте, мы поймем, что единственная обязанность функции более не актуальна, то мы от нее просто избавимся.

Здесь лучше привести пример. Вот функция, делающая более одной «вещи»:

def calculate_and print_stats(list_of_numbers):
    sum = sum(list_of_numbers)
    mean = statistics.mean(list_of_numbers)
    median = statistics.median(list_of_numbers)
    mode = statistics.mode(list_of_numbers)

    print('-----------------Stats-----------------')
    print('SUM: {}'.format(sum)
    print('MEAN: {}'.format(mean)
    print('MEDIAN: {}'.format(median)
    print('MODE: {}'.format(mode)

А именно две: вычисляет набор статистических данных о списке чисел и выводит их в STDOUT. Функция нарушает правило: должна быть единственная конкретная причина, по которой ее, возможно, потребовалось бы изменить. В данном случае просматриваются две очевидные причины, по которым это понадобится: либо потребуется вычислять новую или иную статистику, либо потребуется изменить формат вывода. Поэтому данную функцию лучше переписать в виде двух отдельных функций: одна будет выполнять вычисления и возвращать их результаты, а другая – принимать эти результаты и выводить их в консоль. Функцию (вернее, наличие у нее двух обязанностей) с потрохами выдает слово and в ее названии.

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

На самом деле, функции, выполняющие ровно две вещи, встречаются редко. Гораздо чаще натыкаешься на функции, делающие намного, намного больше операций. Опять же, из соображений удобочитаемости и тестируемости такие «многостаночные» функции следует дробить на однозадачные, в каждой из которых заключен единственный аспект работы.

Докстроки

Казалось бы, все в курсе, что есть документ PEP-8, где даются рекомендации по стилю кода на Python, но гораздо меньше среди нас тех, кто знает PEP-257, в котором такие же рекомендации даются по поводу докстрок. Чтобы не пересказывать содержание PEP-257, отсылаю вас самих к этому документу – почитайте в свободное время. Однако, основные его идеи таковы:

  • Для каждой функции нужна докстрока
  • В ней следует соблюдать грамматику и пунктуацию; писать законченными предложениями
  • Докстрока начинается с краткого (в одно предложение) описания того, что делает функция
  • Докстрока формулируется в предписывающем, а не в описательном стиле

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

Возвращаемые значения

Функции можно (и следует) трактовать как маленькие самодостаточные программы. Они принимают некоторый ввод в форме параметров и возвращают результат. Параметры, конечно, опциональны. А вот возвращаемые значения обязательны с точки зрения внутреннего устройства Python. Если вы даже попытаетесь написать функцию, которая не возвращает значения – не сможете. Если функция даже не станет возвращать значения, то интерпретатор Python «принудит» ее возвращать None. Не верите? Попробуйте сами:

❯ python3
Python 3.7.0 (default, Jul 23 2018, 20:22:55)
[Clang 9.1.0 (clang-902.0.39.2)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> def add(a, b):
...   print(a + b)
...
>>> b = add(1, 2)
3
>>> b
>>> b is None
True

Как видите, значение b – по сути None. Итак, даже если вы напишете функцию без инструкции return, она все равно будет что-то возвращать. И должна. В конце концов, это ведь маленькая программа, верно? Насколько полезны программы, от которых нет никакого вывода – и поэтому невозможно судить, верно ли выполнилась данная программа? Но самое важное – как вы собираетесь тестировать такую программу?

Я даже не побоюсь утверждать следующее: каждая функция должна возвращать полезное значение, хотя бы ради тестируемости. Код, который я пишу, должен быть протестирован (это не обсуждается). Только представьте, каким корявым может получится тестирование вышеприведенной функции add (подсказка: вам придется перенаправлять ввод/вывод, после чего вскоре все пойдет наперекосяк). Кроме того, возвращая значение, мы можем выполнять сцепление методов и, следовательно, писать код вот так:

with open('foo.txt', 'r') as input_file:
    for line in input_file:
        if line.strip().lower().endswith('cat'):
            # ... делаем с этими строками что-нибудь полезное

Строка if line.strip().lower().endswith('cat'): работает, поскольку каждый из строковых методов (strip(), lower(), endswith()) в результате вызова функции возвращает строку.

Вот несколько распространенных доводов, которые вам может привести программист, объясняя, почему написанная им функция не возвращает значения:

«Она всего лишь [какая-то операция, связанная с вводом/выводом, например, сохранение значения в базе данных]. Здесь я не могу вернуть ничего полезного.»

Не соглашусь. Функция может вернуть True, если операция завершилась успешно.

«Здесь мы изменяем один из имеющихся параметров, используем его как ссылочный параметр.»»»

Здесь – два замечания. Во-первых, всеми силами старайтесь так не делать. Во-вторых, снабжать функцию каким-либо аргументом лишь для того, чтобы узнать, что она изменилась – в лучшем случае удивительно, а в худшем – попросту опасно. Вместо этого, как и при работе со строковыми методами, старайтесь возвращать новый экземпляр параметра, в котором уже отражены примененные к нему изменения. Даже если это не получается делать, поскольку создание копии какого-то параметра сопряжено с чрезмерными издержками, все равно можно откатываться к предложенному выше варианту «Вернуть True, если операция завершилась успешно».

«Мне нужно возвращать несколько значений. Нет такого единственного значения, которое в данном случае было бы целесообразно возвращать.»

Этот аргумент немного надуманный, но мне доводилось его слышать. Ответ, разумеется, как раз в том, что автор и хотел сделать – но не знал как: для возврата нескольких значений используйте кортеж.

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

Длина функции

Я не раз признавался, что довольно туп. Могу одновременно держать в голове примерно три вещи. Если вы дадите мне прочесть 200-строчную функцию и спросите, что она делает, я, вероятно, буду таращиться на нее не менее 10 секунд. Длина функции прямо сказывается на ее удобочитаемости и, следовательно, на поддержке. Поэтому старайтесь, чтобы ваши функции оставались короткими. 50 строк – величина, взятая совершенно с потолка, но мне она кажется разумной. (Надеюсь), что большинство функций, которые вам доведется писать, будут значительно короче.

Если функция соответствует Принципу единственной ответственности, то, вероятно, она будет достаточно краткой. Если она читая или идемпотентная (об этом мы поговорим) ниже – то, наверное, она также получится короткой. Все эти идеи гармонично сочетаются друг с другом и помогают писать хороший, чистый код.

Итак, что же делать, если ваша функция получилась слишком длинной? РЕФАКТОРИТЬ! Вероятно, вам приходится заниматься рефакторингом постоянно, даже если вы не знаете этого термина. Рефакторинг – это попросту изменение структуры программы, без изменения ее поведения. Поэтому, извлечение нескольких строк кода из длинной функции и превращение их в самостоятельную функцию – это один из типов рефакторинга. Оказывается, это еще и наиболее распространенный, и самый быстрый способ продуктивного укорачивания длинных функций. Поскольку вы даете этим новым функциям подходящие имена, получающийся у вас код гораздо проще читать. Я написал целую книгу о рефакторинге (на самом деле, я им постоянно занимаюсь), так что здесь вдаваться в детали не буду. Просто знайте, что, если у вас есть слишком длинная функция – то ее следует рефакторить.

Идемпотентность и функциональная чистота

Заголовок этого раздела может показаться слегка устрашающим, но концептуально раздел прост. Идемпотентная функция при одинаковом наборе аргументов всегда возвращает одно и то же значение, независимо от того, сколько раз ее вызывают. Результат не зависит от нелокальных переменных, изменяемости аргументов или от любых данных, поступающих из потоков ввода/вывода. Следующая функция add_three(number) идемпотентна:

def add_three(number):
    """вернуть *число* + 3."""
    return number + 3

Независимо от того, сколько раз мы вызовем add_three(7), ответ всегда будет равен 10. А вот другой случай – функция, не являющаяся идемпотентной:

def add_three():
    """Вернуть 3 + число, введенное пользователем."""
    number = int(input('Enter a number: '))
    return number + 3

Эта откровенно надуманная функция не идемпотентна, поскольку возвращаемое значение функции зависит от ввода/вывода, а именно – от числа, введенного пользователем. Разумеется, при разных вызовах add_three() возвращаемые значения будут отличаться. Если мы дважды вызовем эту функцию, то пользователь в первом случае может ввести 3, а во втором – 7, и тогда два вызова add_three() вернут 6 и 10 соответственно.

Вне программирования также встречаются примеры идемпотентности – например, по такому принципу устроена кнопка «вверх» у лифта. Нажимая ее в первый раз, мы «уведомляем» лифт, что хотим подняться. Поскольку кнопка идемпотентна, то сколько ее потом ни нажимать – ничего страшного не произойдет. Результат будет всегда одинаков.

Почему идемпотентность так важна

Тестируемость и удобство в поддержке. Идемпотентные функции легко тестировать, поскольку они гарантированно, в любом случае вернут одинаковый результат, если вызвать их с одними и теми же аргументами. Тестирование сводится к проверке того, что при разнообразных вызовах функция всегда возвращает ожидаемое значение. Более того, эти тесты будут быстрыми: скорость тестов – важная проблема, которую часто обходят вниманием при модульном тестировании. А рефакторинг при работе с идемпотентными функциями – вообще легкая прогулка. Не важно, как вы измените код вне функции – результат ее вызова с одними и теми же аргументами всегда будет один и тот же.

Что такое «чистая» функция?

В функциональном программировании функция считается чистой, если она, во-первых, идемпотентна, а во-вторых – не вызывает наблюдаемых побочных эффектов. Не забывайте: функция идемпотентна, если всегда возвращает один и тот же результат при конкретном наборе аргументов. Однако, это не означает, что функция не может влиять на другие компоненты – например, на нелокальные переменные или потоки ввода/вывода. Например, если бы идемпотентная версия вышеприведенной функции add_three(number) выводила результат в консоль, а лишь затем возвращала бы его, она все равно считалась бы идемпотентной, поскольку при ее обращении к потоку ввода/вывода эта операция доступа никак не влияет на значение, возвращаемое от функции. Вызов print() – это просто побочный эффект: взаимодействие с остальной программой или системой как таковой, происходящее наряду с возвратом значения.

Давайте немного разовьем наш пример с add_three(number). Можно написать следующий код, чтобы определить, сколько раз была вызвана add_three(number):

add_three_calls = 0

def add_three(number):
    """Вернуть *число* + 3."""
    global add_three_calls
    print(f'Returning {number + 3}')
    add_three_calls += 1
    return number + 3

def num_calls():
    """Вернуть, сколько раз была вызвана *add_three*."""
    return add_three_calls

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

Чистая функция не оказывает побочных эффектов. Она не только не использует никаких «внешних данных» при расчете значения, но и не взаимодействует с остальной программой/системой, только вычисляет и возвращает указанное значение. Следовательно, хотя наше новое определение add_three(number) остается идемпотентным, эта функция уже не чистая.

В чистых функциях нет инструкций логирования или вызовов print(). При работе они не обращаются к базе данных и не используют соединений с интернетом. Не обращаются к нелокальным переменным и не изменяют их. И не вызывают других не-чистых функций.

Короче говоря, они не оказывают «жуткого дальнодействия», выражаясь словами Эйнштейна (но в контексте информатики, а не физики). Они не изменяют каким-либо образом остальные части программы или системы. В императивном программировании (а именно им вы и занимаетесь, когда пишете код на Python), такие функции – самые безопасные. Они известны своей тестируемостью и удобством в поддержке; более того, поскольку они идемпотентны, тестирование таких функций гарантированно будет столь же быстрым, как и выполнение. Сами тесты также просты: не приходится подключаться к базе данных либо имитировать какие-либо внешние ресурсы, готовить стартовую конфигурацию кода, а по окончании работы не нужно ничего подчищать.

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

Заключение

Вот и все. Оказывается, секрет создания новых функций – никакой не секрет. Просто нужно придерживаться некоторых выверенных наилучших практик и железных правил. Надеюсь, статья вам понравилась. А теперь идите – и перескажите ее друзьям! Давайте договоримся везде и во всех случаях писать отличный код. Или, как минимум, прилагать максимум усилий, чтобы не плодить в этом мире «плохой код». С этим я смогу жить.

Как определять функции в Python 3

В Python есть известные для многих функции:

  • функция Python print() выводит объект на печать в терминале;
  • int() превращает данные в целое число;
  • len() возвращает длину объекта.

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

Начнем с превращения в функцию классический «Hello, World!». Создадим в текстовом редакторе новый файл и назовем его hello.py. Затем определим функцию.

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

В нашем случае определяем функцию с названием hello():

Мы создали начальную инструкцию для создания функции Python 3.

Теперь добавляем вторую строку, в которой устанавливаем инструкции для функции. В примере мы будем печатать в консоли «Hello, World»!

hello.py
def hello():
    print("Hello, World!")

Теперь строковая функция Python полностью определена, но если мы запустим программу, ничего не произойдет, так как мы не вызвали ее. Поэтому вызовем функцию с помощью hello():

hello.py
def hello():
    print("Hello, World!")

hello()

Запускаем программу:

Должно получиться следующее:

Результат

Hello, World!

Функции могут быть и сложнее, чем hello(). В блоке функции Python 3 можно использовать циклы for, условные инструкции и другое.

Например, следующая функция использует условную инструкцию для проверки того, содержит ли значение переменной name гласную, а затем применяет цикл for для итерации по буквам.

names.py

# Определяем функцию names()
def names():
    # Задаем имя переменной с вводом
    name = str(input('Введите имя: '))
    # Проверить, содержит ли имя гласную
    if set('aeiou').intersection(name.lower()):
        print('Имя содержит гласную.')
    else:
        print('Имя не содержит гласную.')

    # Итерация по имени
    for letter in name:
        print(letter)

# Вызываем функцию
names()

Вызов функции Python names(), которую мы определили, задает условную инструкцию и цикл for. Из этого примера видно, как можно организовать код в пределах функции. Также можно определить условное выражение и цикл for как две отдельные функции.

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

Создадим небольшую программу с параметрами x, y и z. Определим функцию, которая суммирует параметры в различных конфигурациях. Она возвращает их сумму. Затем мы вызовем функцию и передадим в нее числа.

add_numbers.py
def add_numbers(x, y, z):
    a = x + y
    b = x + z
    c = y + z
    print(a, b, c)

add_numbers(1, 2, 3)

Мы передали число 1 в параметр x, число 2 в параметр y, и число 3 в параметр z. Эти значения соответствуют каждому параметру в том порядке, в котором они приведены.

Программа выполняет математические вычисления на основе значений параметров:

a = 1 + 2
b = 1 + 3
c = 2 + 3

Функция Python 3 выводит результаты математических расчетов a, b, и c, где a должно равняться 3, b — 4 и c — 5. Запускаем программу:

python add_numbers.py

Результат
3 4 5

Когда значения 1, 2 и 3 мы передаем в качестве параметров функции add_numbers(), то получаем ожидаемый результат.

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

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

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

Создадим Python математическую функцию, которая будет отображать информацию о профиле пользователя. Передадим параметры в функцию в виде username (строка) и followers (число).

profile.py
# Определяем функцию с параметрами
def profile_info(username, followers):
    print("Имя Username: " + username)
    print("Followers: " + str(followers))

В определении функции username и followers находятся в скобках. Блок функции выводит информацию о пользователе в виде строк с применением двух параметров.

Теперь можем вызвать функцию и назначить ей параметры:

profile.py
def profile_info(username, followers):
    print("Имя Username: " + username)
    print("Followers: " + str(followers))

# Вызываем функцию с указанными выше параметрами
profile_info("sammyshark", 945)

# Вызываем функцию с именованными аргументами
profile_info(username="AlexAnglerfish", followers=342)

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

Запускаем программу:

python profile.py

Результат
Username: sammyshark
Followers: 945
Username: AlexAnglerfish
Followers: 342

В результате получаем имена пользователей и количество их подписчиков.

Из следующего примера видим, что для той же программы, но с другим вызовом, можно менять последовательность параметров:

profile.py
def profile_info(username, followers):
    print("Имя Username: " + username)
    print("Followers: " + str(followers))

# Изменяем последовательность параметров
profile_info(followers=820, username="cameron-catfish")

Снова запустив программу, получаем следующее:
Результат
Username: cameron-catfish
Followers: 820

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

Также можно указать значения по умолчанию для обоих параметров. Создадим значение по умолчанию для параметра followers со значением 1:

profile.py
def profile_info(username, followers=1):
    print("Имя Username: " + username)
    print("Followers: " + str(followers))

Теперь можно запустить функцию с параметром username, а число подписчиков по умолчанию будет 1. При желании можно изменить количество пользователей:

profile.py
def profile_info(username, followers=1):
    print("Имя Username: " + username)
    print("Followers: " + str(followers))

profile_info(username="JOctopus")
profile_info(username="sammyshark", followers=945)

Запустив программу командой python profile.py, получаем следующее:

Результат

Username: JOctopus
Followers: 1
Username: sammyshark
Followers: 945

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

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

До сих пор мы использовали print(), а не return. Создадим программу, которая вместо вывода в терминал будет возвращать переменную.

В новом текстовом файле создадим программу, которая будет возводить в квадрат параметр x и возвращать переменную y. Выполняем вызов, чтобы вывести переменную result после запуска функции square() с аргументом 3:

square.py
def square(x):
    y = x ** 2
    return y

result = square(3)
print(result)

Запускаем программу, чтобы увидеть результат:

python square.py

Результат
9

В качестве выходных данных получаем число 9, что и является результатом возведения в квадрат числа 3. Рассмотрим действие инструкции return в программе:

square.py
def square(x):
    y = x ** 2
    # return y

result = square(3)
print(result)

Снова запускаем программу:

python square.py

Результат
None

Без return программа не может вернуть значение, поэтому оно равно None.

В следующем примере математической функции в Python заменим print() из программы add_numbers.py на инструкцию return:

add_numbers.py
def add_numbers(x, y, z):
    a = x + y
    b = x + z
    c = y + z
    return a, b, c

sums = add_numbers(1, 2, 3)
print(sums)

Вне функции объявляем переменную sums, которая равна результату действия функции для чисел 1, 2 и 3 из примера, приведенного выше. Затем выводим переменную sums. Снова запускаем программу, теперь уже с инструкцией return:

python add_numbers.py

Результат

(3, 4, 5)

На выходе получаем те же числа, что и с использованием инструкции print(). Теперь результат предоставлен в виде кортежа, так как в списке выражений инструкции return имеется запятая.

Функции Python немедленно завершаются, когда встречают инструкцию return, независимо от того, возвращают они значение или нет:

return_loop.py
def loop_five():
    for x in range(0, 25):
        print(x)
        if x == 5:
            # Функция останавливается на x == 5
            return
    print("Эта строка не будет выполняться.")

loop_five()

Инструкция return в цикле for завершает функцию, поэтому строка вне цикла не будет выполняться. При использовании инструкции break был бы завершен только цикл, и выполнялась последняя строка print().

Инструкция return завершает функцию и может возвращать значение в случае применения параметров.

Хотя в Python можно вызывать функцию, которая находится в конце программы, во многих языках программирования (таких как C++ и Java) для выполнения программы требуется функция main. Применение функции main() не обязательно, но поможет организовать логику программы, помещая важные элементы в одну функцию.

Начнем с добавления Python функции main() в уже составленную программу hello.py. Оставляем функцию hello() и определяем функцию main():

hello.py
def hello():
    print("Hello, World!")

def main():

Применяем инструкцию print(), чтобы знать, что мы находимся в функции main(). Кроме этого вызовем функцию hello() внутри функции main():

hello.py
def hello():
    print("Hello, World!")

def main():
    print("Это главная функция")
    hello()

Ниже вызываем функцию main():

hello.py
def hello():
    print("Hello, World!")

def main():
    print("Это главная функция.")
    hello()

main()

Теперь запускаем программу:

python hello.py

Получаем следующее:
Результат
Это главная функция.
Hello, World!

Поскольку мы вызвали Python строковую функцию hello() внутри main(), а затем вызвали только функцию main(), то получили текст «Hello, World!» один раз после строки, которая сообщает, что мы находимся в главной функции.

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

На языке Python ‘__main__’ — это имя области, в которой будет выполняться код верхнего уровня. Если программа запускается стандартным вводом или с помощью интерактивного запроса, то __name__ устанавливается равным ‘__main__’.

В связи с этим существует соглашение о применении следующей конструкции:

if __name__ == '__main__':

    # Код для выполнения, когда это главная программа

Так мы получаем возможность использовать программные файлы в качестве:

  • главной программы и запускать ту часть, которая следует после инструкции if;
  • модуля и не запускать то, что следует после инструкции if.

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

Расширим программу names.py и создадим новый файл more_names.py. Объявим в этой программе глобальную переменную и изменим функцию names() так, чтобы инструкции находились в двух отдельных Python функциях.

Первая функция has_vowel() будет проверять, содержит ли строка name гласную. Вторая функция print_letters() выведет все буквы строки name:

more_names.py
# Объявляем глобальную переменную name для применения во всех функциях
name = str(input('Введите имя: '))

# Определяем функцию, чтобы проверить, содержит ли имя гласную букву
def has_vowel():
    if set('aeiou').intersection(name.lower()):
        print('Имя содержит гласную.')
    else:
        print('Имя не содержит гласную.')

# Итерация по буквам в строке имени
def print_letters():
    for letter in name:
        print(letter)

Определим main(), которая содержит вызов Python математических функций has_vowel() и print_letters():

more_names.py
# Объявить имя глобальной переменной для применения во всех функциях
name = str(input('Введите имя: '))

# Определяем функцию, чтобы проверить, содержит ли имя гласную букву
def has_vowel():
    if set('aeiou').intersection(name.lower()):
        print('Имя содержит гласную.')
    else:
        print('Имя не содержит гласную.')

# Итерация по буквам в строке имени
def print_letters():
    for letter in name:
        print(letter)

# Определяем основной метод для вызова других функций
def main():
    has_vowel()
    print_letters()

В конце файла добавляем конструкцию if __name__ == ‘__main__’:. Для запуска всех Python функций вызываем main() после инструкции if.

more_names.py

# Объявляем глобальную переменную name для применения во всех функциях
name = str(input('Введите имя: '))

# Определяем функцию, чтобы проверить, содержит ли имя гласную букву
def has_vowel():
    if set('aeiou').intersection(name.lower()):
        print('Имя содержит гласную.')
    else:
        print('Имя не содержит гласную.')

# Итерация по буквам в строке имени
def print_letters():
    for letter in name:
        print(letter)

# Определяем основной метод для вызова других функций
def main():
    has_vowel()
    print_letters()

# Выполняем функцию main()
if __name__ == '__main__':
    main()

Запускаем программу:

Программа генерирует тот же результат, что и программа names.py, но код в ней лучше организован, и его можно использовать в виде модуля без изменений.

Если не хотите объявлять Python функцию main(), то можете закончить программу так:

more_names.py
...
if __name__ == '__main__':
    has_vowel()
    print_letters()

Применение main() в качестве функции в сочетании с инструкцией if __name__ == ‘__main__’: поможет организовать код в логическом порядке, сделать его модульным и удобным для чтения.

Функции — это блоки кода с инструкциями, которые выполняют действия в рамках программы, делают код модульным и дают возможность использовать его многократно.

Данная публикация является переводом статьи «How To Define Functions in Python 3» , подготовленная редакцией проекта.

Использование функций в Python—Справка | ArcGIS Desktop

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

В ArcPy все функции геообработки представлены в виде функций, однако не все функции являются инструментами геообработки. Кроме инструментов в ArcPy имеется несколько функций для улучшения рабочих процессов геообработки с использованием Python. Функции могут использоваться для создания списков определенных наборов данных, извлечения свойств набора данных, проверки имени таблицы перед ее добавлением в базу геоданных, а также выполнения многих других полезных задач геообработки. Эти функции имеются только в ArcPy, они отсутствуют в числе инструментов ArcGIS, поскольку предназначены для алгоритмов Python.

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

В следующем примере используются две функции ArcPy: GetParameterAsText для получения входного аргумента и Exists для определения, существует ли вход. Функция Exists возвращает логический аргумент (Истина (True) или Ложь (False)).

import arcpy

input = arcpy.GetParameterAsText(0)
if arcpy.Exists(input):
    print("Data exists")
else: 
    print("Data does not exist")

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

import arcpy
import os

# The workspace environment needs to be set before ListFeatureClasses
#    to identify which workspace the list will be based on
#   
arcpy.env.workspace = "c:/data"
out_workspace = "c:/data/results/"
clip_features = "c:/data/testarea/boundary.shp"

# Loop through a list of feature classes in the workspace
#
for fc in arcpy.ListFeatureClasses():
    # Set the output name to be the same as the input name, and 
    #    locate in the 'out_workspace' workspace
    #
    output = os.path.join(out_workspace, fc)

    # Clip each input feature class in the list
    #
    arcpy.Clip_analysis(fc, clip_features, output, 0.1)

Связанные разделы

Python 3: 3 функции, которые следует помнить | by Somethingtoldme | NOP::Nuances of Programming

Многие разработчики, особенно новички, уже активно пишут на Python 3. И хотя в этой версии появилось множество новых функций, многие из них неизвестны или применяются редко. Я расскажу о трёх таких — менее популярных, но очень полезных. С этими функциями я познакомился в других языках и полюбил их, и я считаю, что они действительно делают Python 3 лучше.

Перечисления

Я часто работал с перечислениями в Java и Swift, также продолжаю делать это в Python.

Объявление перечисления в Python очень просто и работает в версиях до 3 (хотя и с ограниченной функциональностью):

from enum import Enum

class State(Enum):
AIR = 0
LAND = 1
SEA = 2

myState = State.AIR

# Вывод: 0
print(myState.value)
# Вывод: AIR
print(myState.name)

В приведенном выше коде видно, что для получения перечисления нужно сначала объявить класс, а затем превратить его в подкласс Enum. Потом вы просто определяете каждое из состояний (State) в следующих строках. В моем случае были доступны AIR, LAND и SEA.

Функциональность, добавленная в Python 3, — это возможность вызовов .value и .name. С их помощью можно получить связанное с состоянием целочисленное значение или строку.

В приведенном выше коде при выводе State.LAND.name возвращается значение LAND, так что теперь функционал охватывает больше, чем просто получение целого числа.

Перечисления пригодятся для получения описания для констант. Например, вместо того, чтобы проверять, равно ли состояние 0 или 1, гораздо лучше узнать, является ли оно State.MOVING или State.STATIONARY, ведь константы могут изменяться. Если кто-то посмотрит на ваш код, MOVING для него будет иметь больше смысла, чем 0. В результате значительно улучшается читаемость.

Для получения дополнительной информации ознакомьтесь с официальной документацией Python 3 по Enum здесь.

Форматирование

Добавленные в Python 3.6 fstrings — отличный способ форматирования текста. Они обеспечивают гораздо большую читабельность и менее подвержены ошибкам в отличие от format, ранее используемого в Python. Вот пример с format:

name = 'Brett'
blog_title = 'Medium'

# Hi, my name is Brett and I am writing on my Medium blog.
a = "Hi, my name is {} and I am writing on my {} blog.".format(name, blog_title)

Как видите, у нас есть пустые скобки в строке, а затем мы перечисляем имена переменных по порядку.

Теперь рассмотрим пример того же кода с помощью fstring. Он гораздо более читабелен и похож на форматирование строки в Swift.

name = 'Brett'
blog_title = 'Medium'

# Hi, my name is Brett and I am writing on my Medium blog.
a = f"Hi, my name is {name} and I am writing on my {blog_title} blog."

Чтобы сделать строку чище, мы просто пишем букву f перед кавычками, а затем вместо того, чтобы оставлять скобки пустыми, помещаем переменные или данные непосредственно в них. Поскольку переменные записываются в самих скобках, не нужно подсчитывать количество элементов, чтобы выяснить, где находится каждая из них — переменные существуют именно там, куда помещаются.

Классы данных

Классы данных, возможно, ещё более скрытая возможность, поэтому объясню кратко. Мне очень нравятся они в Kotlin, поэтому я предпочитаю работать с ними в Python.

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

Представьте, что у вас есть программа, и вы передаете строку и массив чисел между различными классами. Вы могли бы просто использовать такие методы, как pass(str, arr), но лучшим подходом было бы создание класса данных, который содержит только строку в виде поля и массива. С классом данных ваши действия станут понятнее, а выполнять модульное тестирование будет проще.

Я приведу пример, как создать простой класс данных, представляющий трехмерный вектор (он может быть легко расширен для представления любой комбинации различных данных):

from dataclasses import dataclass

# Определение класса данных
@dataclass
class Vector3D:
x: int
y: int
z: int

# Создание вектора
u = Vector3D(1,1,-1)

# Вывод: Vector3D(x=1, y=1, z=-1)
print(u)

Как видите, определение класса данных очень похоже на объявление обычного класса, за исключением того, что мы используем @dataclass перед ним, а затем каждое поле объявляется как name: type.

Хотя функциональность созданного нами Vector3D ограничена, смысл класса данных заключается только в том, чтобы повысить эффективность и уменьшить количество ошибок в коде. Намного лучше передать объект vector3d, чем переменные int.

Для получения более подробной информации о @dataclass ознакомьтесь с официальной документацией Python 3 здесь. Спасибо за чтение!

Читайте также:

Читайте нас в Telegram, VK и Яндекс.Дзен

Параметры и аргументы функций — Документация Python для сетевых инженеров 3.0

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

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

При работе с функциями важно различать:

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

Параметры бывают обязательные и необязательные.

Обязательные:

Необязательные (со значением по умолчанию):

В этом случае a — передавать необязательно.

Аргументы бывают позиционные и ключевые.

def summ(a, b):
    return a + b

Позиционные:

Ключевые:

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

Подробнее типы параметров и аргументов будут рассматриваться позже.

Для того, чтобы функция могла принимать входящие значения, ее нужно
создать с параметрами (файл func_check_passwd.py):

In [1]: def check_passwd(username, password):
   ...:     if len(password) < 8:
   ...:         print('Пароль слишком короткий')
   ...:         return False
   ...:     elif username in password:
   ...:         print('Пароль содержит имя пользователя')
   ...:         return False
   ...:     else:
   ...:         print(f'Пароль для пользователя {username} прошел все проверки')
   ...:         return True
   ...:

В данном случае, у функции два параметра: username и password.

Функция проверяет пароль и возвращает False, если проверки не прошли и
True если пароль прошел проверки:

In [2]: check_passwd('nata', '12345')
Пароль слишком короткий
Out[2]: False

In [3]: check_passwd('nata', '12345lsdkjflskfdjsnata')
Пароль содержит имя пользователя
Out[3]: False

In [4]: check_passwd('nata', '12345lsdkjflskfdjs')
Пароль для пользователя nata прошел все проверки
Out[4]: True

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

In [5]: check_passwd('nata')
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-5-e07773bb4cc8> in <module>
----> 1 check_passwd('nata')

TypeError: check_passwd() missing 1 required positional argument: 'password'

Аналогично, возникнет ошибка, если передать три и больше аргументов.

Создание функции Python из командной строки (Функции Azure)



  • Чтение занимает 8 мин

В этой статье

В этой статье используются средства командной строки для создания функции Python, которая отвечает на HTTP-запросы.In this article, you use command-line tools to create a Python function that responds to HTTP requests. После тестирования кода в локальной среде его необходимо развернуть в бессерверной среде Функций Azure.After testing the code locally, you deploy it to the serverless environment of Azure Functions.

Выполнение этого краткого руководства предполагает небольшую дополнительную плату в несколько центов США в учетной записи Azure.Completing this quickstart incurs a small cost of a few USD cents or less in your Azure account.

Существует также версия этой статьи для Visual Studio Code.There is also a Visual Studio Code-based version of this article.

Настройка локальной средыConfigure your local environment

Перед началом работы убедитесь, что у вас есть такие компоненты.Before you begin, you must have the following:

Проверка предварительных условийPrerequisite check

Убедитесь, что предварительные требования (зависят от того, используете ли вы Azure CLI или Azure PowerShell для создания ресурсов Azure) выполнены:Verify your prerequisites, which depend on whether you are using Azure CLI or Azure PowerShell for creating Azure resources:

  • В окне терминала или командном окне запустите func --version, чтобы убедиться, что используется версия Azure Functions Core Tools 3.x.In a terminal or command window, run func --version to check that the Azure Functions Core Tools are version 3.x.

  • Выполните команду az --version, чтобы убедиться, что используется версия Azure CLI 2.4 или более поздняя.Run az --version to check that the Azure CLI version is 2.4 or later.

  • Выполните команду az login, чтобы войти в Azure и проверить активную подписку.Run az login to sign in to Azure and verify an active subscription.

  • Выполните команду python --version (в ОС Linux и MacOS) или py --version (в ОС Windows), чтобы убедиться, что для Python возвращается версия 3.8.x, 3.7.x или 3.6.x.Run python --version (Linux/macOS) or py --version (Windows) to check your Python version reports 3.8.x, 3.7.x or 3.6.x.

  • В окне терминала или командном окне запустите func --version, чтобы убедиться, что используется версия Azure Functions Core Tools 3.x.In a terminal or command window, run func --version to check that the Azure Functions Core Tools are version 3.x.

  • Выполните команду (Get-Module -ListAvailable Az).Version и убедитесь, что используется версия 5.0 или более поздняя.Run (Get-Module -ListAvailable Az).Version and verify version 5.0 or later.

  • Выполните команду Connect-AzAccount, чтобы войти в Azure и проверить активную подписку.Run Connect-AzAccount to sign in to Azure and verify an active subscription.

  • Выполните команду python --version (в ОС Linux и MacOS) или py --version (в ОС Windows), чтобы убедиться, что для Python возвращается версия 3.8.x, 3.7.x или 3.6.x.Run python --version (Linux/macOS) or py --version (Windows) to check your Python version reports 3.8.x, 3.7.x or 3.6.x.

Создание и активация виртуальной средыCreate and activate a virtual environment

В подходящей папке выполните следующие команды, чтобы создать и активировать виртуальную среду с именем .venv.In a suitable folder, run the following commands to create and activate a virtual environment named .venv. Обязательно используйте Python 3.8, 3.7 или 3.6, которые поддерживают Функции Azure.Be sure to use Python 3.8, 3.7 or 3.6, which are supported by Azure Functions.

python -m venv .venv
source .venv/bin/activate

Если пакет venv не установлен Python для вашего дистрибутива Linux, выполните следующую команду:If Python didn’t install the venv package on your Linux distribution, run the following command:

sudo apt-get install python3-venv
py -m venv .venv
.venv\scripts\activate
py -m venv .venv
.venv\scripts\activate

Все последующие команды будут выполняться в этой активированной виртуальной среде.You run all subsequent commands in this activated virtual environment.

Создание локального проекта службы «Функции»Create a local function project

В Функциях Azure проект функций представляет собой контейнер для одной или нескольких отдельных функций, каждая из которых реагирует на конкретный триггер.In Azure Functions, a function project is a container for one or more individual functions that each responds to a specific trigger. Все функции в проекте совместно используют те же локальные конфигурации и конфигурации размещения.All functions in a project share the same local and hosting configurations. В этом разделе вы создадите проект функций, содержащий одну функцию.In this section, you create a function project that contains a single function.

  1. Выполните команду func init, как показано ниже, чтобы создать проект функций в папке с именем LocalFunctionProj с указанной средой выполнения:Run the func init command, as follows, to create a functions project in a folder named LocalFunctionProj with the specified runtime:

    func init LocalFunctionProj --python
    
  2. Перейдите в папку проекта:Navigate into the project folder:

    cd LocalFunctionProj
    

    Эта папка содержит различные файлы проекта, в том числе файлы конфигурации local.settings.json и host.json.This folder contains various files for the project, including configurations files named local.settings.json and host.json. Файл local.settings.json может содержать секреты, скачанные из Azure, поэтому файл по умолчанию исключен из системы управления версиями в GITIGNORE-файле.Because local.settings.json can contain secrets downloaded from Azure, the file is excluded from source control by default in the .gitignore file.

  3. Добавьте функцию в проект с помощью приведенной ниже команды, где аргумент --name — уникальное имя функции (HttpExample), а аргумент --template позволяет указать триггер функции (HTTP).Add a function to your project by using the following command, where the --name argument is the unique name of your function (HttpExample) and the --template argument specifies the function’s trigger (HTTP).

    func new --name HttpExample --template "HTTP trigger" --authlevel "anonymous"
    

    Команда func new создает вложенную папку с именем функции. Эта папка содержит файл кода на выбранном для проекта языке и файл конфигурации function.json.func new creates a subfolder matching the function name that contains a code file appropriate to the project’s chosen language and a configuration file named function.json.

Проверка содержимого файла (дополнительно)(Optional) Examine the file contents

При необходимости можно сразу перейти к локальному запуску функции и просмотреть содержимое файла позже.If desired, you can skip to Run the function locally and examine the file contents later.

__init__.py__init__.py

__init__.py содержит функцию Python main(), которая активируется в соответствии с конфигурацией в function.json.__init__.py contains a main() Python function that’s triggered according to the configuration in function.json.

import logging

import azure.functions as func


def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    name = req.params.get('name')
    if not name:
        try:
            req_body = req.get_json()
        except ValueError:
            pass
        else:
            name = req_body.get('name')

    if name:
        return func.HttpResponse(f"Hello, {name}. This HTTP triggered function executed successfully.")
    else:
        return func.HttpResponse(
             "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response.",
             status_code=200
        )

Для триггера HTTP функция получает данные запроса в переменной req, как определено в файле function.json.For an HTTP trigger, the function receives request data in the variable req as defined in function.json. req — это экземпляр класса azure.functions.HttpRequest.req is an instance of the azure.functions.HttpRequest class. Возвращаемый объект, определенный как $return в файле function.json, — это экземпляр класса azure.functions.HttpResponse.The return object, defined as $return in function.json, is an instance of azure.functions.HttpResponse class. Дополнительные сведения см. в статье Триггеры и привязки HTTP в службе «Функции Azure».To learn more, see Azure Functions HTTP triggers and bindings.

function.jsonfunction.json

function.json — это файл конфигурации, который определяет входные и выходные данные для функции bindings, в том числе тип триггера.function.json is a configuration file that defines the input and output bindings for the function, including the trigger type.

При необходимости можно изменить scriptFile, чтобы вызывать другой файл Python.You can change scriptFile to invoke a different Python file if desired.

{
    "scriptFile": "__init__.py",
    "bindings": [
        {
            "authLevel": "function",
            "type": "httpTrigger",
            "direction": "in",
            "name": "req",
            "methods": [
                "get",
                "post"
            ]
        },
        {
            "type": "http",
            "direction": "out",
            "name": "$return"
        }
    ]
}

Для каждой привязки требуется направление, тип и уникальное имя.Each binding requires a direction, a type, and a unique name. В HTTP-триггере есть входная привязка типа httpTrigger и выходная привязка типа http.The HTTP trigger has an input binding of type httpTrigger and output binding of type http.

Локальное выполнение функцииRun the function locally

  1. Выполните функцию, запустив локальное хост-приложение среды выполнения Функций Azure из папки LocalFunctionProj:Run your function by starting the local Azure Functions runtime host from the LocalFunctionProj folder:

    func start
    

    Ближе к концу выходных данных появятся следующие строки:Toward the end of the output, the following lines should appear:

     ...
    
     Now listening on: http://0.0.0.0:7071
     Application started. Press Ctrl+C to shut down.
    
     Http Functions:
    
             HttpExample: [GET,POST] http://localhost:7071/api/HttpExample
     ...
    
     

    Примечание

    Если результат HttpExample не похож на пример выше, скорее всего, вы запустили основное приложение из папки, отличной от корневой папки проекта.If HttpExample doesn’t appear as shown above, you likely started the host from outside the root folder of the project. В этом случае остановите хост-приложение клавишами CTRL+C, перейдите в корневую папку проекта и снова выполните указанную выше команду.In that case, use Ctrl+C to stop the host, navigate to the project’s root folder, and run the previous command again.

  2. Скопируйте URL-адрес функции HttpExample из этих выходных данных в браузер и добавьте строку запроса ?name=<YOUR_NAME>, сформировав полный URL-адрес, например http://localhost:7071/api/HttpExample?name=Functions.Copy the URL of your HttpExample function from this output to a browser and append the query string ?name=<YOUR_NAME>, making the full URL like http://localhost:7071/api/HttpExample?name=Functions. В браузере должно отобразиться сообщение, например Hello Functions:The browser should display a message like Hello Functions:

  3. Терминал, в котором вы запустили проект, также выводит данные журнала при выполнении запросов.The terminal in which you started your project also shows log output as you make requests.

  4. Когда все будет готово, нажмите клавиши CTRL+C и выберите y, чтобы отключить хост-приложение функции.When you’re done, use Ctrl+C and choose y to stop the functions host.

Создание вспомогательных ресурсов Azure для функцииCreate supporting Azure resources for your function

Прежде чем развернуть код функции в Azure, необходимо создать три ресурса:Before you can deploy your function code to Azure, you need to create three resources:

  • группу ресурсов — логический контейнер связанных ресурсов;A resource group, which is a logical container for related resources.
  • учетную запись хранения — для сохранения состояния и других сведений о проектах;A Storage account, which maintains state and other information about your projects.
  • приложение-функцию — среду для выполнения кода функции.A function app, which provides the environment for executing your function code. Оно сопоставляется с локальным проектом функций и позволяет группировать функции в логические единицы, чтобы упростить развертывание, масштабирование и совместное использование ресурсов, а также управление ими.A function app maps to your local function project and lets you group functions as a logical unit for easier management, deployment, and sharing of resources.

Чтобы создать эти элементы, выполните следующие команды:Use the following commands to create these items. Поддерживается Azure CLI и PowerShell.Both Azure CLI and PowerShell are supported.

  1. Войдите в Azure, если вы еще этого не сделали:If you haven’t done so already, sign in to Azure:

    az login
    

    Чтобы войти в учетную запись Azure, выполните команду az login.The az login command signs you into your Azure account.

    Connect-AzAccount
    

    Чтобы войти в учетную запись Azure, выполните командлет Connect-AzAccount.The Connect-AzAccount cmdlet signs you into your Azure account.

  2. Создайте группу ресурсов с именем AzureFunctionsQuickstart-rg в регионе westeurope.Create a resource group named AzureFunctionsQuickstart-rg in the westeurope region.

    az group create --name AzureFunctionsQuickstart-rg --location westeurope
    

    Чтобы создать группу ресурсов, выполните команду az group create.The az group create command creates a resource group. Группу ресурсов и ресурсы целесообразно создавать в ближайшем к вам регионе. Для этого используйте команду az account list-locations.You generally create your resource group and resources in a region near you, using an available region returned from the az account list-locations command.

    New-AzResourceGroup -Name AzureFunctionsQuickstart-rg -Location westeurope
    

    Команда New-AzResourceGroup создает группу ресурсов.The New-AzResourceGroup command creates a resource group. Группу ресурсов и ресурсы целесообразно создавать в ближайшем к вам регионе. Для этого используйте командлет Get-AzLocation.You generally create your resource group and resources in a region near you, using an available region returned from the Get-AzLocation cmdlet.

    Примечание

    Вы не можете разместить приложения Windows и Linux в одной группе ресурсов.You can’t host Linux and Windows apps in the same resource group. Если у вас есть группа ресурсов AzureFunctionsQuickstart-rg с приложением-функцией Windows или веб-приложением, необходимо использовать другую группу ресурсов.If you have an existing resource group named AzureFunctionsQuickstart-rg with a Windows function app or web app, you must use a different resource group.

  3. В группе ресурсов и регионе создайте учетную запись хранения общего назначения:Create a general-purpose storage account in your resource group and region:

    az storage account create --name <STORAGE_NAME> --location westeurope --resource-group AzureFunctionsQuickstart-rg --sku Standard_LRS
    

    Создайте учетную запись хранения с помощью команды az storage account create.The az storage account create command creates the storage account.

    New-AzStorageAccount -ResourceGroupName AzureFunctionsQuickstart-rg -Name <STORAGE_NAME> -SkuName Standard_LRS -Location westeurope
    

    Чтобы создать учетную запись хранения, выполните командлет New-AzStorageAccount.The New-AzStorageAccount cmdlet creates the storage account.

    В предыдущем примере замените <STORAGE_NAME> соответствующим именем, которое является уникальным в службе хранилища Azure.In the previous example, replace <STORAGE_NAME> with a name that is appropriate to you and unique in Azure Storage. Имена должны содержать от трех до 24 символов и только в нижнем регистре.Names must contain three to 24 characters numbers and lowercase letters only. Standard_LRS указывает учетную запись общего назначения, которая поддерживается Функциями.Standard_LRS specifies a general-purpose account, which is supported by Functions.

    В этом кратком руководстве с учетной записи хранения будет взиматься плата лишь в несколько центов США.The storage account incurs only a few cents (USD) for this quickstart.

  4. Создайте приложение-функцию в Azure:Create the function app in Azure:

    az functionapp create --resource-group AzureFunctionsQuickstart-rg --consumption-plan-location westeurope --runtime python --runtime-version 3.8 --functions-version 3 --name <APP_NAME> --storage-account <STORAGE_NAME> --os-type linux
    

    Чтобы создать приложение-функцию в Azure, выполните команду az functionapp create.The az functionapp create command creates the function app in Azure. Если вы используете Python 3.7 или 3.6, измените --runtime-version на 3.7 или 3.6 соответственно.If you are using Python 3.7 or 3.6, change --runtime-version to 3.7 or 3.6, respectively.

    New-AzFunctionApp -Name <APP_NAME> -ResourceGroupName AzureFunctionsQuickstart-rg -StorageAccount <STORAGE_NAME> -FunctionsVersion 3 -RuntimeVersion 3.8 -Runtime python -Location 'West Europe'
    

    Чтобы создать приложение-функцию в Azure, выполните командлет New-AzFunctionApp.The New-AzFunctionApp cmdlet creates the function app in Azure. Если вы используете Python 3.7 или 3.6, измените -RuntimeVersion на 3.7 или 3.6 соответственно.If you’re using Python 3.7 or 3.6, change -RuntimeVersion to 3.7 or 3.6, respectively.

    В предыдущем примере замените <STORAGE_NAME> именем учетной записи, использованной на предыдущем шаге, и измените <APP_NAME> на глобально уникальное имя, подходящее вам.In the previous example, replace <STORAGE_NAME> with the name of the account you used in the previous step, and replace <APP_NAME> with a globally unique name appropriate to you. <APP_NAME> также является доменом DNS по умолчанию для приложения-функции.The <APP_NAME> is also the default DNS domain for the function app.

    Эта команда создает приложение-функцию, работающее в указанной языковой среде выполнения в рамках плана использования Функций Azure, который не предусматривает плату за объем, используемый здесь.This command creates a function app running in your specified language runtime under the Azure Functions Consumption Plan, which is free for the amount of usage you incur here. Эта команда также подготавливает связанный экземпляр Application Insights Azure в той же группе ресурсов. Его можно использовать для мониторинга приложения-функции и просмотра журналов.The command also provisions an associated Azure Application Insights instance in the same resource group, with which you can monitor your function app and view logs. Дополнительные сведения см. в разделе Мониторинг функций Azure.For more information, see Monitor Azure Functions. Этот экземпляр не создает затраты, пока вы не активируете его.The instance incurs no costs until you activate it.

Развертывание проекта функций в AzureDeploy the function project to Azure

После того как вы успешно создадите приложение-функцию в Azure, вы сможете развернуть локальный проект функций с помощью команды func azure functionapp publish.After you’ve successfully created your function app in Azure, you’re now ready to deploy your local functions project by using the func azure functionapp publish command.

В следующем примере замените <APP_NAME> на имя своего приложения.In the following example, replace <APP_NAME> with the name of your app.

func azure functionapp publish <APP_NAME>

Команда publish показывает результаты, аналогичные приведенным ниже (усечены для простоты):The publish command shows results similar to the following output (truncated for simplicity):

...

Getting site publishing info...
Creating archive for current directory...
Performing remote build for functions project.

...

Deployment successful.
Remote build succeeded!
Syncing triggers...
Functions in msdocs-azurefunctions-qs:
    HttpExample - [httpTrigger]
        Invoke url: https://msdocs-azurefunctions-qs.azurewebsites.net/api/httpexample

Вызов функции в AzureInvoke the function on Azure

Функция использует триггер HTTP, поэтому ее необходимо вызывать через HTTP-запрос по URL-адресу в браузере или с помощью такого средства, как cURL.Because your function uses an HTTP trigger, you invoke it by making an HTTP request to its URL in the browser or with a tool like curl.

Скопируйте полный URL-адрес вызова Invoke URL, показанный в выходных данных команды publish, в адресную строку браузера, добавив параметр запроса &name=Functions.Copy the complete Invoke URL shown in the output of the publish command into a browser address bar, appending the query parameter &name=Functions. В браузере должны отображаться выходные данные, аналогичные данным при локальном запуске функции.The browser should display similar output as when you ran the function locally.

Запустите curl, используя Invoke URL и добавив параметр &name=Functions.Run curl with the Invoke URL, appending the parameter &name=Functions. Результатом выполнения этой команды должен быть текст Hello Functions.The output of the command should be the text, «Hello Functions.»

Выполните следующую команду, чтобы просмотреть журналы потоковой передачи практически в реальном времени в Application Insights на портале Azure:Run the following command to view near real-time streaming logs in Application Insights in the Azure portal:

func azure functionapp logstream <APP_NAME> --browser

В отдельном окне терминала или в браузере снова вызовите удаленную функцию.In a separate terminal window or in the browser, call the remote function again. В окне терминала отображается подробный журнал выполнения функции в Azure.A verbose log of the function execution in Azure is shown in the terminal.

Очистка ресурсовClean up resources

Если вы намерены перейти к следующему шагу и добавить выходную привязку очереди службы хранилища Azure, можете сохранить все ресурсы, которые пригодятся на этом этапе.If you continue to the next step and add an Azure Storage queue output binding, keep all your resources in place as you’ll build on what you’ve already done.

В противном случае используйте следующую команду, чтобы удалить группу ресурсов и все содержащиеся в ней ресурсы и избежать дополнительных расходов.Otherwise, use the following command to delete the resource group and all its contained resources to avoid incurring further costs.

az group delete --name AzureFunctionsQuickstart-rg
Remove-AzResourceGroup -Name AzureFunctionsQuickstart-rg

Дальнейшие действияNext steps

Возникли проблемы? Сообщите нам!Having issues? Let us know.



Определение функций в Python 3

Введение

Функция — это блок инструкций, который выполняет действие и, однажды определенный, может быть использован повторно. Функции делают код более модульным, позволяя использовать один и тот же код снова и снова.

Python имеет ряд встроенных функций, с которыми вы, возможно, знакомы, в том числе:

  • print () , которая распечатает объект на терминал
  • int () , который преобразует строковый или числовой тип данных в целочисленный тип данных
  • len () , которая возвращает длину объекта

Имена функций включают круглые скобки и могут включать параметры.

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

Определение функции

Начнем с классического «Hello, World!» программу в функцию.

Мы создадим новый текстовый файл в выбранном текстовом редакторе и вызовем программу hello.py . Затем мы определим функцию.

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

В этом случае мы определим функцию с именем hello () :

hello.py

  def hello ():
  

Устанавливает начальную инструкцию для создания функции.

Отсюда мы добавим вторую строку с отступом из 4 пробелов, чтобы предоставить инструкции для того, что делает функция. В этом случае мы напечатаем Hello, World! к консоли:

hello.py

  def hello ():
    print ("Привет, мир!")

  

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

Итак, вне нашего определенного функционального блока, давайте вызовем функцию с помощью hello () :

hello.py

  def hello ():
    print ("Привет, мир!")

Привет()

  

Теперь запустим программу:

  

Вы должны получить следующий результат:

  

Выход

Привет, мир!

Функции могут быть сложнее, чем функция hello () , которую мы определили выше. Например, мы можем использовать для циклов, условных операторов и т. Д. В нашем функциональном блоке.

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

names.py

  # Определить имена функций ()
def names ():
    # Настроить имя переменной с вводом
    name = str (input ('Введите свое имя:'))
    # Проверить, есть ли в имени гласная
    если установлено ('aeiou'). пересечение (name.ниже()):
        print ('Ваше имя содержит гласную.')
    еще:
        print ('Ваше имя не содержит гласных.')

    # Итерировать по имени
    на букву в имени:
        печать (письмо)

# Вызов функции
имена ()

  

Функция names () , которую мы определили выше, устанавливает условный оператор и цикл для , показывая, как можно организовать код в определении функции. Однако, в зависимости от того, что мы намерены использовать в нашей программе и как мы хотим настроить наш код, мы можем захотеть определить условный оператор и цикл для как две отдельные функции.

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

Работа с параметрами

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

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

Давайте создадим небольшую программу, которая принимает параметры x , y и z . Мы создадим функцию, которая складывает параметры вместе в различных конфигурациях. Их суммы будут напечатаны функцией. Затем мы вызовем функцию и передадим ей числа.

add_numbers.py

  def add_numbers (x, y, z):
    а = х + у
    б = х + г
    с = у + г
    печать (a, b, c)

add_numbers (1, 2, 3)

  

Мы передали число 1 in для параметра x , 2 in для параметра y и 3 in для параметра z .Эти значения соответствуют каждому параметру в том порядке, в котором они указаны.

Программа, по сути, выполняет следующую математику на основе значений, которые мы передали в параметры:

  а = 1 + 2
б = 1 + 3
с = 2 + 3
  

Функция также печатает a , b и c , и на основе приведенных выше математических расчетов мы ожидаем, что a будет равно 3 , b будет равно 4 и c. будет 5 .Запустим программу:

  
  

Выход

3 4 5

Когда мы передаем 1 , 2 и 3 в качестве параметров функции add_numbers () , мы получаем ожидаемый результат.

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

Аргументы ключевого слова

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

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

Давайте создадим функцию, которая будет показывать нам информацию профиля пользователя. Мы передадим ему параметры в виде имени пользователя (в виде строки) и подписчиков (в виде целого числа).

profile.py

  # Определить функцию с параметрами
def profile_info (имя пользователя, подписчики):
    print ("Имя пользователя:" + имя пользователя)
    print ("Подписчики:" + str (подписчики))

  

В операторе определения функции имя пользователя и последователи содержатся в скобках функции profile_info () .Блок функции выводит информацию о пользователе в виде строк, используя два параметра.

Теперь мы можем вызвать функцию и назначить ей параметры:

profile.py

  def profile_info (имя пользователя, подписчики):
    print ("Имя пользователя:" + имя пользователя)
    print ("Подписчики:" + str (подписчики))

# Вызов функции с параметрами, указанными выше
profile_info ("саммышарк", 945)

# Вызов функции с ключевыми аргументами
profile_info (username = "AlexAnglerfish", подписчики = 342)

  

В первом вызове функции мы ввели информацию с именем пользователя sammyshark и подписчиками 945 , во втором вызове функции мы использовали ключевое слово arguments, присваивая значения переменным аргумента.

Запустим программу:

  
  

Выход

Имя пользователя: sammyshark Подписчиков: 945 Имя пользователя: AlexAnglerfish Подписчиков: 342

Вывод показывает нам имена пользователей и количество подписчиков для обоих пользователей.

Это также позволяет нам изменять порядок параметров, как в этом примере той же программы с другим вызовом:

profile.py

  def profile_info (имя пользователя, подписчики):
    print ("Имя пользователя:" + имя пользователя)
    print ("Подписчики:" + str (подписчики))

# Изменить порядок параметров
profile_info (подписчики = 820, username = "cameron-catfish")

  

Когда мы снова запустим программу с профилем python .py , мы получим следующий результат:

  

Выход

Имя пользователя: cameron-catfish Подписчиков: 820

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

Значения аргументов по умолчанию

Мы также можем предоставить значения по умолчанию для одного или обоих параметров. Давайте создадим значение по умолчанию для параметра подписчиков со значением 1 :

.

профиль.py

  def profile_info (имя пользователя, подписчики = 1):
    print ("Имя пользователя:" + имя пользователя)
    print ("Подписчики:" + str (подписчики))
  

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

profile.py

  def profile_info (имя пользователя, подписчики = 1):
    print ("Имя пользователя:" + имя пользователя)
    print ("Подписчики:" + str (подписчики))

profile_info (username = "JOctopus")
profile_info (username = "sammyshark", подписчики = 945)
  

Когда мы запускаем программу с профилем python .py , мы получим следующий результат:

  

Выход

Имя пользователя: JOctopus Подписчиков: 1 Имя пользователя: sammyshark Подписчиков: 945

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

Возвращение значения

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

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

До сих пор мы использовали оператор print () вместо оператора return в наших функциях. Давайте создадим программу, которая вместо печати будет возвращать переменную.

В новом текстовом файле с именем square.py мы создадим программу, которая возводит в квадрат параметр x и возвращает переменную y . Мы вызываем вызов для печати переменной result , которая формируется путем выполнения функции square () с переданным ей 3 .

square.py

  def квадрат (x):
    у = х ** 2
    вернуть y

результат = квадрат (3)
печать (результат)

  

Мы можем запустить программу и увидеть результат:

  
  

Выход

9

Целое число 9 возвращается как результат, чего мы и ожидаем, если попросим Python найти квадрат 3.

Чтобы лучше понять, как работает оператор return , мы можем закомментировать оператор return в программе:

кв.py

  def квадрат (x):
    у = х ** 2
    # return y

результат = квадрат (3)
печать (результат)

  

Теперь давайте снова запустим программу:

  
  

Выход

Нет

Без использования здесь оператора return программа не может вернуть значение, поэтому по умолчанию используется значение None .

В качестве другого примера, в приведенной выше программе add_numbers.py мы могли заменить оператор print () на оператор return .

add_numbers.py

  def add_numbers (x, y, z):
    а = х + у
    б = х + г
    с = у + г
    вернуть a, b, c

суммы = add_numbers (1, 2, 3)
печать (суммы)

  

Вне функции, мы устанавливаем переменную sums равной результату функции, принимающей 1 , 2 и 3 , как мы делали выше. Затем мы вызвали печать переменной сумм .

Давайте снова запустим программу, теперь она имеет оператор return :

  
  

Выход

(3, 4, 5)

Мы получаем те же числа 3 , 4 и 5 в качестве выходных данных, которые мы получили ранее с помощью оператора print () в функции.На этот раз он доставляется в виде кортежа, потому что в списке выражений оператора return есть как минимум одна запятая.

Функции немедленно завершаются, когда они попадают в оператор return , независимо от того, возвращают они значение или нет.

return_loop.py

  def loop_five ():
    для x в диапазоне (0, 25):
        печать (х)
        если x == 5:
            # Остановить функцию при x == 5
            возвращаться
    print («Эта строка не будет выполняться.»)

loop_five ()

  

Использование оператора return в цикле для завершает функцию, поэтому строка, находящаяся за пределами цикла, не запускается.Если бы вместо этого мы использовали оператор break , в это время завершился бы только цикл, и была бы запущена последняя строка print () .

Оператор return завершает функцию и может возвращать значение, когда выполняется с параметром.

Использование

main () как функции

Хотя в Python вы можете вызвать функцию внизу своей программы, и она запустится (как мы это делали в приведенных выше примерах), для многих языков программирования (таких как C ++ и Java) для выполнения требуется основная функция .Включение функции main () , хотя и не обязательно, может логически структурировать наши программы Python, объединяя наиболее важные компоненты программы в одну функцию. Это также может облегчить чтение наших программ программистам, не использующим Python.

Начнем с добавления функции main () в программу hello.py , описанную выше. Мы сохраним нашу функцию hello () , а затем определим функцию main () :

hello.py

  def hello ():
    print ("Привет, мир!")

def main ():
  

Давайте включим в функцию main () оператор print () , чтобы сообщить нам, что мы находимся в функции main () .Кроме того, давайте вызовем функцию hello () внутри функции main () :

hello.py

  def hello ():
    print ("Привет, мир!")


def main ():
    print («Это основная функция»)
    Привет()
  

Наконец, внизу программы мы вызовем функцию main () :

hello.py

  def hello ():
    print ("Привет, мир!")

def main ():
    print ("Это основная функция.")
    Привет()

основной()

  

На этом этапе мы можем запустить нашу программу:

  

Получим следующий результат:

  

Выход

Это основная функция.Привет мир!

Поскольку мы вызвали функцию hello () внутри main () , а затем вызвали только main () для запуска, Hello, World! Текст печатается только один раз после строки, которая сообщает нам, что мы находимся в основной функции.

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

В Python '__main__' — это имя области, в которой будет выполняться код верхнего уровня. Когда программа запускается из стандартного ввода, сценария или из интерактивной подсказки, ее __name__ устанавливается равным '__main__' .

Из-за этого существует соглашение использовать следующую конструкцию:

 , если __name__ == '__main__':
    # Код для запуска, если это основная программа
  

Это позволяет использовать программные файлы:

  • в качестве основной программы и запустить то, что следует за оператором if
  • как модуль и не запускать то, что следует за оператором if .

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

Давайте расширим нашу программу names.py выше и создадим новый файл с именем more_names.py . В этой программе мы объявим глобальную переменную и изменим нашу исходную функцию names () так, чтобы инструкции содержались в двух дискретных функциях.

Первая функция, has_vowel () , проверяет, содержит ли строка имени гласную.

Вторая функция print_letters () будет печатать каждую букву строки name .

more_names.py

  # Объявить имя глобальной переменной для использования во всех функциях
name = str (input ('Введите свое имя:'))


# Определить функцию, чтобы проверить, содержит ли имя гласную
def has_vowel ():
    если установлено ('aeiou'). пересечение (name.ниже()):
        print ('Ваше имя содержит гласную.')
    еще:
        print ('Ваше имя не содержит гласных.')


# Перебрать буквы в строке имени
def print_letters ():
    на букву в имени:
        печать (письмо)
  

С такой настройкой давайте определим функцию main () , которая будет содержать вызов функций has_vowel () и print_letters () .

more_names.py

  # Объявить имя глобальной переменной для использования во всех функциях
name = str (input ('Введите свое имя:'))


# Определить функцию, чтобы проверить, содержит ли имя гласную
def has_vowel ():
    если установлено ('aeiou').пересечение (name.lower ()):
        print ('Ваше имя содержит гласную.')
    еще:
        print ('Ваше имя не содержит гласных.')


# Перебрать буквы в строке имени
def print_letters ():
    на букву в имени:
        печать (письмо)


# Определить основной метод, который вызывает другие функции
def main ():
    has_vowel ()
    print_letters ()
  

Наконец, мы добавим конструкцию if __name__ == '__main__': в конец файла. Для наших целей, поскольку мы поместили все функции, которые мы хотели бы выполнять, в функцию main () , мы вызовем функцию main () после этого оператора if .

more_names.py

  # Объявить имя глобальной переменной для использования во всех функциях
name = str (input ('Введите свое имя:'))


# Определить функцию, чтобы проверить, содержит ли имя гласную
def has_vowel ():
    если установлено ('aeiou'). пересечение (name.lower ()):
        print ('Ваше имя содержит гласную.')
    еще:
        print ('Ваше имя не содержит гласных.')


# Перебрать буквы в строке имени
def print_letters ():
    на букву в имени:
        печать (письмо)


# Определить основной метод, который вызывает другие функции
def main ():
    has_vowel ()
    print_letters ()


# Выполнить функцию main ()
если __name__ == '__main__':
    основной()

  

Теперь мы можем запустить программу:

  

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

Если вы не хотите объявлять функцию main () , вы также можете завершить программу следующим образом:

more_names.py

  ...
если __name__ == '__main__':
    has_vowel ()
    print_letters ()
  

Использование main () как функции и оператора if __name__ == '__main__': может организовать ваш код логическим образом, делая его более читаемым и модульным.

Заключение

Функции — это блоки кода инструкций, которые выполняют действия в программе, помогая сделать наш код многоразовым и модульным.

Чтобы узнать больше о том, как сделать ваш код более модульным, вы можете прочитать наше руководство по написанию модулей на Python 3.

Определение вашей собственной функции Python — Настоящий Python

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

Из этого руководства вы узнаете:

  • Как функции работают в Python и почему они полезны
  • Как определить и вызвать вашу собственную функцию Python
  • Механизмы передачи аргументов вашей функции
  • Как вернуть данные из вашей функции обратно в вызывающую среду

Функции в Python

Возможно, вы знакомы с математической концепцией функции .Функция — это связь или отображение между одним или несколькими входами и набором выходов. В математике функция обычно представлена ​​так:

Здесь f — это функция, которая работает на входах x и y . Выход функции: z . Однако функции программирования гораздо более обобщены и универсальны, чем это математическое определение. Фактически, правильное определение и использование функций настолько критично для правильной разработки программного обеспечения, что практически все современные языки программирования поддерживают как встроенные, так и определяемые пользователем функции.

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

>>>

  >>> s = 'foobar'
>>> id (s)
56313440
  

len () возвращает длину переданного ему аргумента:

>>>

  >>> a = ['foo', 'bar', 'baz', 'qux']
>>> len (а)
4
  

any () принимает в качестве аргумента итерацию и возвращает Истина , если какой-либо из элементов в итерации является истинным, и Ложь в противном случае:

>>>

  >>> любое ([False, False, False])
Ложь
>>> любой ([Ложь, Истина, Ложь])
Правда

>>> any (['bar' == 'baz', len ('foo') == 4, 'qux' в {'foo', 'bar', 'baz'}])
Ложь
>>> any (['bar' == 'baz', len ('foo') == 3, 'qux' in {'foo', 'bar', 'baz'}])
Правда
  

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

  1. Какие аргументов (если есть) нужно
  2. Какие значения (если есть) возвращает

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

Когда вы определяете свою собственную функцию Python, она работает точно так же. Где-то в коде вы вызываете функцию Python, и выполнение программы передается в тело кода, составляющего функцию.

Примечание: В этом случае вы будете знать, где находится код и как именно он работает, потому что вы его написали!

Когда функция завершена, выполнение возвращается в то место, где функция была вызвана.В зависимости от того, как вы спроектировали интерфейс функции, данные могут передаваться при вызове функции, а возвращаемые значения могут передаваться обратно после ее завершения.

Важность функций Python

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

  • Подпрограммы
  • Процедуры
  • Методы
  • Подпрограммы

Итак, зачем вообще определять функции? Есть несколько очень веских причин.Давайте пройдемся по нескольким.

Абстракция и возможность повторного использования

Предположим, вы пишете код, который делает что-то полезное. По мере продолжения разработки вы обнаружите, что задача, выполняемая этим кодом, вам часто требуется во многих различных местах вашего приложения. Что вы должны сделать? Что ж, вы можете просто копировать код снова и снова, используя возможность копирования и вставки вашего редактора.

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

Примечание: На первый взгляд это может показаться разумным решением, но в долгосрочной перспективе это может стать кошмаром для обслуживания! Хотя ваш редактор кода может помочь, предоставляя функцию поиска и замены, этот метод подвержен ошибкам, и вы можете легко внести в свой код ошибки, которые будет трудно найти.

Лучшее решение — определить функцию Python, которая выполняет задачу . В любом месте вашего приложения, где вам нужно выполнить задачу, вы просто вызываете функцию. В дальнейшем, если вы решите изменить способ его работы, вам нужно будет изменить код только в одном месте, то есть в том месте, где определена функция. Изменения будут автоматически приняты везде, где вызывается функция.

Абстракция функциональности в определение функции является примером принципа «не повторяйся» (DRY) при разработке программного обеспечения.Это, пожалуй, самая сильная мотивация для использования функций.

Модульность

Функции

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

  # Основная программа

# Код для чтения файла в
<заявление>
<заявление>
<заявление>
<заявление>

# Код для обработки файла
<заявление>
<заявление>
<заявление>
<заявление>

# Код для записи файла
<заявление>
<заявление>
<заявление>
<заявление>
  

В этом примере основная программа — это связка кода, связанного в длинную последовательность, с пробелами и комментариями, которые помогают упорядочить ее.Однако если бы код стал намного длиннее и сложнее, вам было бы все труднее осмысливать его.

В качестве альтернативы вы можете структурировать код примерно так:

  def read_file ():
    # Код для чтения файла в
    <заявление>
    <заявление>
    <заявление>
    <заявление>

def process_file ():
    # Код для обработки файла
    <заявление>
    <заявление>
    <заявление>
    <заявление>

def write_file ():
    # Код для записи файла
    <заявление>
    <заявление>
    <заявление>
    <заявление>


# Основная программа
read_file ()
process_file ()
write_file ()
  

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

Примечание: Ключевое слово def вводит новое определение функции Python. Вы все об этом узнаете очень скоро.

В жизни вы делаете такие вещи все время, даже если не думаете об этом явно.Если бы вы захотели переместить несколько полок, заполненных вещами, из одной стороны гаража в другую, то, надеюсь, вы не станете просто стоять и бесцельно думать: «Ой, блин. Мне нужно перевезти все это туда! Как это сделать???» Вы бы разделили задание на управляемые шаги:

  1. Уберите с полок.
  2. Разобрать полок.
  3. Перенести частей полки через гараж на новое место.
  4. Снова соберите полок.
  5. Перенести вещей через гараж.
  6. Положите вещей обратно на полки.

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

Разделение пространств имен

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

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

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

Надеюсь, вы достаточно убедились в достоинствах функций и хотите их создать! Посмотрим как.

Вызовы функций и определение

Обычный синтаксис для определения функции Python следующий:

  def <имя_функции> ([<параметры>]):
    <заявление (я)>
  

Компоненты определения поясняются в таблице ниже:

Компонент Значение
по умолчанию Ключевое слово, информирующее Python о том, что функция определяется
<имя_функции> Действительный идентификатор Python, который называет функцию
<параметры> Необязательный список параметров, разделенных запятыми, которые могут быть переданы функции
: Пунктуация, обозначающая конец заголовка функции Python (имя и список параметров)
<выписки> Блок действительных операторов Python

Последний элемент, , называется телом функции.Тело — это блок операторов, который будет выполняться при вызове функции. Тело функции Python определяется отступом в соответствии с правилом off-side. Это то же самое, что и блоки кода, связанные со структурой управления, например, if или while statement.

Синтаксис для вызова функции Python следующий:

  <имя_функции> ([<аргументы>])
  

<аргументы> — значения, переданные в функцию.Они соответствуют <параметры> в определении функции Python. Вы можете определить функцию, которая не принимает никаких аргументов, но круглые скобки по-прежнему необходимы. И определение функции, и вызов функции всегда должны включать круглые скобки, даже если они пусты.

Как обычно, вы начнете с небольшого примера, а затем добавите сложности. Помня освященную веками математическую традицию, вы вызовете свою первую функцию Python f () . Вот файл сценария foo.py , который определяет и вызывает f () :

  1def f ():
 2 s = '- Внутри f ()'
 3 отпечатка (ов)
 4
 5print ('Перед вызовом f ()')
 6f ()
 7print ('После вызова f ()')
  

Вот как работает этот код:

  1. Строка 1 использует ключевое слово def , чтобы указать, что функция определяется. Выполнение оператора def просто создает определение f () . Все следующие строки с отступом (строки 2–3) становятся частью тела f () и сохраняются как его определение, но еще не выполняются.

  2. Строка 4 — это небольшой пробел между определением функции и первой строкой основной программы. Хотя это и не является синтаксически необходимым, это приятно иметь. Чтобы узнать больше о пробелах вокруг определений функций Python верхнего уровня, прочтите статью Написание красивого кода Python с помощью PEP 8.

  3. Строка 5 — это первый оператор без отступа, поскольку он не является частью определения f () . Это начало основной программы.Когда выполняется основная программа, этот оператор выполняется первым.

  4. Линия 6 — это звонок на номер f () . Обратите внимание, что пустые круглые скобки всегда требуются как в определении функции, так и при ее вызове, даже если нет параметров или аргументов. Выполнение переходит к f () , и выполняются операторы в теле f () .

  5. Строка 7 — это следующая строка, выполняемая после завершения тела f () .Выполнение возвращается к этому оператору print () .

Последовательность выполнения (или потока управления ) для foo.py показана на следующей диаграмме:

Когда foo.py запускается из командной строки Windows, результат будет следующим:

  C: \ Users \ john \ Documents \ Python \ doc> python foo.py
Перед вызовом f ()
- Внутри f ()
После вызова f ()
  

Иногда вам может понадобиться определить пустую функцию, которая ничего не делает.Это называется заглушкой , которая обычно является временным заполнителем для функции Python, которая будет полностью реализована позже. Как блок в управляющей структуре не может быть пустым, так и тело функции не может быть пустым. Чтобы определить функцию-заглушку, используйте оператор pass :

>>>

  >>> def f ():
...     проходить
...
>>> f ()
  

Как вы можете видеть выше, вызов функции-заглушки синтаксически допустим, но ничего не делает.

Передан аргумент

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

Позиционные аргументы

Самый простой способ передать аргументы функции Python — использовать позиционных аргументов (также называемых обязательных аргументов ).В определении функции вы указываете в скобках список параметров, разделенных запятыми:

>>>

  >>> def f (кол-во, шт., Цена):
... print (f '{qty} {item} cost $ {price: .2f}')
...
  

При вызове функции указывается соответствующий список аргументов:

>>>

  >>> f (6, 'бананы', 1.74)
6 бананов стоят 1,74 доллара
  

Параметры ( qty , item и price ) ведут себя как переменных , которые определены локально для функции.Когда функция вызывается, переданные аргументы ( 6 , «бананы», и 1.74 ) привязывают к параметрам по порядку, как если бы путем присвоения переменной:

Параметр Аргумент
шт. 6
товар бананы
цена 1.74

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

Хотя позиционные аргументы являются наиболее простым способом передачи данных в функцию, они также обеспечивают наименьшую гибкость. Во-первых, порядок аргументов в вызове должен соответствовать порядку параметров в определении.Конечно, ничто не мешает вам указывать позиционные аргументы не по порядку:

>>>

  >>> f ('бананы', 1.74, 6)
бананы 1.74 стоят $ 6.00
  

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

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

>>>

  >>> # Слишком мало аргументов
>>> f (6, 'бананы')
Отслеживание (последний вызов последний):
  Файл "", строка 1, в 
    f (6, 'бананы')
TypeError: f () отсутствует 1 обязательный позиционный аргумент: 'цена'
  

Вы также не можете указать лишние:

>>>

  >>> # Слишком много аргументов
>>> f (6, 'бананы', 1.74, кумкваты)
Отслеживание (последний вызов последний):
  Файл "", строка 1, в 
    f (6, «бананы», 1,74, «кумкват»)
TypeError: f () принимает 3 позиционных аргумента, но было дано 4
  

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

Аргументы ключевого слова

При вызове функции можно указать аргументы в форме <ключевое слово> = <значение> . В этом случае каждое <ключевое слово> должно соответствовать параметру в определении функции Python. Например, ранее определенная функция f () может быть вызвана с аргументами ключевого слова следующим образом:

>>>

  >>> f (qty = 6, item = 'bananas', price = 1,74)
6 бананов стоят 1,74 доллара
  

Ссылка на ключевое слово, которое не соответствует ни одному из заявленных параметров, генерирует исключение:

>>>

  >>> f (qty = 6, item = 'bananas', cost = 1.74)
Отслеживание (последний вызов последний):
  Файл "", строка 1, в 
TypeError: f () получил неожиданный аргумент ключевого слова 'стоимость'
  

Использование аргументов ключевого слова снимает ограничение на порядок аргументов. Каждый аргумент ключевого слова явно обозначает конкретный параметр по имени, поэтому вы можете указать их в любом порядке, и Python все равно будет знать, какой аргумент соответствует какому параметру:

>>>

  >>> f (item = 'bananas', price = 1.74, qty = 6)
6 бананов стоят 1 доллар.74
  

Однако, как и в случае с позиционными аргументами, количество аргументов и параметров должно совпадать:

>>>

  >>> # Еще слишком мало аргументов
>>> f (кол-во = 6, элемент = 'бананы')
Отслеживание (последний вызов последний):
  Файл "", строка 1, в 
    f (кол-во = 6, элемент = 'бананы')
TypeError: f () отсутствует 1 обязательный позиционный аргумент: 'цена'
  

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

Вы можете вызвать функцию, используя как позиционные, так и ключевые аргументы:

>>>

  >>> f (6, цена = 1.74, item = 'bananas')
6 бананов стоят 1,74 доллара

>>> f (6, 'бананы', цена = 1,74)
6 бананов стоят 1,74 доллара
  

Когда присутствуют как позиционные аргументы, так и аргументы ключевого слова, все позиционные аргументы должны идти первыми:

>>>

  >>> f (6, item = 'bananas', 1.74)
SyntaxError: позиционный аргумент следует за аргументом ключевого слова
  

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

Параметры по умолчанию

Если параметр, указанный в определении функции Python, имеет форму <имя> = <значение> , тогда <значение> становится значением по умолчанию для этого параметра. Параметры, определенные таким образом, называются параметрами по умолчанию или дополнительными параметрами . Пример определения функции с параметрами по умолчанию показан ниже:

>>>

  >>> def f (qty = 6, item = 'bananas', price = 1.74):
... print (f '{qty} {item} cost $ {price :.2f} ')
...
  

Когда вызывается эта версия f () , любой аргумент, который не указан, принимает значение по умолчанию:

>>>

  >>> f (4, 'яблоки', 2.24)
4 яблока стоят 2,24 доллара.
>>> f (4, 'яблоки')
4 яблока стоят 1,74 доллара

>>> f (4)
4 банана стоят 1,74 доллара
>>> f ()
6 бананов стоят 1,74 доллара

>>> f (item = 'кумкват', кол-во = 9)
9 кумкватов стоят 1,74 доллара
>>> f (цена = 2,29)
6 бананов стоят 2,29 доллара
  

Итого:

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

Изменяемые значения параметров по умолчанию

Все может стать странным, если вы укажете значение параметра по умолчанию, которое является изменяемым объектом . Рассмотрим это определение функции Python:

>>>

  >>> def f (my_list = []):
... my_list.append ('###')
... вернуть my_list
...
  

f () принимает единственный параметр списка, добавляет строку '###' в конец списка и возвращает результат:

>>>

  >>> f (['foo', 'bar', 'baz'])
['foo', 'bar', 'baz', '###']

>>> f ([1, 2, 3, 4, 5])
[1, 2, 3, 4, 5, '###']
  

Значение по умолчанию для параметра my_list — пустой список, поэтому, если f () вызывается без каких-либо аргументов, возвращаемое значение — это список с одним элементом '###' :

Пока все имеет смысл.Что вы ожидаете, если вызовите f () без каких-либо параметров второй и третий раз? Посмотрим:

>>>

  >>> f ()
['###', '###']
>>> f ()
['###', '###', '###']
  

Ой! Вы могли ожидать, что каждый последующий вызов также будет возвращать одноэлементный список ['###'] , как и первый. Вместо этого возвращаемое значение продолжает расти. Что случилось?

В Python значения параметров по умолчанию определяются только один раз , когда функция определена (то есть, когда выполняется инструкция def ).Значение по умолчанию не переопределяется каждый раз при вызове функции. Таким образом, каждый раз, когда вы вызываете f () без параметра, вы выполняете .append () в том же списке.

Вы можете продемонстрировать это с помощью id () :

>>>

  >>> def f (my_list = []):
... печать (id (my_list))
... my_list.append ('###')
... вернуть my_list
...
>>> f ()
140095566958408
['###']
>>> f ()
140095566958408
['###', '###']
>>> f ()
140095566958408
['###', '###', '###']
  

Отображаемый идентификатор объекта подтверждает, что, когда для my_list разрешено значение по умолчанию, значение будет одним и тем же объектом при каждом вызове.Поскольку списки изменяемы, каждый последующий вызов .append () заставляет список удлиняться. Это распространенная и довольно хорошо задокументированная ошибка, когда вы используете изменяемый объект в качестве значения параметра по умолчанию. Это потенциально приводит к путанице в поведении кода, и, вероятно, лучше этого избегать.

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

>>>

  >>> def f (my_list = None):
... если my_list - None:
... my_list = []
... my_list.append ('###')
... вернуть my_list
...

>>> f ()
['###']
>>> f ()
['###']
>>> f ()
['###']

>>> f (['фу', 'бар', 'баз'])
['foo', 'bar', 'baz', '###']

>>> f ([1, 2, 3, 4, 5])
[1, 2, 3, 4, 5, '###']
  

Обратите внимание, как это гарантирует, что my_list теперь действительно по умолчанию использует пустой список всякий раз, когда f () вызывается без аргумента.

Передача по значению и передача по ссылке в Pascal

В разработке языков программирования есть две общие парадигмы для передачи аргумента функции:

  1. Передаваемое значение: Копия аргумента передается функции.
  2. Передача по ссылке: В функцию передается ссылка на аргумент.

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

Примечание: Не волнуйтесь, если вы не знакомы с Паскалем! Концепции аналогичны концепциям Python, а показанные примеры сопровождаются достаточно подробным объяснением, чтобы вы могли составить общее представление.Как только вы увидели, как передача аргументов работает в Паскале, мы вернемся к Python, и вы увидите, как он сравнивается.

Вот что вам нужно знать о синтаксисе Паскаля:

  • Процедуры: Процедура в Паскале похожа на функцию Python.
  • Двоеточие равно: Этот оператор (: = ) используется для присваивания в Паскале. Это аналог знака равенства ( = ) в Python.
  • Writeln () : Эта функция отображает данные на консоли, аналогично функции print () в Python.

Имея такую ​​основу, вот первый пример Pascal:

  1 // Пример # 1 для Паскаля
 2
 3процедура f (fx: целое число);
 4начать
 5 Writeln ('Начать f (): fx =', fx);
 6 FX: = 10;
 7 Writeln ('Конец f (): fx =', fx);
 8end;
 9
10 // Основная программа
11вар
12 x: целое число;
13
14начало
15 х: = 5;
16 Writeln ('Перед f (): x =', x);
17 f (x);
18 Writeln ('После f (): x =', x);
19 конец.
  

Вот что происходит:

  • Строка 12: Основная программа определяет целочисленную переменную x .
  • Строка 15: Первоначально x присваивается значение 5 .
  • Строка 17: Затем он вызывает процедуру f () , передавая x в качестве аргумента.
  • Строка 5: Внутри f () инструкция writeln () показывает, что соответствующий параметр fx изначально равен 5 , переданному значению.
  • Строка 6: fx затем присваивается значение 10 .
  • Строка 7: Это значение проверяется этим оператором writeln () , выполняемым непосредственно перед выходом из f () .
  • Строка 18: Вернувшись в вызывающую среду основной программы, этот оператор writeln () показывает, что после возврата f () x все еще остается 5 , как это было до вызова процедуры. .

Запуск этого кода дает следующий результат:

  Перед f (): x = 5
Начать f (): fx = 5
Конец f (): fx = 10
После f (): x = 5
  

В этом примере x — это , переданное значением , поэтому f () получает только копию.Когда соответствующий параметр fx изменяется, x не изменяется.

Примечание: Если вы хотите увидеть это в действии, вы можете запустить код самостоятельно, используя онлайн-компилятор Pascal.

Просто выполните следующие действия:

  1. Скопируйте код из поля кода выше.
  2. Посетите онлайн-компилятор Паскаля.
  3. В поле кода слева замените любое существующее содержимое кодом, который вы скопировали на шаге 1.
  4. Щелкните Выполнить .

Вы должны увидеть тот же результат, что и выше.

Теперь сравните это со следующим примером:

  1 // Пример # 2 для Паскаля
 2
 3процедура f (var fx: integer);
 4начать
 5 Writeln ('Начать f (): fx =', fx);
 6 FX: = 10;
 7 Writeln ('Конец f (): fx =', fx);
 8end;
 9
10 // Основная программа
11вар
12 x: целое число;
13
14начало
15 х: = 5;
16 Writeln ('Перед f (): x =', x);
17 f (x);
18 Writeln ('После f (): x =', x);
19 конец.
  

Этот код идентичен первому примеру с одним изменением.Это наличие слова var перед fx в определении процедуры f () в строке 3. Это означает, что аргумент f () , переданный по ссылке . Изменения, внесенные в соответствующий параметр fx , также изменят аргумент в вызывающей среде.

Вывод этого кода такой же, как и раньше, за исключением последней строки:

  Перед f (): x = 5
Начать f (): fx = 5
Конец f (): fx = 10
После f (): x = 10
  

Опять же, fx присваивается значение 10 внутри f () , как и раньше.Но на этот раз, когда возвращается f () , x в основной программе также были изменены.

Во многих языках программирования это, по сути, различие между передачей по значению и передачей по ссылке:

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

Причина, по которой «почему» исходит из того, что означает ссылка на этих языках. Значения переменных хранятся в памяти. В Паскале и подобных языках ссылка — это, по сути, адрес этой ячейки памяти, как показано ниже:

На схеме слева x — это память, выделенная в пространстве имен основной программы. Когда вызывается f () , x — это , переданное значением , поэтому память для соответствующего параметра fx выделяется в пространстве имен f () , а значение x копируется туда. .Когда f () изменяет fx , изменяется именно эта локальная копия. Значение x в среде вызова остается неизменным.

На диаграмме справа x равно , переданному по ссылке . Соответствующий параметр fx указывает на фактический адрес в пространстве имен основной программы, где хранится значение x . Когда f () изменяет fx , он изменяет значение в этом месте, точно так же, как если бы основная программа изменяла саму x .

Передача по значению и передача по ссылке в Python

Являются ли параметры в Python передачей по значению или по ссылке? Ответ таков: ни то, ни другое. Это потому, что ссылка в Python означает не то же самое, что в Паскале.

Напомним, что в Python каждая часть данных представляет собой объект . Ссылка указывает на объект, а не на конкретную ячейку памяти. Это означает, что присваивание не интерпретируется в Python так же, как в Паскале. Рассмотрим следующую пару операторов на Паскале:

Они интерпретируются следующим образом:

  • Переменная x ссылается на конкретную ячейку памяти.
  • Первый оператор помещает в это место значение 5 .
  • Следующий оператор перезаписывает 5 и помещает вместо него 10 .

Напротив, в Python аналогичные операторы присваивания выглядят следующим образом:

Эти операторы присваивания имеют следующее значение:

  • Первый оператор заставляет x указывать на объект, значение которого составляет 5 .
  • Следующий оператор переназначает x как новую ссылку на другой объект, значение которого составляет 10 . Другими словами, второе присвоение повторно привязывает x к другому объекту со значением 10 .

В Python, когда вы передаете аргумент функции, происходит аналогичное повторное связывание . Рассмотрим этот пример:

>>>

  1 >>> def f (fx):
 2 ... fx = 10
 3 ...
 4 >>> х = 5
 5 >>> f (x)
 6 >>> х
 75
  

В основной программе оператор x = 5 в строке 5 создает ссылку с именем x , привязанную к объекту, значение которого равно 5 .Затем в строке 7 вызывается f () с x в качестве аргумента. При первом запуске f () создается новая ссылка с именем fx , которая изначально указывает на тот же объект 5 , что и x :

Однако, когда выполняется инструкция fx = 10 в строке 2, f () выполняет повторную привязку fx к новому объекту, значение которого составляет 10 . Две ссылки, x и fx , не связаны друг с другом на .Ничто другое из того, что делает f () , не повлияет на x , и когда f () завершится, x все равно будет указывать на объект 5 , как это было до вызова функции:

Подтвердить все это можно с помощью id () . Вот слегка расширенная версия приведенного выше примера, которая отображает числовые идентификаторы задействованных объектов:

>>>

  1 >>> def f (fx):
 2 ... печать ('fx =', fx, '/ id (fx) =', id (fx))
 3... fx = 10
 4 ... печать ('fx =', fx, '/ id (fx) =', id (fx))
 5 ...
 6
 7 >>> х = 5
 8 >>> print ('x =', x, '/ id (x) =', id (x))
 9x = 5 / id (x) = 13578
10
11 >>> f (x)
12fx = 5 / id (FX) = 13578
13fx = 10 / id (fx) = 1357

8 14 15 >>> печать ('x =', x, '/ id (x) =', id (x)) 16x = 5 / id (x) = 13578

При первом запуске f () , fx и x указывают на один и тот же объект, чей id () равен 13578 .После того, как f () выполнит оператор fx = 10 в строке 3, fx указывает на другой объект, чей id () равен 1357

8 . Связь с исходным объектом в вызывающей среде теряется.

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

Примечание. Механизм передачи аргументов Python был назван передачей по назначению .Это связано с тем, что имена параметров привязаны к объектам при вводе функции в Python, а присвоение также является процессом привязки имени к объекту. Вы также можете увидеть термины «передача по объекту», «передача по ссылке на объект» или «передача по совместному использованию».

Ключевой вывод здесь заключается в том, что функция Python не может изменить значение аргумента, переназначив соответствующий параметр чему-то другому. Следующий пример демонстрирует это:

>>>

  >>> def f (x):
... x = 'foo'
...
>>> для i в (
... 40,
... dict (foo = 1, bar = 2),
... {1, 2, 3},
...         'бар',
... ['foo', 'bar', 'baz']):
... f (я)
... печать (я)
...
40
{'foo': 1, 'bar': 2}
{1, 2, 3}
бар
['фу', 'бар', 'баз']
  

Здесь объекты типа int , dict , set , str и list передаются в f () в качестве аргументов. f () пытается назначить каждый объект строковому объекту 'foo' , но, как вы можете видеть, вернувшись в вызывающую среду, все они не изменились.Как только f () выполнит присвоение x = 'foo' , ссылка будет rebound , и соединение с исходным объектом будет потеряно.

Означает ли это, что функция Python вообще никогда не может изменять свои аргументы? На самом деле нет, это не так! Посмотрите, что здесь происходит:

>>>

  >>> def f (x):
... x [0] = '---'
...

>>> my_list = ['foo', 'bar', 'baz', 'qux']

>>> f (мой_лист)
>>> мой_лист
['---', 'bar', 'baz', 'qux']
  

В этом случае аргумент f () является списком.Когда вызывается f () , передается ссылка на my_list . Вы уже видели, что f () не может переназначить my_list оптом. Если бы x было назначено чему-то другому, то оно было бы привязано к другому объекту, и соединение с my_list было потеряно.

Однако f () может использовать ссылку для внесения изменений в my_list . Здесь f () модифицировал первый элемент.Вы можете видеть, что после возврата из функции my_list фактически был изменен в вызывающей среде. То же самое относится и к словарю:

>>>

  >>> def f (x):
... x ['bar'] = 22
...

>>> my_dict = {'foo': 1, 'bar': 2, 'baz': 3}

>>> f (my_dict)
>>> my_dict
{'foo': 1, 'bar': 22, 'baz': 3}
  

Здесь f () использует x в качестве ссылки для внесения изменений в my_dict .Это изменение отражается в вызывающей среде после возврата f () .

Сводка по передаче аргументов

Передачу аргумента в Python можно резюмировать следующим образом. Передача неизменяемого объекта , например int , str , tuple или frozenset , в функцию Python действует как передача по значению. Функция не может изменять объект в вызывающей среде.

Передача изменяемого объекта , такого как список , dict или set , действует в некоторой степени - но не совсем - как передача по ссылке.Функция не может переназначить объект оптом, но она может изменять элементы на месте внутри объекта, и эти изменения будут отражены в вызывающей среде.

Побочные эффекты

Итак, в Python вы можете изменить аргумент из функции, чтобы изменение отражалось в вызывающей среде. Но стоит ли вам это делать? Это пример того, что на жаргоне программирования называется побочным эффектом .

В более общем смысле говорят, что функция Python вызывает побочный эффект, если она каким-либо образом изменяет среду своего вызова.Изменение значения аргумента функции - лишь одна из возможностей.

Примечание: Вы, вероятно, знакомы с побочными эффектами из области здоровья человека, где этот термин обычно относится к непреднамеренным последствиям лекарств. Часто последствия нежелательны, например, рвота или седативный эффект. С другой стороны, побочные эффекты могут быть использованы намеренно. Например, некоторые лекарства вызывают стимуляцию аппетита, что может быть полезно, даже если это не является основным назначением лекарства.

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

Когда они скрыты или неожиданны, побочные эффекты могут привести к программным ошибкам, которые очень трудно отследить.Как правило, их лучше избегать.

Возвращение

Заявление

Что тогда делать функции Python? В конце концов, во многих случаях, если функция не вызывает каких-либо изменений в вызывающей среде, тогда нет никакого смысла в ее вызове. Как функция должна влиять на вызывающего?

Что ж, одна из возможностей - использовать возвращаемых значений функции . Оператор return в функции Python служит двум целям:

  1. Он немедленно завершает функцию и передает управление выполнением обратно вызывающей стороне.
  2. Он предоставляет механизм, с помощью которого функция может передавать данные обратно вызывающей стороне.

Выход из функции

Внутри функции оператор return вызывает немедленный выход из функции Python и передачу выполнения обратно вызывающей стороне:

>>>

  >>> def f ():
... печать ('фу')
... печать ('полоса')
...     возвращаться
...

>>> f ()
фу
бар
  

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

Однако, return операторов не обязательно должны быть в конце функции. Они могут появляться в любом месте тела функции и даже несколько раз. Рассмотрим этот пример:

>>>

  1 >>> def f (x):
 2 ... если x <0:
 3...         возвращаться
 4 ... если x> 100:
 5 ... вернуться
 6 ... печать (x)
 7 ...
 8
 9 >>> f (-3)
10 >>> f (105)
11 >>> f (64)
1264
  

Первые два вызова f () не вызывают никакого вывода, потому что выполняется оператор return и функция завершается преждевременно до того, как будет достигнут оператор print () в строке 6.

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

  def f ():
    если error_cond1:
        возвращаться
    если error_cond2:
        возвращаться
    если error_cond3:
        возвращаться

    <нормальная обработка>
  

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

Возврат данных вызывающему абоненту

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

>>>

  1 >>> def f ():
 2 ... вернуть 'foo'
 3 ...
 4
 5 >>> s = f ()
 6 >>> с
 7'фу '
  

Здесь значение выражения f () в строке 5 равно 'foo' , которое впоследствии присваивается переменной s .

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

Например, в этом коде f () возвращает словарь. Тогда в вызывающей среде выражение f () представляет словарь, а f () ['baz'] является действительной ключевой ссылкой в ​​этот словарь:

>>>

  >>> def f ():
... return dict (foo = 1, bar = 2, baz = 3)
...

>>> f ()
{'foo': 1, 'bar': 2, 'baz': 3}
>>> f () ['баз']
3
  

В следующем примере f () возвращает строку, которую можно разрезать, как любую другую строку:

>>>

  >>> def f ():
... вернуть 'foobar'
...

>>> f () [2: 4]
'ob'
  

Здесь f () возвращает список, который можно индексировать или разрезать:

>>>

  >>> def f ():
... return ['foo', 'bar', 'baz', 'qux']
...

>>> f ()
['foo', 'bar', 'baz', 'qux']
>>> f () [2]
'баз'
>>> f () [:: - 1]
['qux', 'baz', 'bar', 'foo']
  

Если в инструкции return указано несколько выражений, разделенных запятыми, они упаковываются и возвращаются как кортеж:

>>>

  >>> def f ():
... вернуть 'foo', 'bar', 'baz', 'qux'
...

>>> тип (f ())
<класс 'кортеж'>
>>> t = f ()
>>> т
('фу', 'бар', 'баз', 'qux')

>>> a, b, c, d = f ()
>>> print (f'a = {a}, b = {b}, c = {c}, d = {d} ')
a = foo, b = bar, c = baz, d = qux
  

Если возвращаемое значение не указано, функция Python возвращает специальное значение Python Нет :

>>>

  >>> def f ():
...     возвращаться
...

>>> print (f ())
Никто
  

То же самое происходит, если тело функции вообще не содержит оператора return и функция отваливается от конца:

>>>

  >>> def g ():
...     проходить
...

>>> print (g ())
Никто
  

Напомним, что Нет является ложным при оценке в логическом контексте.

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

>>>

  >>> def f ():
...     возвращаться
...
>>> def g ():
...     проходить
...

>>> если f () или g ():
... печать ('да')
... еще:
... печать ('нет')
...
нет
  

Здесь вызовы как f () , так и g () являются ложными, поэтому f () или g () также являются, и выполняется предложение else .

Возвращаясь к побочным эффектам

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

  1процедура double (var x: integer);
 2начать
 3 х: = х * 2;
 4end;
 5
 6вар
 7 x: целое число;
 8
 9начало
10 х: = 5;
11 Writeln ('Перед вызовом процедуры:', x);
12 двойных (х);
13 Writeln ('После вызова процедуры:', x);
14 конец.
  

Выполнение этого кода дает следующий результат, который подтверждает, что double () действительно изменяет x в вызывающей среде:

  Перед процедурой вызов: 5
После вызова процедуры: 10
  

В Python это не сработает.Как вы теперь знаете, целые числа Python неизменяемы, поэтому функция Python не может изменить целочисленный аргумент с помощью побочного эффекта:

>>>

  >>> def double (x):
... х * = 2
...

>>> х = 5
>>> двойной (х)
>>> х
5
  

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

>>>

  >>> def double (x):
... вернуть x * 2
...

>>> х = 5
>>> х = двойной (х)
>>> х
10
  

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

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

>>>

  >>> def double_list (x):
... я = 0
... пока я >> a = [1, 2, 3, 4, 5]
>>> double_list (а)
>>> а
[2, 4, 6, 8, 10]
  

В отличие от double () в предыдущем примере, double_list () фактически работает так, как задумано.Если в документации для функции четко указано, что содержимое аргумента списка изменено, это может быть разумной реализацией.

Тем не менее, вы также можете написать double_list () , чтобы передать желаемый список обратно по возвращаемому значению и позволить вызывающей стороне выполнить назначение, аналогично тому, как double () было переписано в предыдущем примере:

>>>

  >>> def double_list (x):
... r = []
... для i в x:
...             р.добавить (я * 2)
... вернуть г
...

>>> a = [1, 2, 3, 4, 5]
>>> а = двойной_лист (а)
>>> а
[2, 4, 6, 8, 10]
  

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

Списки аргументов переменной длины

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

>>>

  >>> def avg (a, b, c):
... return (a + b + c) / 3
...
  

Все хорошо, если вы хотите усреднить три значения:

Однако, как вы уже видели, когда используются позиционные аргументы, количество переданных аргументов должно соответствовать количеству объявленных параметров. Тогда ясно, что с этой реализацией avg () для любого количества значений, кроме трех, не все в порядке:

>>>

  >>> ср (1, 2, 3, 4)
Отслеживание (последний вызов последний):
  Файл "", строка 1, в 
    средн. (1, 2, 3, 4)
TypeError: avg () принимает 3 позиционных аргумента, но было дано 4
  

Вы можете попробовать определить avg () с дополнительными параметрами:

>>>

  >>> def avg (a, b = 0, c = 0, d = 0, e = 0):
....
....
....
...
  

Это позволяет указывать переменное количество аргументов. Следующие вызовы, по крайней мере, синтаксически верны:

  в среднем (1)
ср (1, 2)
средн. (1, 2, 3)
средн. (1, 2, 3, 4)
средн. (1, 2, 3, 4, 5)
  

Но при таком подходе все еще есть несколько проблем. Во-первых, он по-прежнему позволяет использовать до пяти аргументов, а не произвольное число. Что еще хуже, нет способа отличить указанные аргументы от аргументов, которым разрешено использовать по умолчанию.У функции нет способа узнать, сколько аргументов было передано на самом деле, поэтому она не знает, на что делить:

>>>

  >>> def avg (a, b = 0, c = 0, d = 0, e = 0):
... return (a + b + c + d + e) ​​/ # На что делить ???
...
  

Очевидно, и этого не пойдет.

Вы можете написать avg () , чтобы получить единственный аргумент списка:

>>>

  >>> def avg (a):
... всего = 0
... для v в:
... всего + = v
... return total / len (a)
...

>>> avg ([1, 2, 3])
2.0
>>> avg ([1, 2, 3, 4, 5])
3.0
  

По крайней мере, это работает. Он допускает произвольное количество значений и дает правильный результат. В качестве дополнительного бонуса это работает, когда аргумент также является кортежем:

>>>

  >>> t = (1, 2, 3, 4, 5)
>>> avg (t)
3.0
  

Недостатком является то, что дополнительный этап группировки значений в список или кортеж, вероятно, не является тем, чего ожидает пользователь функции, и это не очень элегантно.Всякий раз, когда вы находите код Python, который выглядит неэлегантно, вероятно, есть лучший вариант.

В данном случае действительно есть! Python предоставляет способ передать функции переменное количество аргументов с упаковкой и распаковкой кортежей аргументов с помощью оператора звездочки ( * ).

Упаковка кортежей аргументов

Если перед именем параметра в определении функции Python стоит звездочка ( * ), это указывает на упаковку кортежа аргументов . Все соответствующие аргументы в вызове функции упаковываются в кортеж, на который функция может ссылаться по заданному имени параметра.Вот пример:

>>>

  >>> def f (* args):
... печать (аргументы)
... print (тип (аргументы), len (аргументы))
... для x в аргументах:
... печать (x)
...

>>> f (1, 2, 3)
(1, 2, 3)
<класс 'кортеж'> 3
1
2
3

>>> f ('foo', 'bar', 'baz', 'qux', 'quux')
('foo', 'bar', 'baz', 'qux', 'quux')
<класс 'кортеж'> 5
фу
бар
баз
qux
quux
  

В определении f () спецификация параметра * args указывает на упаковку кортежа.При каждом вызове f () аргументы упаковываются в кортеж, на который функция может ссылаться по имени args . Можно использовать любое имя, но args выбирают настолько часто, что это практически стандарт.

Используя упаковку кортежей, вы можете очистить avg () следующим образом:

>>>

  >>> def avg (* args):
... всего = 0
... для i в аргументах:
... всего + = я
... вернуть total / len (args)
...

>>> avg (1, 2, 3)
2.0
>>> avg (1, 2, 3, 4, 5)
3.0
  

Еще лучше, вы можете привести его в порядок, заменив цикл на на встроенную функцию Python sum () , которая суммирует числовые значения в любой итерации:

>>>

  >>> def avg (* args):
... вернуть сумму (аргументы) / len (аргументы)
...

>>> avg (1, 2, 3)
2.0
>>> avg (1, 2, 3, 4, 5)
3.0
  

Теперь avg () написан лаконично и работает по назначению.

Тем не менее, в зависимости от того, как этот код будет использоваться, может быть, еще есть над чем поработать. Как написано, avg () выдаст исключение TypeError , если какие-либо аргументы не являются числовыми:

>>>

  >>> avg (1, 'foo', 3)
Отслеживание (последний вызов последний):
  Файл "", строка 1, в 
  Файл "", строка 2, в среднем
TypeError: неподдерживаемые типы операндов для +: 'int' и 'str'
  

Для максимальной надежности следует добавить код, проверяющий, что аргументы имеют правильный тип.Позже в этой серии руководств вы узнаете, как перехватывать исключения, такие как TypeError , и обрабатывать их соответствующим образом. Вы также можете проверить исключения Python: введение.

Распаковка кортежа аргументов

Аналогичная операция доступна на другой стороне уравнения в вызове функции Python. Когда аргументу в вызове функции предшествует звездочка ( * ), это указывает на то, что аргумент представляет собой кортеж, который должен быть распакованным и переданным в функцию как отдельные значения:

>>>

  >>> def f (x, y, z):
... print (f'x = {x} ')
... print (f'y = {y} ')
... печать (f'z = {z} ')
...

>>> f (1, 2, 3)
х = 1
у = 2
г = 3

>>> t = ('фу', 'бар', 'баз')
>>> f (* t)
x = foo
y = бар
z = baz
  

В этом примере * t в вызове функции указывает, что t - это кортеж, который следует распаковать. Распакованные значения 'foo' , 'bar' и 'baz' назначаются параметрам x , y и z соответственно.

Хотя этот тип распаковки называется распаковкой кортежей , он работает не только с кортежами. Оператор звездочка ( * ) может применяться к любой итерации в вызове функции Python. Например, список или набор тоже можно распаковать:

>>>

  >>> a = ['foo', 'bar', 'baz']
>>> тип (а)
<список классов>
>>> f (* а)
x = foo
y = бар
z = baz

>>> s = {1, 2, 3}
>>> тип (ы)
<класс 'набор'>
>>> f (* s)
х = 1
у = 2
г = 3
  

Вы даже можете использовать упаковку и распаковку кортежей одновременно:

>>>

  >>> def f (* args):
... print (тип (аргументы), аргументы)
...

>>> a = ['foo', 'bar', 'baz', 'qux']
>>> f (* а)
<класс 'кортеж'> ('foo', 'bar', 'baz', 'qux')
  

Здесь f (* a) указывает, что список a должен быть распакован, а элементы переданы в f () как отдельные значения. Спецификация параметра * args заставляет значения упаковываться обратно в кортеж args .

Упаковка словаря аргументов

Python имеет аналогичный оператор, двойную звездочку ( ** ), который можно использовать с параметрами и аргументами функции Python для указания упаковки и распаковки словаря .Двойная звездочка ( ** ) перед параметром в определении функции Python указывает, что соответствующие аргументы, которые, как ожидается, будут парами ключ = значение , должны быть упакованы в словарь:

>>>

  >>> def f (** kwargs):
... печать (kwargs)
... print (введите (kwargs))
... для ключа val в kwargs.items ():
... print (ключ, '->', val)
...

>>> f (foo = 1, bar = 2, baz = 3)
{'foo': 1, 'bar': 2, 'baz': 3}
<класс 'dict'>
foo -> 1
бар -> 2
баз -> 3
  

В этом случае аргументы foo = 1 , bar = 2 и baz = 3 упакованы в словарь, на который функция может ссылаться по имени kwargs .Опять же, можно использовать любое имя, но своеобразное kwargs (которое является сокращением от ключевого слова args ) почти стандартно. Вам не обязательно его придерживаться, но если вы это сделаете, то любой, кто знаком с соглашениями о кодировании Python, сразу поймет, что вы имеете в виду.

Распаковка словаря аргументов

Распаковка словаря аргументов аналогична распаковке кортежа аргументов. Когда двойная звездочка ( ** ) предшествует аргументу в вызове функции Python, она указывает, что аргумент является словарем, который должен быть распакован, с полученными элементами, переданными в функцию как аргументы ключевого слова:

>>>

  >>> def f (a, b, c):
... print (F'a = {a} ')
... печать (F'b = {b} ')
... печать (F'c = {c} ')
...

>>> d = {'a': 'foo', 'b': 25, 'c': 'qux'}
>>> е (** д)
a = foo
б = 25
c = qux
  

Элементы в словаре d распаковываются и передаются в f () как аргументы ключевого слова. Итак, f (** d) эквивалентно f (a = 'foo', b = 25, c = 'qux') :

>>>

  >>> f (a = 'foo', b = 25, c = 'qux')
a = foo
б = 25
c = qux
  

На самом деле, проверьте это:

>>>

  >>> f (** dict (a = 'foo', b = 25, c = 'qux'))
a = foo
б = 25
c = qux
  

Здесь dict (a = 'foo', b = 25, c = 'qux') создает словарь из указанных пар ключ / значение.Затем оператор двойной звездочки ( ** ) распаковывает его и передает ключевые слова в f () .

Собираем все вместе

Думайте о * args как о списке позиционных аргументов переменной длины, а о ** kwargs как о списке аргументов ключевого слова переменной длины.

Все три - стандартные позиционные параметры, * args и ** kwargs - могут использоваться в одном определении функции Python. Если да, то их следует указывать в таком порядке:

>>>

  >>> def f (a, b, * args, ** kwargs):
... print (F'a = {a} ')
... печать (F'b = {b} ')
... print (F'args = {args} ')
... печать (F'kwargs = {kwargs} ')
...

>>> f (1, 2, 'foo', 'bar', 'baz', 'qux', x = 100, y = 200, z = 300)
а = 1
b = 2
args = ('foo', 'bar', 'baz', 'qux')
kwargs = {'x': 100, 'y': 200, 'z': 300}
  

Это обеспечивает столько гибкости, сколько вам может понадобиться в функциональном интерфейсе!

Множественные распаковки в вызове функции Python

Python версии 3.5 представил поддержку дополнительных обобщений распаковки, как указано в PEP 448.Одна вещь, которую позволяют эти улучшения, - это множественных распаковок за один вызов функции Python:

>>>

  >>> def f (* args):
... для i в аргументах:
... печать (я)
...

>>> a = [1, 2, 3]
>>> t = (4, 5, 6)
>>> s = {7, 8, 9}

>>> f (* a, * t, * s)
1
2
3
4
5
6
8
9
7
  

Вы также можете указать несколько распаковок словарей в вызове функции Python:

>>>

  >>> def f (** kwargs):
... для k, v в kwargs.items ():
... print (k, '->', v)
...

>>> d1 = {'a': 1, 'b': 2}
>>> d2 = {'x': 3, 'y': 4}

>>> f (** d1, ** d2)
а -> 1
б -> 2
х -> 3
у -> 4
  

Примечание: Это расширение доступно только в Python версии 3.5 или новее. Если вы попробуете это в более ранней версии, то получите исключение SyntaxError .

Кстати, операторы распаковки * и ** применяются не только к переменным, как в примерах выше.Вы также можете использовать их с литералами, которые повторяются:

>>>

  >>> def f (* args):
... для i в аргументах:
... печать (я)
...

>>> f (* [1, 2, 3], * [4, 5, 6])
1
2
3
4
5
6

>>> def f (** kwargs):
... для k, v в kwargs.items ():
... print (k, '->', v)
...

>>> f (** {'a': 1, 'b': 2}, ** {'x': 3, 'y': 4})
а -> 1
б -> 2
х -> 3
у -> 4
  

Здесь литеральные списки [1, 2, 3] и [4, 5, 6] указаны для распаковки кортежей, а буквальные словари {'a': 1, 'b': 2} и {'x': 3, 'y': 4} указаны для распаковки словаря.

Аргументы только для ключевых слов

Функцию Python в версии 3.x можно определить так, чтобы она принимала аргументов, содержащих только ключевые слова. . Это аргументы функции, которые должны быть указаны с помощью ключевого слова. Давайте рассмотрим ситуацию, в которой это может быть полезно.

Предположим, вы хотите написать функцию Python, которая принимает переменное количество строковых аргументов, объединяет их вместе, разделенные точкой ( "." ), и выводит их на консоль. Для начала подойдет что-то вроде этого:

>>>

  >>> def concat (* args):
... print (f '-> {".". join (args)}')
...

>>> concat ('a', 'b', 'c')
-> a.b.c
>>> concat ('foo', 'bar', 'baz', 'qux').
-> foo.bar.baz.qux
  

В существующем виде выходной префикс жестко запрограммирован на строку '->' . Что, если вы хотите изменить функцию, чтобы она также принимала это как аргумент, чтобы пользователь мог указать что-то еще? Это одна из возможностей:

>>>

  >>> def concat (префикс, * args):
... print (f '{prefix} {".".join (аргументы)} ')
...

>>> concat ('//', 'a', 'b', 'c')
//a.b.c
>>> concat ('...', 'foo', 'bar', 'baz', 'qux')
... foo.bar.baz.qux
  

Работает так, как рекламируется, но в этом решении есть несколько нежелательных моментов:

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

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

Вы могли подумать, что можете решить вторую проблему, указав параметр со значением по умолчанию, например, например:

>>>

  >>> def concat (prefix = '->', * args):
... print (f '{префикс} {".". join (args)}')
...
  

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

.
>>>

  >>> concat ('a', 'b', 'c')
ab.c
  

Что, если вы попытаетесь указать префикс в качестве аргумента ключевого слова? Ну, вы не можете сначала указать:

>>>

  >>> concat (prefix = '//', 'a', 'b', 'c')
  Файл "", строка 1
SyntaxError: позиционный аргумент следует за аргументом ключевого слова
  

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

Однако вы также не можете указать его последним:

>>>

  >>> concat ('a', 'b', 'c', prefix = '...')
Отслеживание (последний вызов последний):
  Файл "", строка 1, в 
TypeError: concat () получил несколько значений для аргумента prefix
  

Опять же, префикс является позиционным параметром, поэтому ему назначается первый аргумент, указанный в вызове (в данном случае это 'a' ). Затем, когда он снова указывается в качестве аргумента ключевого слова в конце, Python думает, что он был назначен дважды.

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

>>>

  >>> def concat (* args, prefix = '->'):
... print (f '{префикс} {".". join (args)}')
...
  

В этом случае префикс становится параметром только с ключевым словом. Его значение никогда не будет заполнено позиционным аргументом.Его можно указать только с помощью именованного аргумента ключевого слова:

>>>

  >>> concat ('a', 'b', 'c', prefix = '...')
... a.b.c
  

Обратите внимание, что это возможно только в Python 3. В версии 2.x Python указание дополнительных параметров после параметра аргументов переменной * args вызывает ошибку.

Аргументы, содержащие только ключевое слово, позволяют функции Python принимать переменное количество аргументов, за которыми следует один или несколько дополнительных параметров в качестве аргументов ключевого слова.Если вы хотите изменить concat () так, чтобы можно было указать символ-разделитель, вы можете добавить дополнительный аргумент, состоящий только из ключевых слов:

>>>

  >>> def concat (* args, prefix = '->', sep = '.'):
... print (f '{префикс} {sep.join (args)}')
...

>>> concat ('a', 'b', 'c')
-> a.b.c
>>> concat ('a', 'b', 'c', prefix = '//')
//a.b.c
>>> concat ('a', 'b', 'c', prefix = '//', sep = '-')
// а-б-в
  

Если параметру, содержащему только ключевое слово, присвоено значение по умолчанию в определении функции (как в примере выше), а ключевое слово опущено при вызове функции, то предоставляется значение по умолчанию:

>>>

  >>> concat ('a', 'b', 'c')
-> а.до н.э
  

Если, с другой стороны, параметру не присвоено значение по умолчанию, то он становится обязательным, и если его не указать, возникает ошибка:

>>>

  >>> def concat (* args, префикс):
... print (f '{префикс} {".". join (args)}')
...

>>> concat ('a', 'b', 'c', prefix = '...')
... a.b.c

>>> concat ('a', 'b', 'c')
Отслеживание (последний вызов последний):
  Файл "", строка 1, в 
TypeError: в concat () отсутствует 1 обязательный аргумент, содержащий только ключевое слово: 'prefix'
  

Что, если вы хотите определить функцию Python, которая принимает аргумент, состоящий только из ключевых слов, но не принимает переменное количество позиционных аргументов? Например, следующая функция выполняет указанную операцию с двумя числовыми аргументами:

>>>

  >>> def oper (x, y, op = '+'):
... если op == '+':
... вернуть x + y
... elif op == '-':
... вернуть x - y
... elif op == '/':
... вернуть x / y
...     еще:
... return None
...

>>> опер (3, 4)
7
>>> опер (3, 4, '+')
7
>>> опер (3, 4, '/')
0,75
  

Если вы хотите сделать op параметром только для ключевого слова, вы можете добавить посторонний параметр аргумента фиктивной переменной и просто игнорировать его:

>>>

  >>> def oper (x, y, * ignore, op = '+'):
... если op == '+':
... вернуть x + y
... elif op == '-':
... вернуть x - y
... elif op == '/':
... вернуть x / y
...     еще:
... return None
...

>>> oper (3, 4, op = '+')
7
>>> oper (3, 4, op = '/')
0,75
  

Проблема с этим решением заключается в том, что * ignore поглощает любые посторонние позиционные аргументы, которые могут быть включены:

>>>

  >>> oper (3, 4, «Мне здесь не место»)
7
>>> oper (3, 4, «Мне здесь не место», op = '/')
0.75
  

В этом примере не должно быть дополнительного аргумента (как объявляет сам аргумент). Вместо того, чтобы тихо добиться успеха, это действительно должно привести к ошибке. То, что это не так, в лучшем случае неопрятно. В худшем случае это может привести к вводящему в заблуждение результату:

Чтобы исправить это, версия 3 позволяет параметру аргумента переменной в определении функции Python быть просто звездочкой ( * ) с опущенным именем:

>>>

  >>> def oper (x, y, *, op = '+'):
... если op == '+':
... вернуть x + y
... elif op == '-':
... вернуть x - y
... elif op == '/':
... вернуть x / y
...     еще:
... return None
...

>>> oper (3, 4, op = '+')
7
>>> oper (3, 4, op = '/')
0,75

>>> oper (3, 4, «Мне здесь не место»)
Отслеживание (последний вызов последний):
  Файл "", строка 1, в 
TypeError: oper () принимает 2 позиционных аргумента, но было дано 3

>>> опер (3, 4, '+')
Отслеживание (последний вызов последний):
  Файл "", строка 1, в 
TypeError: oper () принимает 2 позиционных аргумента, но было дано 3
  

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

Только позиционные аргументы

Начиная с Python 3.8, параметры функции также могут быть объявлены только позиционными , что означает, что соответствующие аргументы должны быть предоставлены позиционно и не могут быть указаны с помощью ключевого слова.

Чтобы обозначить некоторые параметры как позиционные, вы указываете косую черту (/) в списке параметров определения функции.Любые параметры слева от косой черты (/) должны быть указаны позиционно. Например, в следующем определении функции x и y являются позиционными параметрами, но z можно указать с помощью ключевого слова:

>>>

  >>> # Это Python 3.8
>>> def f (x, y, /, z):
... print (f'x: {x} ')
... print (f'y: {y} ')
... print (f'z: {z} ')
...
  

Это означает, что действительны следующие вызовы:

>>>

  >>> f (1, 2, 3)
х: 1
г: 2
z: 3

>>> f (1, 2, z = 3)
х: 1
г: 2
z: 3
  

Однако следующий звонок на номер f () недействителен:

>>>

  >>> f (x = 1, y = 2, z = 3)
Отслеживание (последний вызов последний):
  Файл "", строка 1, в 
TypeError: f () получила некоторые позиционные аргументы, переданные как аргументы ключевого слова:
'х, у'
  

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

>>>

  >>> # Это Python 3.8
>>> def f (x, y, /, z, w, *, a, b):
... print (x, y, z, w, a, b)
...

>>> f (1, 2, z = 3, w = 4, a = 5, b = 6)
1 2 3 4 5 6

>>> f (1, 2, 3, w = 4, a = 5, b = 6)
1 2 3 4 5 6
  

В этом примере:

  • x и y являются только позиционными.
  • a и b - только ключевые слова.
  • z и w можно указать позиционно или по ключевому слову.

Для получения дополнительной информации о позиционных параметрах см. Основные моменты выпуска Python 3.8.

Строки документации

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

Ниже приведен пример определения функции со строкой документации:

>>>

  >>> def avg (* args):
... "" "Возвращает среднее значение списка числовых значений." ""
... вернуть сумму (аргументы) / len (аргументы)
...
  

Технически, строки документации могут использовать любой из механизмов цитирования Python, но рекомендуется использовать тройных кавычек с использованием символов двойных кавычек ( "" "), как показано выше. Если строка документации умещается в одной строке, то котировки закрытия должны находиться на той же строке, что и котировки открытия.

Многострочные строки документации используются для более объемной документации.Многострочная строка документации должна состоять из итоговой строки, за которой следует пустая строка, за которой следует более подробное описание. Котировки закрытия должны быть на отдельной строке:

>>>

  >>> def foo (bar = 0, baz = 1):
... "" "Выполните преобразование foo.
...
... Аргументы ключевого слова:
... bar - величина по оси бара (по умолчанию = 0)
... baz - величина по оси baz (по умолчанию = 1)
... "" "
... 
...
  

Форматирование строки документации и семантические соглашения подробно описаны в PEP 257.

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

Примечание: Эти атрибуты также упоминаются с помощью атрибутов dunder с красочным псевдонимом и методов dunder. Слово dunder объединяет d из double и под из символа подчеркивания ( _ ).В будущих уроках этой серии вы встретите еще много неприятных атрибутов и методов.

Вы можете получить доступ к строке документации функции с помощью выражения .__ doc__ . Строки документации для приведенных выше примеров могут отображаться следующим образом:

>>>

  >>> print (ср .__ doc__)
Возвращает среднее значение списка числовых значений.

>>> печать (foo .__ doc__)
Выполните преобразование foo.

    Аргументы ключевого слова:
    bar - величина по оси бара (по умолчанию = 0)
    baz - величина по оси baz (по умолчанию = 1)
  

В интерактивном интерпретаторе Python вы можете ввести help () , чтобы отобразить строку документации для :

>>>

  >>> справка (средн.)
Справка по функции avg в модуле __main__:

avg (* аргументы)
    Возвращает среднее значение списка числовых значений.>>> help (foo)
Справка по функции foo в модуле __main__:

foo (bar = 0, baz = 1)
    Выполните преобразование foo.

    Аргументы ключевого слова:
    bar - величина по оси бара (по умолчанию = 0)
    baz - величина по оси baz (по умолчанию = 1)
  

Считается хорошей практикой кодирования указывать строку документации для каждой определяемой вами функции Python. Дополнительные сведения о строках документации см. В документе «Документирование кода Python: полное руководство».

Аннотации функций Python

Начиная с версии 3.0, Python предоставляет дополнительную возможность для документирования функции, которая называется аннотацией функции . Аннотации позволяют прикреплять метаданные к параметрам функции и возвращаемому значению.

Чтобы добавить аннотацию к параметру функции Python, вставьте двоеточие (: ), за которым следует любое выражение после имени параметра в определении функции. Чтобы добавить аннотацию к возвращаемому значению, добавьте символы -> и любое выражение между закрывающей скобкой списка параметров и двоеточием, завершающим заголовок функции.Вот пример:

>>>

  >>> def f (a: '', b: '') -> '':
...     проходить
...
  

Аннотация для параметра a - это строка '' , для b строка '' , а для возвращаемого значения функции строка '' .

Интерпретатор Python создает словарь из аннотаций и назначает их другому специальному атрибуту dunder функции __annotations__ .Аннотации для функции Python f () , показанные выше, могут отображаться следующим образом:

>>>

  >>> f .__ annotations__
{'a': '', 'b': '', 'return': ''}
  

Ключи для параметров - это имена параметров. Ключом для возвращаемого значения является строка 'return' :

>>>

  >>> f .__ annotations __ ['a']
""
>>> f .__ аннотации __ ['b']
''
>>> е.__annotations __ ['return']
''
  

Обратите внимание, что аннотации не ограничиваются строковыми значениями. Это может быть любое выражение или объект. Например, вы можете комментировать объекты типа:

>>>

  >>> def f (a: int, b: str) -> float:
... print (a, b)
... вернуть (3.5)
...

>>> f (1, 'фу')
1 фу
3.5

>>> f .__ annotations__
{'a': <класс 'int'>, 'b': <класс 'str'>, 'return': <класс 'float'>}
  

Аннотация может быть даже составным объектом, например списком или словарем, поэтому к параметрам и возвращаемому значению можно прикрепить несколько элементов метаданных:

>>>

  >>> def area (
...     р: {
... 'desc': 'радиус круга',
... 'тип': float
...}) -> \
... {
... 'desc': 'площадь круга',
... 'тип': float
...}:
... return 3.14159 * (r ** 2)
...

>>> площадь (2,5)
19,6349375

>>> area .__ annotations__
{'r': {'desc': 'радиус круга', 'type': },
'return': {'desc': 'область круга', 'type': }}

>>> area .__ annotations __ ['r'] ['desc']
'радиус круга'
>>> Площадь.__annotations __ ['return'] ['type']
<класс 'float'>
  

В приведенном выше примере аннотация прикреплена к параметру r и к возвращаемому значению. Каждая аннотация представляет собой словарь, содержащий описание строки и объект типа.

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

>>>

  >>> def f (a: int = 12, b: str = 'baz') -> float:
... print (a, b)
... вернуть (3.5)
...

>>> f .__ annotations__
{'a': <класс 'int'>, 'b': <класс 'str'>, 'return': <класс 'float'>}

>>> f ()
12 баз
3.5
  

Что делают аннотации? Откровенно говоря, они почти ничего не делают. Они просто вроде как там. Давайте снова посмотрим на один из примеров сверху, но с небольшими изменениями:

>>>

  >>> def f (a: int, b: str) -> float:
... print (a, b)
... вернуть 1, 2, 3
...

>>> f ('фу', 2,5)
foo 2.5
(1, 2, 3)
  

Что здесь происходит? Аннотации для f () указывают, что первый аргумент - int , второй аргумент - str , а возвращаемое значение - float . Но последующий вызов f () нарушает все правила! Аргументы: str и float соответственно, а возвращаемое значение - кортеж. И все же переводчик позволяет всему этому скользить без каких-либо жалоб.

Аннотации не накладывают никаких семантических ограничений на код вообще. Это просто биты метаданных, прикрепленные к параметрам функции Python и возвращаемому значению. Python послушно прячет их в словаре, присваивает словарю атрибут dunder функции __annotations__ , и все. Аннотации являются необязательными и вообще не влияют на выполнение функций Python.

Процитирую Амала в Амаль и ночные посетители : «Какая польза от этого?»

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

  def f (a: int, b: str) -> float:
  

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

Deep Dive: принудительная проверка типов

Если бы вы были склонны, вы могли бы добавить код для принудительного применения типов, указанных в аннотациях к функциям.Вот функция, которая проверяет фактический тип каждого аргумента на соответствие тому, что указано в аннотации для соответствующего параметра. Он отображает Истинно , если они соответствуют Ложь , если нет:

>>>

  >>> def f (a: int, b: str, c: float):
... импорт проверить
... args = inspect.getfullargspec (f) .args
... аннотации = inspect.getfullargspec (f) .annotations
... для x в аргументах:
... print (x, '->',
... 'arg is', type (locals () [x]), ',',
... 'annotation is', annotations [x],
... '/', (type (locals () [x])) is annotations [x])
...

>>> f (1, 'foo', 3.3)
a -> arg - это , аннотация - это  / True
b -> arg - , аннотация -  / True
c -> arg - , аннотация -  / True

>>> f ('фу', 4.3, 9)
a -> arg - это , аннотация -  / False
b -> arg - , аннотация -  / False
c -> arg - , аннотация -  / False

>>> f (1, 'фу', 'бар')
a -> arg - это , аннотация - это  / True
b -> arg - , аннотация -  / True
c -> arg - , аннотация -  / False
  

(Модуль inspect содержит функции, которые получают полезную информацию о живых объектах - в данном случае функция f () .)

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

Фактически, схема использования аннотаций для выполнения проверки статического типа в Python описана в PEP 484. Доступна бесплатная программа проверки статического типа для Python под названием mypy, основанная на спецификации PEP 484.

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

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

>>>

  >>> def f (a: int, b: str) -> float:
...     возвращаться
...

>>> f .__ annotations__
{'a': <класс 'int'>, 'b': <класс 'str'>, 'return': <класс 'float'>}
  

По сути, это та же функция со словарем __annotations__ , созданным вручную:

>>>

  >>> def f (a, b):
...     возвращаться
...

>>> f .__ annotations__ = {'a': int, 'b': str, 'return': float}

>>> f .__ annotations__
{'a': <класс 'int'>, 'b': <класс 'str'>, 'return': <класс 'float'>}
  

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

На самом деле, атрибут __annotations__ не сильно отличается от большинства других атрибутов функции. Например, его можно динамически изменять. Вы можете использовать атрибут возвращаемого значения, чтобы подсчитать, сколько раз функция выполняется:

>>>

  >>> def f () -> 0:
... f .__ аннотации __ ['return'] + = 1
... print (f "f () был выполнен {f .__ annotations __ ['return']} время (с)")
...

>>> f ()
f () было выполнено 1 раз (а)
>>> f ()
f () было выполнено 2 раза (а)
>>> f ()
f () было выполнено 3 раза (а)
  

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

Заключение

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

Вы узнали:

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

Документация

Learning with Python 2nd Edition

3.1. Определения и использование

В контексте программирования функция представляет собой именованную последовательность операторов.
который выполняет желаемую операцию. Эта операция указана в функции .
определение
.В Python синтаксис определения функции:

 def NAME (СПИСОК ПАРАМЕТРОВ):
    ЗАЯВЛЕНИЯ
 

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

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

  1. Заголовок , который начинается с ключевого слова и заканчивается двоеточием.
  2. Тело , состоящее из одного или нескольких операторов Python, каждый
    с таким же отступом - 4 пробела - это стандарт Python - от
    заголовок.

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

Первая пара функций, которые мы собираемся написать, не имеет параметров, поэтому
синтаксис выглядит так:

 def new_line ():
    print # оператор печати без аргументов печатает новую строку
 

Эта функция называется new_line. Пустые скобки указывают на то, что у него есть
без параметров. Его тело содержит только один оператор, который выводит
символ новой строки.(Вот что происходит, когда вы используете команду печати
без аргументов.)

При определении новой функции функция не запускается. Для этого нам понадобится
вызов функции . Вызов функций содержит имя функции, которую
выполняется, за которым следует список значений, называемых аргументов , которые назначаются
к параметрам в определении функции. В наших первых примерах пустой
список параметров, поэтому вызовы функций не принимают никаких аргументов. Уведомление,
однако скобки необходимы при вызове функции :

 принт «Первая линия."
новая линия()
напечатайте «Вторая строка».
 

Результат этой программы:

Дополнительный пробел между двумя строками является результатом new_line ()
вызов функции. Что, если бы нам нужно было больше места между строками? Мы могли позвонить
та же функция повторно:

 печать «Первая линия».
новая линия()
новая линия()
новая линия()
напечатайте «Вторая строка».
 

Или мы могли бы написать новую функцию с именем three_lines, которая печатает три новых
линии:

 def three_lines ():
    новая линия()
    новая линия()
    новая линия()

print "Первая строка."
three_lines ()
напечатайте «Вторая строка».
 

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

Вы должны обратить внимание на эту программу:

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

  1. Создание новой функции дает вам возможность назвать группу
    заявления. Функции могут упростить программу, скрывая сложные вычисления
    за одной командой и с использованием английских слов вместо загадочного кода.
  2. Создание новой функции может уменьшить размер программы за счет исключения повторяющихся
    код.Например, короткий способ напечатать девять последовательных новых строк - это
    вызовите three_lines трижды.

Объединение фрагментов кода из предыдущего раздела в скрипт
с именем tryme1.py вся программа выглядит так:

 def new_line ():
    Распечатать

def three_lines ():
    новая линия()
    новая линия()
    новая линия()

напечатайте «Первая строка».
three_lines ()
напечатайте «Вторая строка».
 

Эта программа содержит два определения функций: new_line и
три_строчки. Определения функций выполняются так же, как и другие операторы,
но в результате создается новая функция.Заявления внутри
функция не выполняется до тех пор, пока функция не будет вызвана, а функция
определение не производит никакого вывода.

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

3,2. Поток исполнения

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

Выполнение всегда начинается с первого оператора программы. Заявления
выполняется по одному, в порядке сверху вниз.

Определения функций не изменяют ход выполнения программы, но
помните, что операторы внутри функции не выполняются до тех пор, пока
функция вызывается. Хотя это не часто, вы можете определить одну функцию
внутри другого. В этом случае внутреннее определение не выполняется до тех пор, пока
вызывается внешняя функция.

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

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

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

Какова мораль этой грязной сказки? Когда вы читаете программу, не читайте
сверху донизу. Вместо этого следите за ходом выполнения.

3.3. Параметры, аргументы и оператор импорта

Большинству функций требуются аргументы, значения, которые управляют тем, как функция выполняет свои
работа. Например, если вы хотите найти абсолютное значение числа, у вас есть
чтобы указать, что это за номер. Python имеет встроенную функцию для вычислений
абсолютное значение:

 >>> абс (5)
5
>>> абс (-5)
5
 

В этом примере аргументы функции abs - 5 и -5.

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

 >>> pow (2, 3)
8
>>> pow (7, 4)
2401
 

Еще одна встроенная функция, которая принимает более одного аргумента, - это макс.

 >>> макс (7, 11)
11
>>> макс (4, 1, 17, 2, 12)
17
>>> макс (3 * 11, 5 ** 3, 512 - 9, 1024 ** 0)
503
 

max может быть отправлено любое количество аргументов, разделенных запятыми, и будет
вернуть максимальное отправленное значение.Аргументы могут быть либо простыми значениями, либо
выражения. В последнем примере возвращается 503, поскольку оно больше 33,
125 и 1.

Вот пример пользовательской функции с параметром:

 def print_twice (параметр):
    параметр печати, параметр
 

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

Интерактивная оболочка Python предоставляет нам удобный способ тестирования наших
функции. Мы можем использовать оператор импорта , чтобы вывести функции, которые у нас есть
определены в сценарии в сеанс интерпретатора. Чтобы увидеть, как это работает, предположим
функция print_twice определена в скрипте chap03.ру. Мы можем
теперь протестируйте его в интерактивном режиме, импортировав в наш сеанс оболочки Python:

 >>> из импорта chap03 *
>>> print_twice ('Спам')
Спам Спам
>>> print_twice (5)
5 5
>>> print_twice (3.14159)
3,14159 3,14159
 

При вызове функции значение аргумента присваивается соответствующему
параметр в определении функции. Фактически, это если param = 'Spam'
выполняется при вызове print_twice ('Spam'), param = 5 в
print_twice (5) и param = 3.14159 в print_twice (3.14159).

Любой тип аргумента, который может быть напечатан, может быть отправлен в print_twice в
первый вызов функции, аргумент - строка. Во втором - целое число.
В третьем - поплавок.

Как и для встроенных функций, мы можем использовать выражение в качестве аргумента для
print_twice:

 >>> print_twice ('Спам' * 4)
СпамСпамСпамСпам СпамСпамСпамСпам
 

«Спам» * 4 сначала оценивается как «SpamSpamSpamSpam», а затем
передается как аргумент print_twice.

3,4. Композиция

Так же, как и математические функции, функции Python могут состоять из ,
Это означает, что вы используете результат одной функции в качестве входных данных для другой.

 >>> print_twice (абс (-7))
7 7
>>> print_twice (макс (3, 1, абс (-11), 7))
11 11
 

В первом примере abs (-7) оценивается как 7, которое затем становится
аргумент print_twice. Во втором примере у нас есть два уровня
состав, так как abs (-11) сначала оценивается как 11 перед max (3,
1, 11, 7) оценивается как 11, а print_twice (11) затем отображает
результат.

Мы также можем использовать переменную в качестве аргумента:

 >>> sval = 'Эрик, половинка пчелы.'
>>> print_twice (свал)
Эрик, наполовину пчела. Эрик, наполовину пчела.
 

Обратите внимание на кое-что очень важное. Имя переменной, которую мы передаем как
аргумент (sval) не имеет ничего общего с именем параметра
(параметр). Опять же, как будто param = sval выполняется, когда
print_twice (sval) вызывается. Неважно, какое значение было названо в
вызывающий, в print_twice его имя - param.

3,5. Переменные и параметры локальные

Когда вы создаете локальную переменную внутри функции, она существует только внутри
функция, и вы не можете использовать ее снаружи. Например:

 def cat_twice (часть1, часть2):
    кошка = часть1 + часть2
    print_twice (кошка)
 

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

 >>> chant1 = "Пирог с Иисусом,"
>>> chant2 = "Dona eis Requiem."
>>> cat_twice (chant1, chant2)
Pie Jesu domine, Dona eis Requiem. Pie Jesu domine, Dona eis Requiem.
 

Когда cat_twice завершается, переменная cat уничтожается. Если мы
пытаемся распечатать, получаем ошибку:

 >>> печать кота
NameError: имя 'кошка' не определено
 

Параметры также локальные. Например, вне функции print_twice,
не существует такой вещи, как param. Если вы попытаетесь его использовать, Python будет
Пожаловаться.

3,6. Диаграммы стека

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

Каждая функция представлена ​​кадром . Рамка - это коробка с названием
функция рядом с ним и параметры и переменные функции внутри
Это. Диаграмма стека для предыдущего примера выглядит так:

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

Каждый параметр ссылается на то же значение, что и соответствующий ему аргумент. Так,
part1 имеет то же значение, что и chant1, part2 имеет то же значение, что и
chant2, а param имеет то же значение, что и cat.

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

Чтобы увидеть, как это работает, создайте сценарий Python с именем tryme2.py, который выглядит
как это:

 def print_twice (параметр):
    параметр печати, параметр
    печать кота

def cat_twice (часть1, часть2):
    кошка = часть1 + часть2
    print_twice (кошка)

chant1 = "Пирог Jesu domine,"
chant2 = "Dona eis Requim."
cat_twice (chant1, chant2)
 

Мы добавили оператор print cat внутри функции print_twice,
но кот там не определен. Запуск этого скрипта приведет к ошибке
сообщение вроде этого:

 Traceback (самый внутренний последний):
  Файл "tryme2.py ", строка 11, в 
    cat_twice (chant1, chant2)
  Файл "tryme2.py", строка 7, в cat_twice
    print_twice (кошка)
  Файл "tryme2.py", строка 3, в print_twice
    печать кота
NameError: глобальное имя cat не определено
 

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

Обратите внимание на сходство между трассировкой и диаграммой стека.Это не
совпадение. Фактически, еще одно распространенное название трассировки - это трассировка стека .

3,7. Глоссарий

аргумент
Значение, передаваемое функции при ее вызове. Это значение
присваивается соответствующему параметру в функции.
кузов
Вторая часть составного оператора. Тело состоит из
последовательность операторов с одинаковым отступом с самого начала
заголовка. Стандартный размер отступа, используемый в
Сообщество Python - это 4 пробела.
составной отчет

Выписка, состоящая из двух частей:

  1. заголовок - который начинается с ключевого слова, определяющего инструкцию
    введите и заканчивается двоеточием.
  2. body - содержит одно или несколько операторов с одинаковым отступом
    из шапки.

Синтаксис составного оператора выглядит следующим образом:

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

Оператор, разрешающий функции и переменные, определенные в Python.
сценарий, который будет перенесен в среду другого сценария или
запущенная оболочка Python.Например, предположим, что в сценарии есть следующее:
с именем tryme.py:

 def print_thrice (вещь):
    печать вещь, вещь, вещь

n = 42
s = "А теперь о другом ..."
 

Теперь запустите оболочку Python из того же каталога, в котором
tryme.py находится:

 $ лс
tryme.py
$ питон
>>>
 

В tryme.py определены три имени: print_thrice, n и
с. Если мы попытаемся получить доступ к любому из них в оболочке без предварительного
при импорте получаем ошибку:

 >>> п
Отслеживание (последний вызов последний):
  Файл "", строка 1, в 
NameError: имя 'n' не определено
>>> print_thrice ("ай!")
Отслеживание (последний вызов последний):
  Файл "", строка 1, в 
NameError: имя print_thrice не определено
 

Если импортировать все из tryme.py, однако мы можем использовать
все, что в нем определено:

 >>> из импорта tryme *
>>> п
42
>>> с
'А сейчас нечто соверешнно другое...'
>>> print_thrice ("Ура!")
Ура! Ура! Ура!
>>>
 

Обратите внимание, что вы не включаете .py из имени сценария в
заявление об импорте.

локальная переменная
Переменная, определенная внутри функции. Можно использовать только локальную переменную
внутри его функции.
параметр
Имя, используемое внутри функции для обозначения значения, переданного как
аргумент.
диаграмма стека
Графическое представление стека функций, их переменных,
и ценности, к которым они относятся.
трассировка
Список выполняемых функций, распечатываемый при выполнении
возникает ошибка. Отслеживание также обычно называют
трассировка стека , поскольку он перечисляет функции в том порядке, в котором они
хранятся в
стек времени выполнения.

3.8. Упражнения

  1. С помощью текстового редактора создайте сценарий Python с именем tryme3.ру. Напиши
    функция в этом файле с именем nine_lines, которая использует three_lines для
    выведите девять пустых строк. Теперь добавьте функцию с именем clear_screen, которая
    печатает двадцать пять пустых строк. Последняя строка вашей программы должна быть
    вызовет на clear_screen.

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

  3. Начиная с рабочей версии tryme3.py, переместите определение
    new_line после определения three_lines. Запишите, что происходит
    при запуске этой программы. Теперь переместите определение new_line под
    вызов three_lines (). Объясните, как это пример правила, которое вы
    заявлено в предыдущем упражнении.

  4. Заполните тело определения функции для cat_n_times, чтобы
    он напечатает строку s, n раз:

     def cat_n_times (s, n):
        <введите здесь свой код>
     

    Сохраните эту функцию в скрипте с именем import_test.py. Теперь в unix
    убедитесь, что вы находитесь в том же каталоге, где находится
    import_test.py находится (ls должен показать import_test.py).
    Запустите оболочку Python и попробуйте следующее:

     >>> из import_test import *
    >>> cat_n_times ('Спам', 7)
    СпамСпамСпамСпамСпамСпамСпам
     

    Если все в порядке, ваша сессия должна работать так же, как и эта.Эксперимент
    другими вызовами cat_n_times, пока вы не почувствуете себя комфортно
    работает.

5. Функции - начало программирования на Python для начинающих веб-разработчиков

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

Чтобы люди (программисты) могли писать сложные программы
который может охватывать тысячи строк кода, языки программирования имеют функции
которые позволяют программистам использовать возможности abstracton для присвоения имен последовательности
инструкции, а затем использовать новые имена без учета
подробности инструкций, к которым они относятся.

В этой главе обсуждаются функции, одна из
Возможности языка Python, поддерживающие такую ​​абстракцию.

5.1. Определение и использование функций

В контексте программирования
функция
- это именованная последовательность операторов, выполняющая желаемую операцию. Этот
операция указывается в определении функции . В Python синтаксис для
определение функции:

 def NAME (СПИСОК ПАРАМЕТРОВ):
    ЗАЯВЛЕНИЯ
 

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

Внутри функции может быть любое количество операторов, но они должны быть
отступ от def .

Определения функций - это составных операторов , похожих на ветвление и
операторы цикла, которые мы видели в условных выражениях и циклах
главы, что означает, что они состоят из следующих частей:

  1. Заголовок , который начинается с ключевого слова и заканчивается двоеточием.

  2. Тело , состоящее из одного или нескольких операторов Python, каждый с отступом
    такое же количество ( 4 пробела - стандарт Python ) из заголовка.

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

5.2. Основываясь на том, что вы узнали в старшей школе по алгебре

Еще в старшей школе в классе Альгеберы вы познакомились с математикой.
функции. Возможно, вам показали схему «функциональной машины», которая
выглядело примерно так:

Идея этой диаграммы состоит в том, что функция подобна машине , которая принимает
вход, x , и преобразует его в выход, f (x) .Свет
желтый прямоугольник f - это абстракция процесса, используемого для преобразования
от x до f (x) .

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

Следующие
квадратичная функция - это
пример:

Вот такая же функция в Python:

 def f (x):
    возврат 3 * x ** 2-2 * x + 5
 

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

Вот наша функция f , вызываемая с несколькими разными аргументами:

 >>> f (3)
26 год
>>> f (0)
5
>>> f (1)
6
>>> f (-1)
10
>>> f (5)
70
 

Определение функции должно сначала быть введено в оболочку Python перед этим.
можно звонить:

 >>> def f (x):
... вернуть 3 * x ** 2 - 2 * x + 5
...
>>>
 

Вызов функций включает неявного присвоения аргумента.
к параметру

Связь между параметром и аргументом в определении
и вызов функции - это неявное присвоение . Это как если бы
мы выполнили операторы присваивания x = 3 , x = 0 , x = 1 ,
x = -1 и x = 5 соответственно перед вызовом функции
на f в предыдущем примере.

5.3.

возвращает заявление

Оператор возврата вызывает
функция для немедленного прекращения выполнения операторов в теле функции и
отправить обратно (или вернуть ) значение после ключевого слова вернуть в
заявление о вызове.

 >>> результат = f (3)
>>> результат
26 год
>>> результат = f (3) + f (-1)
>>> результат
36
 

Оператор return без значения после того, как он все еще возвращает значение типа
мы раньше не видели:

 >>> def mystery ():
...    возвращаться
...
>>> what_is_it = тайна ()
>>> what_is_it
>>> тип (what_is_it)
<класс 'NoneType'>
>>> печать (what_is_it)
Никто
 

None - единственное значение Python NoneType . Мы будем использовать это часто
позже для представления неизвестного или неназначенного значения. А пока тебе нужно быть
знайте, что это значение, возвращаемое оператором return без
Аргумент.

Все вызовы функций Python возвращают значение.Если вызов функции завершается
выполнение операторов в своем теле без нажатия return statement, a
Нет Функция возвращает значение.

 >>> def do_nothing_useful (n, m):
... х = п + м
... у = п - м
...
>>> do_nothing_useful (5, 3)
>>> результат = do_nothing_useful (5, 3)
>>> результат
>>>
>>> print (результат)
Никто
 

Поскольку do_nothing_useful не имеет оператора возврата со значением, он
возвращает значение None , которое присваивается результату . Нет значений
не отображаются в оболочке Python, если они явно не напечатаны.

Любые операторы в теле функции после и return :
обнаруженные никогда не будут выполнены и упоминаются как
мертвый код.

 >>> def try_to_print_dead_code ():
... print ("Это напечатает ...")
... print ("... и это будет.")
...    возвращаться
... print ("Но не это ...")
... print ("потому что это мертвый код!")
...
>>> try_to_print_dead_code ()
Это напечатает...
... и так будет.
>>>
 

5.4. Поток исполнения

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

Выполнение всегда начинается с первого оператора программы. Заявления
выполняется по одному, в порядке сверху вниз.

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

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

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

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

Какова мораль этой грязной сказки? Когда вы читаете программу, не читайте просто
сверху вниз. Вместо этого следует за потоком выполнения . Посмотри на это
программа:

 def f1 ():
    print ("Мо")

def f2 ():
    f4 ()
    print ("Минни")

def f3 ():
    f2 ()
    print ("Miny")
    f1 ()

def f4 ():
    print ("Ини")

f3 ()
 

Результат этой программы:

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

5.5. Инкапсуляция и обобщение

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

Обобщение означает принятие чего-то конкретного, например, подсчет числа
цифр в данном положительном целом числе, и делая его более общим, например
подсчет количества цифр любого целого числа.

Чтобы увидеть, как работает этот процесс, давайте начнем с программы, которая считает
количество цифр в номере 4203 :

Номер

 = 4203
count = 0

а число! = 0:
    count + = 1
    число // = 10

печать (количество)
 

Применяйте к этому то, что вы узнали при отслеживании программы, пока не почувствуете
уверены, что понимаете, как это работает.Эта программа демонстрирует важный
Схема вычисления называется счетчиком . Переменная count - это
инициализируется значением 0, а затем увеличивается каждый раз при выполнении тела цикла. Когда
цикл завершается, счетчик содержит результат - общее количество раз
тело цикла было выполнено, что соответствует количеству цифр.

Первый шаг в инкапсуляции этой логики - обернуть ее в функцию:

 def num_digits ():
    число = 4203
    count = 0

    а число! = 0:
        count + = 1
        число // = 10

    счетчик возврата

печать (число_цифров ())
 

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

 def num_digits (число):
    count = 0

    а число! = 0:
        count + = 1
        число // = 10

    счетчик возврата

печать (число_цифров (4203))
 

После того, как параметризует значение , мы теперь можем использовать нашу логику для подсчета цифр
любое положительное целое число. Вызов print (num_digits (710)) напечатает 3 .Вызов print (num_digits (1345109)) напечатает 7 и так далее.

Эта функция также содержит ошибки. Если мы вызовем num_digits (0) , он вернет
0 , когда он должен вернуть 1 . Если мы вызовем num_digits (-23) ,
программа переходит в бесконечный цикл. Вам будет предложено исправить обе эти ошибки.
как упражнение.

5,6. Композиция

Так же, как и математические функции, функции Python могут состоять из ,
Это означает, что вы используете результат одной функции в качестве входных данных для другой.

 >>> def f (x):
... вернуть 2 * x
...
>>> def g (x):
... вернуть x + 5
...
>>> def h (x):
... вернуть x ** 2-3
>>> f (3)
6
>>> г (3)
8
>>> ч (4)
13
>>> f (g (3))
16
>>> g (f (3))
11
>>> h (f (g (0)))
97
>>>
 

Мы также можем использовать переменную в качестве аргумента:

 >>> # Предположим определения функций для f и g, как в предыдущем примере
>>> val = 10
>>> f (val)
20
>>> f (g (val))
30
>>>
 

Обратите внимание на кое-что очень важное.Имя переменной, которую мы передаем как
аргумент ( значение ) не имеет ничего общего с именем параметра ( x ).
Опять же, это как если бы x = val выполнялось, когда вызывается f (val) . Это
не имеет значения, какое значение было названо в вызывающей стороне, внутри f и g
его имя x .

5,7. Функции тоже данные

Функции, которые вы определяете в Python, являются типом данных.

 >>> def f ():
... print ("Привет из функции f!")
...
>>> тип (f)
<тип 'функция'>
>>> f ()
Привет, из функции f!
>>>
 

Значения функций могут быть элементами списка. Предположим, что f , g и h имеют
был определен, как в разделе "Состав" выше.

 >>> do_stuff = [f, g, h]
>>> для func в do_stuff:
... функция (10)
...
20
15
97
 

Как обычно, вы должны отслеживать выполнение этого примера, пока не почувствуете
уверены, что понимаете, как это работает.

5,8. Список параметров

Передача списка в качестве аргумента фактически передает ссылку на список, а не
копия списка. Поскольку списки являются изменяемыми изменениями, внесенными в изменение параметра
аргумент также. Например, функция ниже принимает список как
аргумент и умножает каждый элемент в списке на 2:

 def double_stuff_v1 (a_list):
    индекс = 0
    для значения в a_list:
        a_list [индекс] = 2 * значение
        индекс + = 1
 

Чтобы проверить эту функцию, мы поместим ее в файл с именем pure_v_modify.py и
импортируйте в нашу оболочку Python, где мы можем поэкспериментировать:

 >>> from pure_v_modify import double_stuff_v1
>>> things = [2, 5, 'Спам', 9.5]
>>> double_stuff_v1 (вещи)
>>> вещи
[4, 10, 'SpamSpam', 19.0]
 

Примечание

Файл, содержащий импортированный код, должен иметь .py
расширение файла, которое
не записано в отчете об импорте .

Параметр a_list и переменная things являются псевдонимами для одного и того же
объект.Диаграмма состояний выглядит так:

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

Если функция изменяет параметр списка, вызывающий абонент видит это изменение.

5,9. Чистые функции и модификаторы

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

Чистая функция не вызывает побочных эффектов.Он общается с
вызывающая программа только через параметры, которые она не изменяет, и возврат
ценить. Вот double_stuff_v2 , записанная как чистая функция:

 def double_stuff_v2 (a_list):
    new_list = []
    для значения в a_list:
        новый_лист + = [2 * значение]
    вернуть новый_лист
 

Эта версия double_stuff не изменяет свои аргументы:

 >>> from pure_v_modify import double_stuff_v2
>>> things = [2, 5, 'Спам', 9.5]
>>> double_stuff_v2 (вещи)
[4, 10, 'SpamSpam', 19.0]
>>> вещи
[2, 5, "Спам", 9.5]
>>>
 

Чтобы использовать чистую версию функции double_stuff для изменения вещей ,
вы бы присвоили возвращаемое значение обратно вещей :

 >>> вещи = double_stuff (вещи)
>>> вещи
[4, 10, 'SpamSpam', 19.0]
>>>
 

5.10. Как лучше?

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

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

5.11. Полиморфизм и типирование уток

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

 >>> def double (вещь):
... вернуть 2 * вещь
...
>>> двойной (5)
10
>>> double ('Спам')
'СпамСпам'
>>> double ([1, 2])
[1, 2, 1, 2]
>>> двойной (3,5)
7.0
>>> double (('а', 'б'))
('а', 'б', 'а', 'б')
>>> двойной (Нет)
Отслеживание (последний вызов последний):
  Файл "", строка 1, в 
  Файл "", строка 2, в двойном формате
TypeError: неподдерживаемые типы операндов для *: 'int' и 'NoneType'
>>>
 

Поскольку * определено для целых чисел, строк, списков, чисел с плавающей запятой и кортежей,
вызов нашей функции double с любым из этих типов в качестве аргумента не
проблема. * не определено для NoneType, поэтому отправка
double function a None Значение приводит к ошибке времени выполнения.

5.12. Двумерные столы

Двумерная таблица - это таблица, в которой вы читаете значение на пересечении
строки и столбца. Таблица умножения - хороший пример. Скажем вы
хотите распечатать таблицу умножения для значений от 1 до 6.

Хороший способ начать - написать цикл, который печатает числа, кратные 2, все на
одна линия:

 для i в диапазоне (1, 7):
    print (2 * я, конец = "")
Распечатать()
 

Здесь мы использовали функцию range , но заставили ее начинать свою последовательность с 1.По мере выполнения цикла значение i изменяется с 1 на 6. Когда все
элементы диапазона были присвоены номерам и , цикл завершается. Каждый
раз в цикле отображается значение 2 * i , за которым следуют три
пробелы.

Опять же, дополнительный аргумент end = "" в функции print подавляет
перевод строки и вместо этого использует три пробела. После завершения цикла вызов
до выведите в строке 3, чтобы завершить текущую строку и начать новую строку.

Вывод программы:

Пока все хорошо. Следующий шаг - инкапсулировать и обобщить .

5.13. Больше инкапсуляции

Эта функция инкапсулирует предыдущий цикл и обобщает его для печати
кратные n :

 def print_multiples (n):
    для i в диапазоне (1, 7):
        print (n * i, end = "")
    Распечатать()
 

Для инкапсуляции все, что нам нужно было сделать, это добавить первую строку, в которой объявляется
имя функции и список параметров.В общем, все, что нам нужно было сделать
было заменено значение 2 параметром n .

Если мы вызовем эту функцию с аргументом 2, мы получим тот же результат, что и раньше.
С аргументом 3 вывод:

С аргументом 4 вывод:

Теперь вы, наверное, уже догадались, как распечатать таблицу умножения - по
вызов print_multiples несколько раз с разными аргументами. Фактически, мы
можно использовать другой цикл:

 для i в диапазоне (1, 7):
    print_multiples (я)
 

Обратите внимание, насколько этот цикл похож на цикл внутри print_multiples .Все мы
сделал замену функции print на вызов функции.

Результатом этой программы является таблица умножения:

 1 2 3 4 5 6
2 4 6 8 10 12
3 6 9 12 15 18
4 8 12 16 20 24
5 10 15 20 25 30
6 12 18 24 30 36
 

5.14. Еще больше инкапсуляции

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

 def print_mult_table ():
    для i в диапазоне (1, 7):
        print_multiples (я)
 

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

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

5,15. Локальные переменные

Вам может быть интересно, как мы можем использовать одну и ту же переменную и в обоих
print_multiples и print_mult_table .Разве это не вызывает проблем, когда
одна из функций меняет значение переменной?

Ответ - нет, потому что i в print_multiples и i в
print_mult_table - это , а не , одна и та же переменная.

Переменные, созданные внутри определения функции, являются локальными; вы не можете получить доступ к
локальная переменная извне своей домашней функции. Это означает, что вы можете иметь
несколько переменных с одинаковыми именами, если они не находятся в одном и том же
функция.

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

Диаграмма стека для этой программы показывает, что две переменные с именами и являются
не та же переменная. Они могут относиться к разным значениям и изменять одно
не влияет на другие.

Значение i в print_mult_table изменяется от 1 до 6. На диаграмме это
оказывается 3.При следующем прохождении цикла это будет 4. Каждый раз через
цикл print_mult_table вызывает print_multiples с текущим значением
и в качестве аргумента. Это значение присваивается параметру n .

Внутри print_multiples значение i изменяется от 1 до 6. В
Диаграмма, оказывается 2. Изменение этой переменной не влияет на значение
из и в print_mult_table .

Обычно и совершенно законно иметь разные локальные переменные с
то же имя.В частности, такие имена, как i и j , часто используются как
переменные цикла. Если вы избегаете их использования в одной функции только потому, что вы использовали
их где-нибудь еще, вы, вероятно, затрудните чтение программы.

5.16. Рекурсивные структуры данных

Все типы данных Python, которые мы видели, можно сгруппировать внутри списков и
кортежи разными способами. Списки и кортежи также могут быть вложенными, обеспечивая
бесчисленное множество возможностей для организации данных. Организация данных для
цель упрощения использования называется
структура данных.

Время выборов, и мы помогаем подсчитывать количество голосов по мере их поступления.
Голоса, прибывающие из отдельных приходов, участков, муниципалитетов, округов и
состояния иногда указываются в виде суммы голосов, а иногда в виде списка
промежуточных итогов голосов. Обдумав, как лучше всего хранить счетчики, мы
решаем использовать список вложенных номеров , который мы определяем следующим образом:

Вложенный список номеров - это список, элементы которого:

  1. номера

  2. списки вложенных номеров

Обратите внимание, что термин «вложенный список номеров» используется в собственном определении.Рекурсивные определения
такие довольно распространены в математике и
Информатика. Они позволяют кратко и эффективно описать
рекурсивные структуры данных
которые частично состоят из более мелких и простых экземпляров самих себя. В
определение не является циклическим, так как в какой-то момент мы достигнем списка, который
не иметь списков в качестве элементов.

Теперь предположим, что наша задача - написать функцию, которая суммирует все значения в
список вложенных номеров. Python имеет встроенную функцию, которая находит сумму
последовательность цифр:

 >>> сумма ([1, 2, 8])
11
>>> sum ((3, 5, 8.5))
16,5
>>>
 

Однако для нашего списка вложенных номеров , сумма не будет работать:

 >>> сумма ([1, 2, [11, 13], 8])
Отслеживание (последний вызов последний):
  Файл "", строка 1, в 
TypeError: неподдерживаемые типы операндов для +: 'int' и 'list'
>>>
 

Проблема в том, что третий элемент этого списка, [11, 13] , сам по себе
список, который нельзя добавить в 1 , 2 и 8 .

5.17. Рекурсия

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

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

 def recursive_sum (список вложенных_числов):
    the_sum = 0
    для элемента в nested_num_list:
        если type (element) == list:
            the_sum = the_sum + recursive_sum (элемент)
        еще:
            the_sum = the_sum + элемент
    вернуть the_sum
 

Тело recursive_sum в основном состоит из цикла для , который проходит
nested_num_list .Если элемент является числовым значением ( иначе ветвь),
он просто добавляется к the_sum . Если элемент является списком, то
recursive_sum вызывается снова с элементом в качестве аргумента. В
оператор внутри определения функции, в котором функция вызывает себя, является
известный как рекурсивный вызов.

Recursion - действительно один из самых красивых и элегантных инструментов на компьютере.
наука.

Немного более сложная проблема - найти наибольшее значение в нашем вложенном
список номеров:

 def recursive_max (nested_num_list):
    "" "
      >>> recursive_max ([2, 9, [1, 13], 8, 6])
      13
      >>> recursive_max ([2, [[100, 7], 90], [1, 13], 8, 6])
      100
      >>> recursive_max ([2, [[13, 7], 90], [1, 100], 8, 6])
      100
      >>> recursive_max ([[[13, 7], 90], 2, [1, 100], 8, 6])
      100
    "" "
    наибольший = nested_num_list [0]
    в то время как тип (наибольший) == тип ([]):
        наибольший = наибольший [0]

    для элемента в nested_num_list:
        если type (element) == type ([]):
            max_of_elem = recursive_max (элемент)
            если самый большой 

Doctests включены, чтобы предоставить примеры работы recursive_max .

Дополнительным поворотом к этой проблеме является поиск числового значения для инициализации
наибольший . Мы не можем просто использовать nested_num_list [0] , так как я либо
число или список. Чтобы решить эту проблему, мы используем цикл while, который назначает
наибольшее значение до первого числового значения независимо от того, насколько глубоко оно вложено.

Каждый из двух приведенных выше примеров имеет базовый вариант , который не приводит к
рекурсивный вызов: случай, когда элемент является числом, а не списком.Без
в базовом случае у вас бесконечная рекурсия , и ваша программа не будет работать.
Python останавливается после достижения максимальной глубины рекурсии и возвращает время выполнения
ошибка.

Запишите следующее в файл с именем infinite_recursion.py :

 #
# infinite_recursion.py
#
def recursion_depth (число):
    print "Число глубины рекурсии% d." % количество
    рекурсия_глубина (число + 1)

рекурсия_глубина (0)
 

В командной строке unix в том же каталоге, в котором вы сохранили
программу введите следующее:

 python infinite_recursion.ру
 

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

 ...
  Файл infinite_recursion.py, строка 3, в recursion_depth
    рекурсия_глубина (число + 1)
RuntimeError: превышена максимальная глубина рекурсии
 

Мы, конечно, никогда не хотели бы, чтобы что-то подобное случилось с пользователем одного из
наши программы, поэтому, прежде чем закончить обсуждение рекурсии, давайте посмотрим, как
подобные ошибки обрабатываются в Python.

5,18. Исключения

Каждый раз, когда возникает ошибка времени выполнения, создается исключение . Программа останавливается
выполняется в этот момент, и Python распечатывает трассировку, которая заканчивается
произошедшее исключение.

Например, деление на ноль создает исключение:

 >>> печать 55/0
Отслеживание (последний вызов последний):
  Файл "", строка 1, в 
ZeroDivisionError: целочисленное деление или по модулю нуля
>>>
 

То же самое и с доступом к несуществующему элементу списка:

 >>> a = []
>>> выведите [5]
Отслеживание (последний вызов последний):
  Файл "", строка 1, в 
IndexError: список индекса вне допустимого диапазона
>>>
 

Или попытка присвоения элемента кортежу:

 >>> tup = ('а', 'б', 'д', 'д')
>>> tup [2] = 'c'
Отслеживание (последний вызов последний):
  Файл "", строка 1, в 
TypeError: объект 'tuple' не поддерживает назначение элементов
>>>
 

В каждом случае сообщение об ошибке в последней строке состоит из двух частей: тип
ошибка перед двоеточием и подробные сведения об ошибке после двоеточия.

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

Например, мы можем запросить у пользователя имя файла, а затем попытаться
Открой это. Если файл не существует, мы не хотим, чтобы программа вылетела из строя; мы хотим
для обработки исключения:

 filename = raw_input ('Введите имя файла:')
пытаться:
    f = open (имя файла, "r")
Кроме:
    print 'Нет файла с именем', имя файла
 

Оператор try выполняет операторы в первом блоке.Если нет
возникают исключения, он игнорирует , кроме оператора . Если возникает какое-либо исключение,
он выполняет операторы в , кроме ветви , а затем продолжает.

Мы можем инкапсулировать эту возможность в функции: существует принимает имя файла
и возвращает true, если файл существует, и false, если его нет:

 def существует (имя файла):
    пытаться:
        f = open (имя файла)
        f.close ()
        вернуть True
    Кроме:
        вернуть ложь
 

Вы можете использовать несколько блоков , кроме , для обработки различных типов исключений.
(см. Ошибки и исключения
урок от Python Tutorial от создателя Python Гвидо ван Россума для более полного обсуждения
исключения).

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

 #
# learn_exceptions.py
#
def get_age ():
    age = input ('Пожалуйста, введите свой возраст:')
    если возраст <0:
        Raise ValueError, "% s не является допустимым возрастом"% age
    возраст возвращения
 

Оператор raise принимает два аргумента: тип исключения и конкретный
информация об ошибке. ValueError - встроенное исключение, которое
наиболее точно соответствует той ошибке, которую мы хотим вызвать. Полный список
встроенных исключений находится в разделе встроенных исключений Python
Справочник по библиотеке, снова созданный создателем Python,
Гвидо ван Россум.

Если функция, которая вызвала get_age , обрабатывает ошибку, то программа может
Продолжать; в противном случае Python печатает трассировку и завершает работу:

 >>> get_age ()
Пожалуйста, введите ваш возраст: 42
42
>>> get_age ()
Пожалуйста, введите ваш возраст: -2
Отслеживание (последний вызов последний):
  Файл "", строка 1, в 
  Файл "learn_exceptions.py ", строка 4, в get_age
    Raise ValueError, "% s не является допустимым возрастом"% age
ValueError: -2 не является допустимым возрастом
>>>
 

Сообщение об ошибке включает тип исключения и дополнительную информацию.
вы предоставили.

Используя обработку исключений, теперь мы можем изменить infinite_recursion.py так, чтобы
он останавливается, когда достигает максимальной разрешенной глубины рекурсии:

 #
# infinite_recursion.py
#
def recursion_depth (число):
    print "Число глубины рекурсии% d." % количество
    пытаться:
        рекурсия_глубина (число + 1)
    Кроме:
        print "Превышена максимальная глубина рекурсии."

рекурсия_глубина (0)
 

Запустите эту версию и посмотрите на результаты.

5.19. Рекурсия хвоста

Когда единственное, что возвращается из функции, - это рекурсивный вызов, на нее ссылаются
как хвостовая рекурсия .

Вот версия функции обратного отсчета из главы 6, написанная с использованием
хвостовая рекурсия:

Обратный отсчет

 def (n):
    если n == 0:
        печать "Blastoff!"
    еще:
        напечатать n
        обратный отсчет (n-1)
 

Любое вычисление, которое может быть выполнено с использованием итерации, также может быть выполнено с использованием
рекурсия.Вот версия find_max , написанная с использованием хвостовой рекурсии:

 def find_max (seq, max_so_far):
    если не seq:
        вернуть max_so_far
    если max_so_far 

Хвостовая рекурсия считается плохой практикой в ​​Python, поскольку Python
компилятор не выполняет оптимизацию для хвостовых рекурсивных вызовов. Рекурсивный
решение в таких случаях использует больше системных ресурсов, чем эквивалент
итерационное решение.

5.20. Рекурсивные математические функции

Рекурсивно определены несколько хорошо известных математических функций. Факториалу, например, придается особая
оператор, ! , и определяется по:

Мы можем легко запрограммировать это на Python:

 def factorial (n):
    если n == 0:
        возврат 1
    еще:
        вернуть n * факториал (n-1)
 

Еще одно хорошо известное рекурсивное соотношение в математике - это соотношение Фибоначчи.
последовательность, которая определяется
по:

 фибоначчи (0) = 1
фибоначчи (1) = 1
фибоначчи (п) = фибоначчи (п-1) + фибоначчи (п-2)
 

Это также можно легко написать на Python:

 def fibonacci (n):
    если n == 0 или n == 1:
        возврат 1
    еще:
        вернуть фибоначчи (n-1) + fibonacci (n-2)
 

Вызов факториала (1000) превысит максимальную глубину рекурсии.И попробовать
запустите fibonacci (35) и посмотрите, сколько времени потребуется для завершения (будьте терпеливы, это
завершу).

Вам будет предложено написать итеративную версию факториала как
упражнение, и мы увидим лучший способ обработки fibonacci в следующем
глава.

5.21. Глоссарий

аргумент

Значение, передаваемое функции при ее вызове. Это значение
присваивается соответствующему параметру в функции.

поток выполнения

Порядок, в котором операторы выполняются во время выполнения программы.

frame

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

function

Именованная последовательность операторов, выполняющая некоторые полезные операции.
Функции могут принимать или не принимать параметры, а также могут создавать или не создавать
результат.

вызов функции

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

композиция функций

Использование выходных данных одного вызова функции в качестве входных данных для другого.

определение функции

Оператор, который создает новую функцию, указывая ее имя,
параметры и операторы, которые он выполняет.

Первая часть составного отчета. Заголовки начинаются с ключевого слова и
заканчиваться двоеточием (:)

локальная переменная

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

Нет

Единственное значение . Нет часто используется для
представляют собой отсутствие значения. Также возвращается return
оператор без аргументов или функция, которая достигает конца своего
body без нажатия return statement, содержащего значение.

параметр

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

диаграмма стека

Графическое представление стека функций, их переменных,
и ценности, к которым они относятся.

traceback

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

Руководство по функциям Python с примерами

Введение в функции в Python

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

Функции позволяют создавать более модульные и СУХИЕ решения сложных проблем.

Хотя Python уже предоставляет множество встроенных функций, таких как print () и len () , вы также можете определить свои собственные функции для использования в ваших проектах.

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

Синтаксис

В Python определение функции имеет следующие особенности:

  1. Ключевое слово def
  2. имя функции
  3. paranthesis '()' и внутри входных параметров paranthesis, хотя входные параметры по желанию.
  4. двоеточие ’:’
  5. некоторый блок кода для выполнения
  6. оператора возврата (необязательно)
  # функция без параметров или возвращаемых значений
def sayHello ():
  print ("Привет!")

sayHello () # вызывает функцию 'Hello!' выводится на консоль

# функция с параметром
def helloWithName (имя):
  print («Привет» + имя + «!»)

helloWithName ("Ada") # вызывает функцию 'Hello Ada!' выводится на консоль

# функция с несколькими параметрами с оператором возврата
def multiply (val1, val2):
  вернуть val1 * val2

multiply (3, 5) # выводит 15 на консоль  

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

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

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

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

  # это базовая функция суммы
def sum (a, b):
  вернуть a + b

результат = сумма (1, 2)
# result = 3  

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

  def sum (a, b = 3):
  вернуть a + b

результат = сумма (1)
# result = 4  

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

  результат = сумма (b = 2, a = 2)
# result = 4  

Однако невозможно передать аргумент ключевого слова перед неосновным

  result = sum (3, b = 2)
#result = 5
результат2 = сумма (b = 2, 3)
# Будет вызывать SyntaxError  

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

  с = сумма
результат = s (1, 2)
# result = 3  

Примечания

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

  print (multiply (3)) # TypeError: multiply () принимает ровно 2 аргумента (задано 0)

print (multiply ('a', 5)) # 'aaaaa' выводится на консоль

print (multiply ('a', 'b')) # TypeError: Python не может умножить две строки  

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

  def myFunc ():
print ('это напечатает')
print ('так будет')

х = 7
# присвоение x не является частью функции, поскольку оно не имеет отступа.  

Переменные, определенные в функции, существуют только в рамках этой функции.

  def double (число):
х = число * 2
вернуть х

print (x) # error - x не определен
print (double (4)) # выводит 8  

Python интерпретирует функциональный блок только тогда, когда функция вызывается, а не когда функция определена. Таким образом, даже если блок определения функции содержит какую-то ошибку, интерпретатор python будет указывать это происходит только при вызове функции.

Теперь давайте рассмотрим некоторые конкретные функции с примерами.

max () function

max () - встроенная функция в Python 3.Он возвращает самый большой элемент в итерации или самый большой из двух или более аргументов.

Аргументы

Эта функция принимает в качестве аргумента два или более числа или любой итерируемый объект. Предоставляя итерацию в качестве аргумента, мы должны убедиться, что все элементы в итерации имеют один и тот же тип. Это означает, что мы не можем передать список, в котором хранятся как строковые, так и целочисленные значения. Синтаксис: max (iterable, * iterables [, key, default]) max (arg1, arg2, * args [, key])

Допустимые аргументы:

  max (2, 3)
макс ([1, 2, 3])
max ('a', 'b', 'c')  

Недействительные аргументы:

  max (2, 'a')
max ([1, 2, 3, 'a'])
max ([])  

Возвращаемое значение

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

Пример кода

  print (max (2, 3)) # Возвращает 3, поскольку 3 является наибольшим из двух значений
print (max (2, 3, 23)) # Возвращает 23, поскольку 23 - наибольшее из всех значений

list1 = [1, 2, 4, 5, 54]
print (max (list1)) # Возвращает 54, поскольку 54 - наибольшее значение в списке

list2 = ['a', 'b', 'c']
print (max (list2)) # Возвращает 'c', поскольку 'c' является наибольшим в списке, потому что c имеет значение ascii больше, чем 'a', 'b'.list3 = [1, 2, 'abc', 'xyz']
print (max (list3)) # Выдает TypeError, поскольку значения в списке имеют другой тип

# Исправьте ошибку TypeError, упомянутую выше, прежде чем переходить к следующему шагу

list4 = []
print (max (list4)) # Выдает ValueError, поскольку аргумент пуст.  

Run Code

Official Docs

min () function

min () - встроенная функция в Python 3. Она возвращает наименьший элемент в итерации или наименьший из двух или более аргументов.

Аргументы

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

Допустимые аргументы:

  мин (2, 3)
мин ([1, 2, 3])
min ('a', 'b', 'c')  

Недействительные аргументы:

  min (2, 'a')
min ([1, 2, 3, 'a'])
min ([])  

Возвращаемое значение

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

Пример кода

  print (min (2, 3)) # Возвращает 2, поскольку 2 является наименьшим из двух значений
print (min (2, 3, -1)) # Возвращает -1, поскольку -1 - наименьшее из двух значений

list1 = [1, 2, 4, 5, -54]
print (min (list1)) # Возвращает -54, поскольку -54 - наименьшее значение в списке

list2 = ['a', 'b', 'c']
print (min (list2)) # Возвращает 'a', поскольку 'a' является наименьшим в списке в алфавитном порядке

list3 = [1, 2, 'abc', 'xyz']
print (min (list3)) # Выдает TypeError, поскольку значения в списке имеют другой тип

# Исправьте ошибку TypeError, упомянутую выше, прежде чем переходить к следующему шагу

list4 = []
print (min (list4)) # Выдает ValueError, поскольку аргумент пуст.  

Run Code

Official Docs

divmod () - встроенная функция в Python 3, которая возвращает частное и остаток при делении номер а по номеру б .В качестве аргументов он принимает два числа: , и , . Аргумент не может быть комплексным числом.

Аргумент

Требуется два аргумента: a и b - целое или десятичное число. Оно не может быть комплексным числом.

Возвращаемое значение

Возвращаемое значение - это пара положительных чисел, состоящая из частного и остатка, полученная путем деления a на b . В случае смешанных типов операндов будут применяться правила для бинарных арифметических операторов.
Для целочисленных аргументов возвращаемое значение будет таким же, как (a // b, a% b) .
Для аргументов Decimal number возвращаемое значение будет таким же, как (q, a% b) , где q обычно равно math.floor (a / b) , но может быть на 1 меньше, чем который.

Пример кода

  print (divmod (5,2)) # print (2,1)
print (divmod (13.5,2.5)) # выводит (5.0, 1.0)
q, r = divmod (13.5,2.5) # Назначает q = частное & r = остаток
print (q) # печатает 5.0, потому что math.floor (13,5 / 2,5) = 5,0
print (r) # выводит 1.0, потому что (13.5% 2.5) = 1.0  

REPL It!

Official Docs

Hex (x) function

hex (x) - это встроенная функция в Python 3 для преобразования целого числа в строчную шестнадцатеричную строку с префиксом «0x».

Аргумент

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

Return

Эта функция возвращает шестнадцатеричную строку в нижнем регистре с префиксом «0x».

Пример

  print (hex (16)) # выводит 0x10
print (hex (-298)) # выводит -0x12a
print (hex (543)) # печатает 0x21f  

Код выполнения

Официальная документация

Функция len ()

len () является встроенной функцией в Python 3. Этот метод возвращает длину (число пунктов) объекта. Требуется один аргумент x .

Аргументы

Требуется один аргумент, x . Этот аргумент может быть последовательностью (например, строкой, байтами, кортежем, списком или диапазоном) или коллекцией (например, словарем, набором или замороженным набором).

Возвращаемое значение

Эта функция возвращает количество элементов в аргументе, который передается в функцию len () .

Пример кода

  list1 = [123, 'xyz', 'zara'] # list
print (len (list1)) # выводит 3, поскольку в списке 3 элемента

str1 = 'баскетбол' # строка
print (len (str1)) # выводит 10, поскольку str1 состоит из 10 символов

tuple1 = (2, 3, 4, 5) # кортеж
print (len (tuple1)) # выводит 4, так как в кортеже 4 элемента

dict1 = {'name': 'John', 'age': 4, 'score': 45} # словарь
print (len (dict1)) # печатает 3, поскольку в dict1 есть 3 пары ключей и значений  

Run Code

Official Docs

Ord function

ord () - встроенная функция в Python 3 для преобразования строки, представляющей один символ Unicode, в целое число, представляющее код Unicode символа.

Примеры:

  >>> ord ('d')
100
>>> ord ('1')
49  

chr function

chr () - это встроенная функция в Python 3 для преобразования целого числа, представляющего код Unicode, в строку, представляющую соответствующий символ.

Примеры:

  >>> chr (49)
'1'  

Следует отметить, что если целочисленное значение, переданное в chr () , выходит за пределы допустимого диапазона, возникает ошибка ValueError.

  >>> chr (-10)
'Traceback (последний вызов последний):
  Файл "", строка 1, в 
    chr (-1)
ValueError: chr () arg not in range (0x110000) ' 

input () functions

Часто в программе нам требуется ввод данных от пользователя. Получение информации от пользователя делает программу интерактивной. В Python 3 для приема ввода от пользователя у нас есть функция input () . Если вызывается функция ввода, выполнение программы будет остановлено до тех пор, пока пользователь не введет ввод и не завершит ввод с помощью клавиши возврата.Давайте посмотрим на несколько примеров:

Когда мы просто хотим принять ввод:

inp = input ()

Run Code

Чтобы дать подсказку с сообщением:

prompt with message = input ('')

Код запуска

3. Если мы хотим ввести целочисленный ввод:

  число = int (ввод ('Пожалуйста, введите число:'))  

Код запуска

Если вы вводите нецелочисленное значение, тогда Python выдаст ошибку ValueError . Поэтому всякий раз, когда вы используете это, убедитесь, что вы его тоже поймали. В противном случае ваша программа неожиданно остановится после запроса.

  число = int (input ('Пожалуйста, введите число:'))
# Пожалуйста, введите число: как
# Введите строку, и она выдаст эту ошибку
# ValueError: недопустимый литерал для int () с основанием 10 'как'  

4. Если нам нужен строковый ввод:

  string = str (input ('Пожалуйста, введите строку:'))  

Run Code

Тем не менее, входные данные по умолчанию сохраняются в виде строки.Использование функции str () дает понять читателю кода, что ввод будет «строкой». Рекомендуется заранее указать, какой тип ввода будет сделан.

Официальные документы

Как вызвать функцию в Python

Оператор определения функции не выполняет функцию. Выполнение (вызов) функции выполняется с использованием имени функции, за которым следует круглые скобки, заключающие обязательные аргументы (если есть).

  >>> def say_hello ():
... print ('Привет')
...
>>> say_hello ()
Привет  

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

  >>> а = 1
>>> b = 10
>>> def fn ():
... print (a) # local a не назначено, включающая функция не указана, глобальный a не указан.
... b = 20 # локальный b назначается в локальной таблице символов для функции.
... print (b) # ссылка на локальный b.
...
>>> fn ()
1
20
>>> b # global b не изменяется при вызове функции.
10  

Фактические параметры (аргументы) вызова функции вводятся в локальную таблицу символов вызываемой функции при ее вызове; таким образом, аргументы передаются с использованием вызова по значению (где значение всегда является ссылкой на объект, а не значением объекта).Когда функция вызывает другую функцию, для этого вызова создается новая локальная таблица символов.

  >>> def приветствие:
... s = "Hello" + s # s в локальной таблице символов переназначены.
... печать (и)
...
>>> person = "Боб"
>>> приветствую (человек)
Привет Боб
>>> person # человек, которого раньше звонил, остается привязанным к исходному объекту, 'Bob'.
'Bob'  

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

  >>> def fn (arg):
... arg.append (1)
...
>>> a = [1, 2, 3]
>>> fn (a)
>>> а
[1, 2, 3, 1]  

Введение в функции Python | 365 Data Science

Итак, вы хотите научиться программировать на Python? Что ж, вы не можете этого сделать, не зная, как работать с функциями Python.

Не беспокойтесь, в этом руководстве мы научим вас, как использовать функции Python и как они могут помочь вам при программировании на Python. Лучший способ обучения - это делать, поэтому давайте создадим нашу первую функцию и посмотрим, как ее можно применить.

Как определить функцию в Python

Чтобы сообщить компьютеру, что вы хотите создать функцию Python, просто напишите def в начале строки. Def не является ни командой, ни функцией. Это ключевое слово . Чтобы указать это, Jupyter автоматически изменит цвет шрифта на зеленый. Затем вы можете ввести имя функции, которую вы будете использовать. (Чтобы узнать, как перемещаться по панели инструментов Jupyter, ознакомьтесь с нашим руководством The Jupyter Dashboard - A Walkthrough.)

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

Поскольку неудобно продолжать на той же строке, когда функция становится длиннее, гораздо лучше выработать привычку размещать инструкции на новой строке, снова с отступом.Хорошая разборчивость - залог хорошего стиля программирования! И меньше споров с людьми, с которыми вы работаете (эти умники ...)

Хорошо, давайте посмотрим, что произойдет, когда мы попросим машину напечатать предложение.

Немного, по крайней мере, на данный момент.

Компьютер создал функцию «простая», которая может распечатать «Моя первая функция», но это все. Чтобы применить функцию, мы должны вызвать ее . Мы должны попросить функцию сделать свою работу.Итак, мы получим его результат, если введем его имя, «простой» и круглые скобки. Видеть?

Отлично! Но давайте сделаем что-нибудь посложнее. В конце концов, функции Python не могут быть такими простыми, верно?

Как создать функцию с параметром

Нашей следующей задачей будет создание функции Python с параметром. Пусть это будет «плюс десять» с параметром «а», что дает нам сумму «а» и 10 в результате…

Всегда начинайте с ключевого слова def.Затем введите имя функции «плюс десять» и в скобках укажите параметр «а». Последнее, что нужно написать в этой строке, - это знак двоеточия.

Хорошо. Что будет дальше, очень важно. Даже важнее, чем чистить зубы вечером. Серьезно. (Не согласен? Ну, тогда это не менее важно, так что обратите внимание)

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

Тип:

  возврат + 10  

Это будет тело этой функции.

Теперь давайте вызовем «плюс десять» с аргументом 2, указанным в скобках.

Потрясающе! Оно работает. (Мы были очень удивлены, что это сработало!)

После того, как мы создали функцию, мы можем запускать ее несколько раз, изменяя ее аргумент.Я мог бы запустить «плюс десять» с аргументом 5, и на этот раз ответ будет 15.

Обратите внимание на следующее. Когда мы определяем функцию, мы указываем в скобках параметр. В функции «плюс десять» «а» является параметром. Позже, когда мы вызываем эту функцию, правильнее будет сказать, что мы предоставляем аргумент, а не параметр. Таким образом, мы можем сказать «вызов плюс десять с аргументом 2, вызов плюс десять с аргументом 5».

Люди часто путают

print и return и тип ситуаций, в которых мы можем их применить .Чтобы лучше понять концепцию, попробуйте представить себе следующее.

Имеется аргумент x, который служит входом в функцию, подобную той, что у нас здесь. Функция в данном случае равна x плюс 10. Учитывая, что x является входом, мы можем думать о нем как о значении, которое мы уже знаем, поэтому комбинация x и функции даст нам выходное значение y. Что ж, в программировании возвращает с учетом значения y; он просто говорит машине «после операций, выполненных функцией f, верните мне значение« y ».«Возврат» играет связь между вторым и третьим этапами процесса. Другими словами, функция может принимать входные данные от одной или нескольких переменных и возвращать один вывод , состоящий из одного или нескольких значений.

Вот почему «return» может использоваться в функции только один раз.

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

Следует учесть некоторые дополнительные преимущества. Вы также можете присвоить функции более интуитивное имя - «плюс десять» или «сложение 10», и функция Python все равно будет работать правильно.Это признак хорошего дизайна. Если на листе с тысячей строк кода вы вызовете все свои функции Python x1, x2, x3 и так далее, ваши коллеги будут сбиты с толку и совершенно недовольны.

Четкое и краткое наименование функций Python делает ваш программный код легким для понимания, и он будет воспринят как образец хорошего стиля. (Если вы хотите научиться набирать чистый код на любом языке программирования, прочтите нашу статью Как набирать код чисто и идеально организованно.Или, если вы хотите получить мощные всесторонние знания в области программирования Python, обязательно ознакомьтесь с нашим Полным руководством по программированию на Python.)

Другой способ определения функции

Есть еще один способ организовать определение вашей функции. Начните с определения «плюс десять» с аргументом «а» и двоеточием. В следующей строке вместо прямого возврата значения «а» плюс 10 внутри функции может быть создана другая переменная для передачи этого значения.Я буду использовать здесь название «результат». Я присвою ему желаемое значение «а» плюс 10.

Давайте проверим, что мы только что сделали.

Если я выполню код в ячейке, я ничего не получу. Почему? Потому что до сих пор я только объявил переменную «результат» в теле нашей функции.

Естественно, чтобы получить желаемый результат, мне также нужно будет вернуть этой переменной.

Видите? Когда я называю «плюс десять» с аргументом 2, я получаю 12.Снова все в порядке.

«

Печать» принимает оператор или, лучше сказать, объект и предоставляет его печатное представление в выходной ячейке.

Он просто делает определенный оператор видимым для программиста. Хорошая причина для этого - когда у вас огромный объем кода и вы хотите видеть распечатанные промежуточные шаги вашей программы, чтобы вы могли следовать потоку управления . В противном случае print не повлияет на расчет вывода.

Иными словами, возврат не визуализирует вывод. Он определяет, какую функцию должен вернуть назад. Важно понимать, что делает каждое из двух ключевых слов. Это очень поможет вам при работе с функциями Python.

Следующее может быть полезным.

Пусть та же функция также распечатает оператор «результат». Если мы запишем только «вернуть результат», а затем «вернуть результат», что мы получим, когда вызовем функцию? Просто первый объект, который нужно вернуть - утверждение «результат».

Если вместо этого мы напечатаем этот оператор , а затем вернем «результат», мы получим то, что хотели: оператор «результат» и результат вычисления - 12. (Если вы хотите изучить элегантный способ выражения добавив оператор с ключевым словом elif , ознакомьтесь с нашим руководством Что такое Elif в Python.)

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

Как использовать функцию в другой функции

Не секрет, что у нас может быть функция внутри функции (что гораздо полезнее, чем картинка внутри картинки).Например, давайте определим функцию под названием «заработная плата», которая рассчитывает вашу дневную заработную плату. Допустим, вы используете рабочих часов в качестве параметра, и вам платят 25 долларов за час.

Обратите внимание, мне технически не нужна команда печати здесь.

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

Когда вы преуспеете в течение дня, ваш босс будет очень рад выплатить бонус в размере 50 долларов, добавленных к вашей зарплате (ну, по крайней мере, он говорит, что счастлив...). Поэтому я определю для вас функцию «с бонусом» . И в качестве параметра я снова буду использовать рабочих часов . Но на этот раз у нас будет два аргумента, определяющих эту функцию - ваша заработная плата (которая является функцией количества отработанных вами часов, и дополнительные 50 долларов, которые вам будут заплачены, когда ваш босс решит, что вы заслуживаете премии.

)

Вот как первая функция участвует в выводе второй - функция внутри функции!

Давайте посмотрим, каков будет результат, если вы сегодня отработали 8 часов, а начальник был очень доволен вашей работой.

«Заработная плата» с аргументом 8 и «с бонусом» с аргументом 8.

Отлично! 200 базовой компенсации, которая становится 250 с бонусом! Вы заработали каждую копейку! 🙂

Примечание автора: если вы заинтересованы в карьере, которая принесет вам не только несколько пенни, но и потенциально к северу от 130 000 долларов, не пропустите наше бесплатное руководство по карьере «Как стать специалистом по данным».

Как объединить условные операторы и функции

Мы уже знаем, как работать с операторами if и как работать с функциями Python.В этом посте мы узнаем, как их сочетать. Это фундаментальная концепция программирования, поэтому обратите внимание! Вы будете сталкиваться с этим довольно регулярно при кодировании.

Мама Джонни сказала ему, что к концу недели, если он накопит не менее 100 долларов, она даст ему дополнительные 10 долларов, однако, если ему не удастся сэкономить хотя бы 100 долларов, она предпочла бы этого не делать. чтобы дать ему лишние деньги.

Ясно. Теперь давайте определим функцию под названием «добавить 10», которая принимает в качестве параметра неизвестное «m», которое представляет деньги, которые Джонни сэкономил к концу недели.

Что мы должны попросить компьютер сделать?

Если «m» больше или равно 100, добавьте 10 к сохраненной сумме. Если это не так, верните заявление, которое сообщает нам, что Джонни должен экономить больше.

То есть, если «m» больше или равно 100, пусть «m» принимает значение «m» плюс 10.

У нас есть «m» на обеих сторонах уравнения, и это совершенно нормально. На самом деле это не уравнение. Помните, что знак «равенства» означает, что выражение в правой части соотносится с тем, что написано в левой части.

Давайте дополним if-часть фразой « возврат м». Подводя итог, логично упомянуть «m» как параметр. Затем мы заменяем его значение значением больше «m» на 10. В конце мы говорим: с этого момента возвращаем значение, равное новым «m».

Наконец, во всех остальных случаях функция будет отображать «Сохранить больше!» (Джонни должен понять, что иметь немного наличных - хорошая привычка, верно?)

Посмотрим, верна ли наша интуиция.

  доб_10 (110)  

Хорошо, 120! А если «m» было равно 50…?

Потрясающе! Все правильно!

Если подумать с логической точки зрения, это имеет смысл, не так ли? Для чего бы вы использовали компьютер? - решать проблемы за вас. И это можно сделать с помощью функций. Скорее всего, вам нужно будет попросить машину выполнить что-то, если данный параметр находится в пределах определенных пределов , и попросить его выполнить другое действие, если параметр на превышает эти пределы .Таким образом, объединение ваших знаний об условных операторах и функциях Python окупается.

Как создавать функции Python, содержащие несколько аргументов

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

Должен ли я вызвать имеющуюся здесь функцию, скажем, для 10, 3 и 2? Я получаю 4.

Кажется, легко добавить несколько параметров, не так ли? И это! Просто будьте осторожны с порядком , в котором вы указываете их значения. В нашем случае я присвоил 10 переменной a, 3 переменной b и 2 переменной c.

В противном случае порядок не будет иметь значения, если и только если вы укажете имена переменных в круглых скобках следующим образом: b равно 3, a равно 10, а c равно 2.

И, конечно, мы могли получить такой же ответ - 4!

Вот как мы можем работать с функциями, имеющими несколько аргументов.

Встроенные функции в Python

Когда вы устанавливаете Python на свой компьютер, вы также устанавливаете некоторые из его встроенных функций . Это означает, что вам не нужно вводить их код каждый раз, когда вы их используете - эти функции Python уже есть на вашем компьютере и могут применяться напрямую.

Функция «тип» позволяет вам получить тип переменной, которую вы используете в качестве аргумента, как в этой ячейке - «Тип» из 10 дает «int» для целого числа.

Функции int, float и string преобразуют свои аргументы в тип данных integer, float и string соответственно.Вот почему 5.0 было преобразовано в 5, 3 было преобразовано в 3.0, а число 500 стало текстом.

Теперь позвольте мне показать вам еще несколько весьма полезных встроенных функций.

«Макс» возвращает максимальное значение из последовательности чисел. Вот почему «Макс» вернул значение 30 в качестве вывода в этой ячейке. Хорошо.

«Мин» делает прямо противоположное - возвращает наименьшее значение из последовательности. Итак, мы получаем 10 в этой ячейке вот здесь - это наименьшее из 10, 20 и 30.

Другая встроенная функция «Abs» позволяет получить абсолютное значение ее аргумента.

Пусть «z» будет равно минус 20. Если мы применим функцию «abs» к «z», результатом будет его абсолютное значение 20. Видите?

Важная функция, которая может вам очень помочь, - это «сумма». Он вычислит сумму всех элементов в списке, обозначенном как аргумент. Рассмотрим следующий список, состоящий из 1, 2, 3 и 4, как его данные. Когда я набираю «список сумм 1», мой результат будет равен 1 плюс 2 плюс 3 плюс 4.Сумма этих чисел равна 10.

«Round» возвращает значение аргумента с плавающей запятой, округленное до указанного числа цифр после десятичной точки. «Округление» 3,555 с двумя цифрами после запятой превратится в 3,56.

Если количество цифр не указано, по умолчанию оно равно нулю. 3,2 округляется до 3,0. Большой!

Если вы хотите возвести 2 в степень 10, вы знаете, что можете набрать «2 двойная звезда 10».Вы можете получить тот же результат, если используете функцию «pow», что означает «мощность». Напишите «pow», а в «круглых скобках» укажите основание и степень, разделенные запятой. В нашем случае «2 запятая 10». Выполните с помощью «Shift и Enter» и… вуаля! 1024!

А что, если вы хотите увидеть, сколько элементов в объекте? Функция «Len», как и «length», поможет вам в этом. Если вы выберете строку в качестве аргумента, функция «Len» сообщит вам, сколько символов содержится в слове.Например, в слове «Математика» 11 знаков.

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

Хорошо, на этом мы завершаем нашу статью, в которой мы познакомили вас с некоторыми основными (но очень важными!) Функциями Python. Чтобы продолжить свое путешествие по Python, почему бы не ознакомиться с нашим руководством о том, как работать со списками в Python? Если вы с энтузиазмом относитесь к расширению своих знаний о Python, перейдите к нашим супер-практическим руководствам.В некоторых упражнениях для проверки своих навыков попробуйте свои силы в следующем: Функции, содержащие несколько аргументов, Комбинирование операторов и функций, Комбинирование условных операторов и функций, Использование функции в другой функции.

функций Python - работа с функциями в Python

СОДЕРЖАНИЕ
Предыдущий
Следующий

последнее изменение 6 июля 2020 г.

В этой части руководства по программированию на Python мы рассмотрим функции на Python.

Определение функции Python

Функция - это блок многократно используемого кода, который используется для выполнения
конкретное действие.Преимущества использования функций:

  • Уменьшение дублирования кода
  • Разложение сложных проблем на более простые
  • Повышение четкости кода
  • Повторное использование кода
  • Скрытие информации

Функции в Python - первоклассные граждане. Это означает, что функции имеют равные
статус с другими объектами в Python. Функции могут быть присвоены переменным,
хранятся в коллекциях или передаются как аргументы.Это дает дополнительную гибкость
к языку.

Типы функций Python

Есть два основных типа функций: встроенные функции и пользовательские.
определенные функции. Встроенные функции являются частью языка Python;
например dir () , len () или abs () .
Пользовательские функции - это функции, созданные с помощью ключевого слова def .

Python, создающий функции

Функция создается с ключевым словом def
Операторы в блоке функции должны иметь отступ.

функция def ():
    проходить
 

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

Эта функция позже выполняется, когда это необходимо. Мы говорим, что вызывает функцию .
Если мы вызываем функцию, выполняются инструкции внутри тела функции.
Они не выполняются до тех пор, пока не будет вызвана функция.

myfunc ()
 

Чтобы вызвать функцию, мы указываем имя функции в круглых скобках.

рет.пи

#! / usr / bin / env python

"" "
Скрипт ret.py показывает, как работать с
функции в Python.
Автор: Ян Боднар
ZetCode, 2019
"" "


def show_module_name ():

    печать (__ doc__)


def get_module_file ():

    вернуть __file__


a = имя_показа_модуля ()
б = get_module_file ()

печать (а, б)
 

Строка в верхней части скрипта называется строкой документации.Он документирует текущий сценарий. Файл, в который мы помещаем код Python
называется модулем .

Мы определяем две функции. Первая функция печатает документацию модуля
нить. Второй возвращает путь к модулю. Функция может или
не может возвращать значение. Если функция не возвращает значение, она
неявно возвращает Нет . Модель __doc__
и __file__ - специальные атрибуты состояния.
Обратите внимание, что с обеих сторон атрибута есть два символа подчеркивания.

$ ./ret.py

Скрипт ret.py показывает, как работать с
функции в Python.
Автор: Ян Боднар
ZetCode, 2019

Нет C: /Users/Jano/PycharmProjects/Simple/simple.py
 

Это результат работы программы.

Определения функций должны предшествовать их использованию. В противном случае
Интерпретатор выдаст ошибку NameError .

func_prec.py

#! / usr / bin / env python

# func_prec.py


def f1 ():
    print ("f1 ()")


f1 ()
# f2 ()


def f2 ():
    print ("f2 ()")
 

В приведенном выше примере у нас есть два определения функций.Прокомментирована одна строка. Вызов функции не может опережать
определение.

# f2 ()


def f2 ():
    print ("f2 ()")
 

Мы можем назвать f2 () только после его определения. Раскомментировать
в строке мы получаем NameError .

Где определять функции

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

defining.py

#! / usr / bin / env python

# определение.ру


class Some ():

    @staticmethod
    def f ():
        print ("метод f ()")


def f ():
    print ("функция f ()")


def g ():
    def f ():
        print ("внутренняя функция f ()")
    f ()


Some.f ()
f ()
грамм()
 

В этом примере мы определяем функцию f () в трех разных
места.

# defining.py

class Some ():

    @staticmethod
    def f ():
        print ("метод f ()")
 

Статический метод определяется с помощью декоратора в классе Some .

def f ():
    print ("функция f ()")
 

Функция определена в модуле.

def g ():
    def f ():
        print ("внутренняя функция f ()")
    f ()
 

Здесь функция f () определена внутри другого g ()
функция. Это внутренняя функция.

Some.f ()
f ()
грамм()
 

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

$ ./defining.py
f () метод
f () функция
f () внутренняя функция
 

Это результат.

Функции Python являются объектами

Функции в Python - это объекты. Ими можно манипулировать, как и другими объектами.
в Python. Поэтому функции называются первоклассными гражданами. Это не
true для других языков ООП, таких как Java или C #.

fun_obj.py

#! / usr / bin / env python

# fun_obj.py


def f ():
    "" "Эта функция печатает сообщение" ""

    print («Сегодня пасмурный день»)


print (isinstance (f, объект))
печать (id (f))

печать (f.__doc__)
print (f .__ name__)
 

В этом скрипте мы показываем, что наша функция тоже является объектом.

def f ():
    "" "Эта функция печатает сообщение" ""

    print («Сегодня пасмурный день»)
 

Мы определяем функцию f () . Он выводит сообщение на консоль. Это также
имеет строку документации.

print (isinstance (f, объект))
 

Функция isinstance () проверяет, работает ли функция f ()
является экземпляром объекта .Все объекты в Python наследуются
из этой базовой сущности.

печать (id (f))
 

Каждый объект в Python имеет уникальный идентификатор. Функция id () возвращает
идентификатор объекта.

печать (f .__ doc__)
print (f .__ name__)
 

Объекты могут иметь атрибуты; печатаем два атрибута функции: __doc__
и __name__ .

$ ./fun_obj.py
Правда
140353774014536
Эта функция печатает сообщение
ж
 

Это результат работы программы.

Функции можно хранить в коллекциях и передавать другим функциям.

fun_coll.py

#! / usr / bin / env python

# fun_coll.py


def f ():
    проходить


def g ():
    проходить


def h (f):
    печать (id (f))


а = (е, г, з)

для я в:
    печать (я)

h (f)
ч (г)
 

Мы определяем три функции. Мы помещаем их в кортеж и передаем функции.

а = (е, г, з)

для я в:
    печать (я)
 

Мы помещаем три функциональных объекта в кортеж и просматриваем его с помощью цикла for.

h (f)
ч (г)
 

Мы передаем функции f () и g () в
ч () функция.

$ ./fun_coll.py
<функция f в 0x0000015B998E9D08>
<функция g в 0x0000015B998E9E18>
<функция h в 0x0000015B998E9840>
14

2 14

4

Это результат работы программы fun_coll.py .

Три вида функций в Python

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

three_kinds.py

#! / usr / bin / env python

из математического импорта sqrt


def cube (x):
    вернуть x * x * x


печать (абс (-1))
печать (куб (9))
печать (sqrt (81))
 

В приведенном выше коде присутствуют три вида функций.

из математического импорта sqrt
 

Функция sqrt () импортируется из математического модуля.

def cube (x):
    вернуть x * x * x
 

Функция cube () - это функция, определяемая пользователем.

печать (абс (-1))
 

Функция abs () является встроенной функцией.
доступный. Это часть ядра языка.

Ключевое слово возврата Python

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

Return.py

#! / usr / bin / env python

# return.py


def show_message (сообщение):
    печать (сообщение)


def cube (x):
    вернуть x * x * x


х = куб (3)
печать (х)

show_message ("Вычисление завершено.")
print (show_message ("Готово."))
 

У нас есть две определенные функции. Один использует возврат
ключевое слово, другое - нет.

def show_message (сообщение):
    печать (сообщение)
 

Функция show_message () не возвращает значение явно.Это
показывает сообщение на консоли.

def cube (x):
    вернуть x * x * x
 

Функции cube () вычисляют выражение и возвращают его результат.
с ключевым словом return .

х = куб (3)
 

В этой строке мы вызываем функцию cube () . Результат
вычисление функции cube () возвращается и назначается
в переменную x . Теперь он содержит значение результата.

show_message ("Вычисление завершено.")
 

Мы вызываем функцию show_message () с сообщением в качестве параметра.
Сообщение выводится на консоль. Мы не ожидаем выгоды от
эта функция.

print (show_message ("Готово."))
 

Этот код создает две строки. Один - это сообщение, напечатанное функцией show_message () .
функция. Другой - это значение None , которое неявно отправляется.
функциями без оператора return .

$. / возврат.ру
27
Расчет закончен.
Готовый.
Никто
 

Это пример вывода.

Мы можем отправить более одного значения из функции. Объекты после
Ключевое слово return разделено запятыми.

Return2.py

#! / usr / bin / env python

# return2.py

n = [1, 2, 3, 4, 5]


def stats (x):

    _mx = макс (х)
    _mn = min (x)
    _ln = len (x)
    _sm = сумма (х)

    возврат _mx, _mn, _ln, _sm


mx, mn, ln, sm = статистика (n)
печать (статистика (n))

печать (mx, mn, ln, sm)
 

Есть определение функции stats () .Эта функция
возвращает четыре значения.

возврат _mx, _mn, _ln, _sm
 

Ключевое слово return возвращает четыре числа. В
числа разделены запятой. Фактически мы отправили
кортеж, содержащий эти четыре значения. Мы также можем вернуть список
вместо кортежа.

mx, mn, ln, sm = статистика (n)
 

Возвращенные значения присваиваются локальным переменным.

$ ./returning2.py
(5, 1, 5, 15)
5 1 5 15
 

Это результат.

Переопределение функции Python

Python по своей природе динамичен. Можно переопределить уже
определенная функция.

redefinition.py

#! / usr / bin / env python

# redefinition.py

from time import gmtime, strftime


def show_message (сообщение):
    печать (сообщение)


show_message ("Готово.")


def show_message (сообщение):
    print (strftime ("% H:% M:% S", gmtime ()))
    печать (сообщение)


show_message ("Обработка.")
 

Мы определяем функцию show_message () .Позже мы представим новый
определение той же функции.

from time import gmtime, strftime
 

Из модуля времени мы импортируем две функции, которые используются для
вычислить текущее время.

def show_message (сообщение):
    печать (сообщение)
 

Это первое определение функции. Он только печатает сообщение
к консоли.

def show_message (сообщение):
    print (strftime ("% H:% M:% S", gmtime ()))
    печать (сообщение)
 

Позже в исходном коде мы установили новое определение showMessage () .
функция.Сообщению предшествует отметка времени.

$ ./redefinition.py
Готовый.
23:49:33 Обработка.
 

Это результат.

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

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

fahrenheit.py

#! / usr / bin / env python

# fahrenheit.py


def C2F (c):
    возврат c * 9/5 + 32


печать (C2F (100))
печать (C2F (0))
печать (C2F (30))
 

В нашем примере мы переводим температуру по Цельсию в градусы Фаренгейта.Функция C2F () принимает один аргумент c, который является
Температура по Цельсию.

$ ./fahrenheit.py
212
32
86
 

Аргументы в функциях Python могут иметь неявные значения. Неявный
значение используется, если значение не указано.

fun_implicit.py

#! / usr / bin / env python

# fun_implicit.py


def power (x, y = 2):

    г = 1

    для i в диапазоне (y):
        г = г * х

    вернуть г


печать (мощность (3))
печать (мощность (3, 3))
печать (мощность (5, 5))
 

Здесь мы создали степенную функцию.Функция имеет один аргумент с
неявное значение. Мы можем вызвать функцию с помощью
один или два аргумента.

$ ./fun_implicit.py
9
27
3125
 

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

fun_keywords.py

#! / usr / bin / env python

# fun_keywords.py

def display (имя, возраст, пол):

    print ("Имя:", имя)
    print ("Возраст:", возраст)
    print ("Секс:", секс)


дисплей («Лары», 43, «М»)
дисплей («Жанна», 24, «Ж»)
 

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

$ ./fun_keywords.py
Имя: Лари
Возраст: 43 года
Пол: M
Имя: Джоан
Возраст: 24 года
Пол: Ж
 

fun_keywords2.py

#! / usr / bin / env python

# fun_keywords2.py


def display (имя, возраст, пол):

    print ("Имя:", имя)
    print ("Возраст:", возраст)
    print ("Секс:", секс)


дисплей (возраст = 43, name = "Lary", sex = "M")
display (name = "Joan", age = 24, sex = "F")
 

Теперь мы вызываем функции по их ключевым словам. Порядок может быть изменен,
хотя делать это не рекомендуется. Обратите внимание, что мы не можем использовать не ключевое слово
аргумент после аргумента ключевого слова. Это закончится синтаксической ошибкой.

display ("Joan", sex = "F", age = 24)
 

Это законная конструкция.Аргумент без ключевого слова может быть
за которым следуют аргументы ключевого слова.

display (age = 24, name = "Joan", "F")
 

Это закончится синтаксической ошибкой. Аргумент без ключевого слова
может не следовать за аргументами ключевого слова.

Функции в Python могут принимать произвольное количество аргументов.

random_args.py

#! / usr / bin / env python

# random_args.py


def do_sum (* аргументы):
    "" "Функция возвращает сумму
всех значений "" "

    г = 0

    для i в аргументах:
        г + = я

    вернуть г


печать (do_sum.__doc__)
печать (do_sum (1, 2, 3))
печать (do_sum (1, 2, 3, 4, 5))
 

Мы используем оператор * , чтобы указать, что функция принимает
произвольное количество аргументов. Функция do_sum () возвращает
сумма всех аргументов. Первая строка в теле функции называется
строка документации функции. Он используется для документирования функции.
Строка должна быть заключена в тройные кавычки.

$ ./arbitrary_args.py
Функция возвращает сумму
всех ценностей
6
15
 

Мы также можем использовать конструкцию ** в наших функциях.В таком случае,
функция примет словарь. Словарь имеет произвольную длину. Мы
затем может нормально проанализировать словарь, как обычно.

details.py

#! / usr / bin / env python

# details.py


def display (** подробности):

    для i в деталях:
        print (f "{i}: {подробности [i]}")


display (name = "Larry", age = 43, sex = "M")
 

Этот пример демонстрирует такой случай. Мы можем предоставить произвольное количество
аргументы ключ-значение. Функция обработает их все.

$./details.py
возраст: 43
имя: Ларри
пол: M
 

Python передает параметры по ссылке

Параметры в функции передаются по ссылке.
Некоторые языки передают копии объектов функциям.
Передача объектов по ссылке позволяет сделать два важных вывода:
а) процесс идет быстрее, чем если бы были переданы копии объектов;
б) изменяемые объекты, которые изменяются в функциях, навсегда
измененный.

pass_by_reference.py

#! / usr / bin / env python

# pass_by_reference.ру

n = [1, 2, 3, 4, 5]

print ("Исходный список:", n)


def f (x):

    x.pop ()
    x.pop ()
    x.insert (0, 0)
    print ("Внутри f ():", x)


f (n)

print ("После вызова функции:", n)
 

В нашем примере мы передаем в функцию список целых чисел. В
объект модифицируется внутри тела функции. После
вызов функции, исходного объекта, списка целых чисел
модифицирован.

def f (x):

    x.pop ()
    x.pop ()
    x.insert (0, 0)
    print ("Внутри f ():", x)
 

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

$ ./passing_by_reference.py
Исходный список: [1, 2, 3, 4, 5]
Внутри f (): [0, 1, 2, 3]
После вызова функции: [0, 1, 2, 3]
 

После того, как список был изменен, он был изменен навсегда.

Глобальные и локальные переменные Python

Далее мы поговорим о том, как переменные используются в функциях Python.

local_variable.py

#! / usr / bin / env python

# local_variable.ру

name = "Джек"


def f ():
    name = "Роберт"
    print ("Внутри функции", имя)


print ("Внешняя функция", имя)
f ()
 

Переменная, определенная в теле функции, имеет локальную область видимости . это
действует только в теле функции.

$ ./local_variable.py
Внешняя функция Джек
В рамках функции Роберт
 

Это пример вывода.

global_variable.py

#! / usr / bin / env python

# global_variable.py

name = "Джек"


def f ():
    print ("Внутри функции", имя)


print ("Внешняя функция", имя)
f ()
 

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

$ ./global_variable.py
Внешняя функция Джек
Внутри функции Джек
 

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

global_variable2.py

#! / usr / bin / env python

# global_variable2.py

name = "Джек"


def f ():

    глобальное имя
    name = "Роберт"
    print ("Внутри функции", имя)


print ("Внешняя функция", имя)
f ()
print ("Внешняя функция", имя)
 

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

глобальное имя
name = "Роберт"
 

Используя ключевое слово global , мы ссылаемся на переменную
определены вне тела функции. Переменной присваивается
новое значение.

$ ./global_variable2.py
Внешняя функция Джек
В рамках функции Роберт
Вне функции Роберт
 

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

В Python можно создавать анонимные функции. Анонимный
функции не имеют имени. С ключевым словом lambda ,
могут быть созданы небольшие анонимные функции.Анонимные функции
программисты Python также называют лямбда-функциями. Они часть
функциональной парадигмы, заложенной в Python.

Лямбда-функции ограничены одним выражением. Они
можно использовать везде, где можно использовать обычные функции. Существует
Лямбда-функции Python
учебник по ZetCode.

lambda_fun.py

#! / usr / bin / env python

# lambda_fun.py

у = 6

z = лямбда x: x * y
печать (z (8))
 

Это небольшой пример лямбда-функции.

z = лямбда x: x * y
 

Ключевое слово lambda создает анонимную функцию. Размер x
- параметр, который передается лямбда-функции. Параметр
за которым следует символ двоеточия. Код рядом с двоеточием:
выражение, которое выполняется при вызове лямбда-функции.
Лямбда-функция назначается переменной z .

печать (z (8))
 

Лямбда-функция выполняется. Число 8 передается анонимному
функция и возвращает 48 в качестве результата.Обратите внимание, что z не
имя для этой функции. Это только переменная, к которой анонимная функция
был назначен.

$ ./lambda_fun.py
48
 

Это результат примера.

Лямбда-функцию можно элегантно использовать с другими функциями.
части языка Python, например map () или filter ()
функции.

lambda_fun2.py

#! / usr / bin / env python

# lambda_fun2.py

cs = [-10, 0, 15, 30, 40]

ft = map (лямбда t: (9.0/5) * t + 32, cs)
печать (список (футы))
 

В этом примере у нас есть список температур по Цельсию. Создаем новый
список, содержащий температуры в градусах Фаренгейта.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *