Содержание

Функции в программировании. Курс «Python. Введение в программирование»

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

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

Существует множество встроенных в язык программирования функций. С некоторыми такими в Python мы уже сталкивались. Это print(), input(), int(), float(), str(), type(). Код их тела нам не виден, он где-то «спрятан внутри языка». Нам же предоставляется только интерфейс – имя функции.

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

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

i = 0
while i < 3:
    a = int(input())
    b = int(input())
    print(a+b)
    i += 1

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

print("Сколько бананов и ананасов для обезьян?")
a = int(input())
b = int(input())
print("Всего", a+b, "шт.
")   print("Сколько жуков и червей для ежей?") a = int(input()) b = int(input()) print("Всего", a+b, "шт.")   print("Сколько рыб и моллюсков для выдр?") a = int(input()) b = int(input()) print("Всего", a+b, "шт.")

Пример исполнения программы:

Сколько бананов и ананасов для обезьян?
15
5
Всего 20 шт.
Сколько жуков и червей для ежей?
50
12
Всего 62 шт.
Сколько рыб и моллюсков для выдр?
16
8
Всего 24 шт.

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

Определение функции. Оператор def

В языке программирования Python функции определяются с помощью оператора def. Рассмотрим код:

def countFood():
    a = int(input())
    b = int(input())
    print("Всего", a+b, "шт.")

Это пример определения функции. Как и другие сложные инструкции вроде условного оператора и циклов функция состоит из заголовка и тела. Заголовок оканчивается двоеточием и переходом на новую строку. Тело имеет отступ.

Ключевое слово def сообщает интерпретатору, что перед ним определение функции. За def следует имя функции. Оно может быть любым, также как и всякий идентификатор, например, переменная. В программировании весьма желательно давать всему осмысленные имена. Так в данном случае функция названа «посчитатьЕду» в переводе на русский.

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

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

Вызов функции

Рассмотрим полную версию программы с функцией:

def countFood():
    a = int(input())
    b = int(input())
    print("Всего", a+b, "шт.")
 
print("Сколько бананов и ананасов для обезьян?")
countFood()
 
print("Сколько жуков и червей для ежей?")
countFood()
 
print("Сколько рыб и моллюсков для выдр?")
countFood()

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

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

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

NameError):

print("Сколько бананов и ананасов для обезьян?")
countFood()
 
print("Сколько жуков и червей для ежей?")
countFood()
 
print("Сколько рыб и моллюсков для выдр?")
countFood()
 
def countFood():
    a = int(input())
    b = int(input())
    print("Всего", a+b, "шт.")

Результат:

Сколько бананов и ананасов для обезьян?
Traceback (most recent call last):
  File "test.py", line 2, in <module>
    countFood()
NameError: name 'countFood' is not defined

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

Функции придают программе структуру

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

Пусть надо написать программу, вычисляющую площади разных фигур. Пользователь указывает, площадь какой фигуры он хочет вычислить. После этого вводит исходные данные. Например, длину и ширину в случае прямоугольника. Чтобы разделить поток выполнения на несколько ветвей, следует использовать оператор if-elif-else:

figure = input("1-прямоугольник, 
2-треугольник, 3-круг: ")
 
if figure == '1':
  a = float(input("Ширина: "))
  b = float(input("Высота: "))
  print("Площадь: %.2f" % (a*b))
elif figure == '2':
  a = float(input("Основание: "))
  h = float(input("Высота: "))
  print("Площадь: %.2f" % (0.5 * a * h))
elif figure == '3':
  r = float(input("Радиус: "))
  print("Площадь: %.
2f" % (3.14 * r**2)) else: print("Ошибка ввода")

Здесь нет никаких функций, и все прекрасно. Но напишем вариант с функциями:

def rectangle():
    a = float(input("Ширина: "))
    b = float(input("Высота: "))
    print("Площадь: %.2f" % (a*b))
 
def triangle():
    a = float(input("Основание: "))
    h = float(input("Высота: "))
    print("Площадь: %.2f" % (0.5 * a * h))
 
def circle():
    r = float(input("Радиус: "))
    print("Площадь: %.2f" % (3.14 * r**2))
 
figure = input("1-прямоугольник, 
2-треугольник, 3-круг: ")
if figure == '1':
  rectangle()
elif figure == '2':
  triangle()
elif figure == '3':
  circle()
else:
  print("Ошибка ввода")

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

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

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

Практическая работа

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

Основная ветка программы, не считая заголовков функций, состоит из одной строки кода. Это вызов функции test(). В ней запрашивается на ввод целое число. Если оно положительное, то вызывается функция positive(), тело которой содержит команду вывода на экран слова «Положительное». Если число отрицательное, то вызывается функция negative(), ее тело содержит выражение вывода на экран слова «Отрицательное».

Понятно, что вызов test() должен следовать после определения функций. Однако имеет ли значение порядок определения самих функций? То есть должны ли определения positive() и negative() предшествовать test() или могут следовать после него? Проверьте вашу гипотезу, поменяв объявления функций местами. Попробуйте объяснить результат.

Примеры решения и дополнительные уроки в android-приложении и pdf-версии курса

Использование функций в 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. Часть 8. Функции

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

Видео: Глеб Лиманский

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

Если бы такой функции в Python не существовало, то мы бы могли написать что-то вроде такого кода:

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

Подписывайтесь на рассылку «Мастерской»

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

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

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

Вот так почти всегда будет выглядеть функция.

Но она не всегда должна что-то принимать на вход или что-то возвращать. Вот пример функции, которая просто здоровается — распечатывает «Hi!», но не принимает аргументов и ничего не возвращает. И если напишете print(say_hi()), то в ответе вы увидите None.

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

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

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

По умолчанию мы назначили small_talk = «Как дела?». Когда мы будем вызывать функцию, нам не нужно указывать этот аргумент, он уже есть по умолчанию. Нам нужно лишь передать имя, дальше функция сама спросит пользователя «Как дела?».

Отдельно указывать аргумент small_talk при вывозе функции нужно только тогда, когда мы хотим внести в него какие-то изменения. Например, мы хотим, чтобы вместо «Как дела?» функция спросила что-то другое.

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

Допустим, наши данные у нас хранятся в виде подобного словаря — phone_book = {‘Alice’: ‘8-987-657 12 11’, ‘Bob’:’89012345678′, ‘Jack’:’8 (9 1 2) 3 4 5 6 7 8 9′}. Ключами тут являются имена, а значениями — телефоны, которые написаны по-разному: с пробелами, дефисами, скобками. Нам нужно к каждому из этих номеров приметь функцию clean_tel().

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

Такой список можно будет легко сохранить в табличку.

Анонимная функция

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

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

А вот как она выглядит, если переписать ее с помощью lambda.

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

Лямбда-функцию не обязательно как-то называть. Ее можно вызвать и без имени. Нужно поместить функцию в скобки. И рядом же в скобках указать аргументы.

Кстати, и нашу функцию say_hi() тоже можно переписать с помощью lambda.

Это все основные принципы работы функций в Python. Если вы хотите прочитать о дополнительных возможностях функций, можете сделать это здесь. И, как всегда, тетрадка Jupyter Notebook с этого урока лежит на нашем GitHub.

Функции в Python | Кодкамп

Введение

Примеры

Определение и вызов простых функций

Использование def утверждения является наиболее распространенным способом определить функцию в Python. Это утверждение так называемое соединение заявление одного пункта со следующим синтаксисом:

def function_name(parameters):
    statement(s)

 

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

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

statement(s) — также известное как тело функции — это непустое последовательность операторов , выполняемых при каждом вызове функции. Это означает , что тело функции не может быть пустым, так же как и любой отступом блок .

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

def greet():
    print("Hello")

 

Теперь давайте называть определенные greet() функции:

greet()
# Out: Hello

 

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

def greet_two(greeting):
    print(greeting)

 

После того, что greet_two() функция должна быть вызвана с аргументом:

greet_two("Howdy")
# Out: Howdy

 

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

 def greet_two(greeting="Howdy"):
    print(greeting)
 

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

 greet_two()
# Out: Howdy 

 

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

def many_types(x):
    if x < 0:
        return "Hello!"
    else:
        return 0

print(many_types(1))
print(many_types(-1))

# Output:
0
Hello!

 

Пока это правильно обрабатывается вызывающей стороной, это совершенно правильный код Python.

Функция , которая достигает конца исполнения без оператора возврата всегда будет возвращать None :

def do_nothing():
    pass

print(do_nothing())
# Out: None

 

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

Возвращение значений из функций

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

def give_me_five():
    return 5

print(give_me_five())  # Print the returned value
# Out: 5

 

или сохраните значение для последующего использования:

num = give_me_five()
print(num)             # Print the saved returned value
# Out: 5

 

или используйте значение для любых операций:

print(give_me_five() + 10)
# Out: 15

 

Если return встречается в функции функция будет немедленно вышла и последующие операции не будут оцениваться:

def give_me_another_five():
    return 5
    print('This statement will not be printed. Ever.')

print(give_me_another_five())
# Out: 5

 

Вы также можете return несколько значений (в виде кортежа):

def give_me_two_fives():
    return 5, 5  # Returns two 5

first, second = give_me_two_fives()
print(first)
# Out: 5
print(second)
# Out: 5

 

Функция, без return заявления неявно возвращает None . Точно так же функция с return утверждением, но не возвращает значение или переменная возвращает None .

Определение функции с аргументами

Аргументы определены в скобках после имени функции:

 def divide(dividend, divisor):  # The names of the function and its arguments
    # The arguments are available by name in the body of the function
    print(dividend / divisor)

 

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

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

divide(10, 2)
# output: 5

 

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

divide(divisor=2, dividend=10)
# output: 5 

Определение функции с необязательными аргументами

Дополнительные аргументы могут быть определены путем назначения ( с использованием = ) значение по умолчанию имя-аргумента:

def make(action='nothing'):
    return action

 

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

make("fun")
# Out: fun

make(action="sleep")
# Out: sleep

# The argument is optional so the function will use the default value if the argument is 
# not passed in. 
make()   
# Out: nothing

 

Изменяемые типы ( list , dict , set и т.д.) , следует относиться с осторожностью , когда дается как атрибут по умолчанию. Любая мутация аргумента по умолчанию изменит его навсегда. См Определение функции с дополнительными изменяемыми аргументами .

Определение функции с несколькими аргументами

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

def func(value1, value2, optionalvalue=10):
    return '{0} {1} {2}'.format(value1, value2, optionalvalue1)

 

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

print(func(1, 'a', 100))
# Out: 1 a 100

print(func('abc', 14))
# abc 14 10

 

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

 print(func('This', optionalvalue='StackOverflow Documentation', value2='is'))
# Out: This is StackOverflow Documentation 

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

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

def func(*args):
    # args will be a tuple containing all values that are passed in
    for i in args:
        print(i)

func(1, 2, 3)  # Calling it with 3 arguments
# Out: 1
#      2
#      3

list_of_arg_values = [1, 2, 3]
func(*list_of_arg_values)  # Calling it with list of values, * expands the list
# Out: 1
#      2
#      3 

func()  # Calling it without arguments
# No Output 

 

Вы не можете предоставить по умолчанию для args , например func(*args=[1, 2, 3]) поднимет синтаксическую ошибку (даже не компилировать).

Вы не можете обеспечить их по имени при вызове функции, например func(*args=[1, 2, 3]) поднимет TypeError .

Но если у вас уже есть свои аргументы в массиве (или любой другой Iterable ), вы можете вызвать вашу функцию следующим образом: func(*my_stuff) .

Эти аргументы ( *args ) можно обращаться по индексу, например , args[0] возвращает первый аргумент

Вы можете принимать произвольное число аргументов с именем, определяя аргумент в определении с двумя * перед ним:

def func(**kwargs):
    # kwargs will be a dictionary containing the names as keys and the values as values
    for name, value in kwargs.items():
        print(name, value)

func(value1=1, value2=2, value3=3)   # Calling it with 3 arguments
# Out: value1 1
#      value2 2
#      value3 3

func()                               # Calling it without arguments
# No Out put

my_dict = {'foo': 1, 'bar': 2}
func(**my_dict)                      # Calling it with a dictionary
# Out: foo 1
#      bar 2

 

Вы не можете предоставить это без имен, например func(1, 2, 3) поднимет TypeError .

kwargs это простой родной словарь питона. Например, args['value1'] даст значение аргумента value1 . Обязательно проверьте заранее , что есть такой аргумент или KeyError будет поднят.

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

Позиционные / ключевые аргументы приходят в первую очередь. (Обязательные аргументы).   Тогда приходит произвольные *arg аргументы. (Необязательный).   Тогда ключевые слова только аргументы приходят дальше. (Необходимые).   Наконец произвольные ключевое слово **kwargs приходят. (Необязательный).

 #       |-positional-|-optional-|---keyword-only--|-optional-|
def func(arg1, arg2=10 , *args, kwarg1, kwarg2=2, **kwargs):
     pass

 
  • arg1 должен быть задан, в противном случае TypeError поднимается. Это может быть задано как позиционный ( func(10) ) или ключевым словом аргумента ( func(arg1=10) ).
  • kwarg1 также должен быть предоставлен, но она может быть обеспечена только в качестве ключевого слова-аргумента: func(kwarg1=10) .
  • arg2 и kwarg2 не являются обязательными. Если значение должно быть изменено тем же правилам , как и для arg1 (либо позиционной или ключевое слово) и kwarg1 (только ключевое слово) применяются.
  • *args уловы дополнительные позиционные параметры. Но обратите внимание, что arg1 и arg2 должны быть предоставлены в качестве позиционных аргументов передать аргументы *args : func(1, 1, 1, 1) .
  • **kwargs перехватывает все дополнительные параметры ключевых слов. В этом случае любой параметр , который не arg1 , arg2 , kwarg1 или kwarg2 . Например: func(kwarg3=10) .
  • В Python 3, вы можете использовать * в покое , чтобы указать , что все последующие аргументы должны быть указаны в качестве ключевых слов. Для экземпляра math.isclose функции в Python 3.5 и выше , определяется с использованием def math.isclose (a, b, *, rel_tol=1e-09, abs_tol=0.0) , что означает , что первые два аргумента могут быть поставлены позиционно , но по желанию третий и четвертый параметры могут быть предоставлены только как ключевые аргументы.

Python 2.x не поддерживает параметры только для ключевых слов. Такое поведение можно эмулировать с kwargs :

def func(arg1, arg2=10, **kwargs):
    try:
        kwarg1 = kwargs.pop("kwarg1")
    except KeyError:
        raise TypeError("missing required keyword-only argument: 'kwarg1'")

    kwarg2 = kwargs.pop("kwarg2", 2)
    # function body ...

 

Примечание по именованию

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

Обратите внимание на уникальность

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

Замечание о функциях вложения с необязательными аргументами

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

def fn(**kwargs):
    print(kwargs)
    f1(**kwargs)

def f1(**kwargs):
    print(len(kwargs))

fn(a=1, b=2)
# Out:
# {'a': 1, 'b': 2}
# 2 

Определение функции с необязательными изменяемыми аргументами

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

объяснение

Эта проблема возникает из — за аргументов функции по умолчанию инициализируются один раз, в тот момент , когда функция определена, а не (как и многие другие языки) , когда функция вызывается. Значения по умолчанию сохраняется в функции объект __defaults__ переменного члена.

def f(a, b=42, c=[]):
    pass

print(f.__defaults__)
# Out: (42, [])

 

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

def append(elem, to=[]):
    to.append(elem)      # This call to append() mutates the default variable "to"
    return to

append(1)
# Out: [1]

append(2)  # Appends it to the internally stored list
# Out: [1, 2]

append(3, [])  # Using a new created list gives the expected result
# Out: [3]

# Calling it again without argument will append to the internally stored list again
append(4)   
# Out: [1, 2, 4]

 

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

Решение

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

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

def append(elem, to=None):
    if to is None:
        to = []

    to.append(elem)
    return to

 

Лямбда (встроенные / анонимные) функции

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

Рассмотрим функцию:

def greeting():
    return "Hello"

 

который, когда называется как:

print(greeting())

 

печатает:

Hello


 

Это можно записать в виде лямбда-функции следующим образом:

greet_me = lambda: "Hello"

 

Это создает встраиваемую функцию с именем greet_me , который возвращает Hello . Обратите внимание , что вы не пишете return при создании функции с лямбда. Значение после : автоматически возвращается.

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

print(greet_me())

 

печатает:

Hello

 

lambda — s может принимать аргументы, тоже:

strip_and_upper_case = lambda s: s.strip().upper()

strip_and_upper_case("  Hello   ")

 

возвращает строку:

HELLO

 

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

greeting = lambda x, *args, **kwargs: print(x, args, kwargs)
greeting('hello', 'world', world='world')

 

печатает:

hello ('world',) {'world': 'world'}

 

lambda — ы обычно используются для коротких функций, которые удобно определить в точке , где они называются ( как правило , с sorted , filter и map ).

Например, эта строка сортирует список строк, игнорируя их регистр и игнорируя пробелы в начале и в конце:

sorted( [" foo ", "    bAR", "BaZ    "], key=lambda s: s.strip().upper())
# Out:
# ['    bAR', 'BaZ    ', ' foo ']

 

Список сортировки просто игнорируя пробелы:

sorted( [" foo ", "    bAR", "BaZ    "], key=lambda s: s.strip())
# Out:
# ['BaZ    ', '    bAR', ' foo ']

 

Примеры с map :

sorted( map( lambda s: s.strip().upper(), [" foo ", "    bAR", "BaZ    "]))
# Out:
# ['BAR', 'BAZ', 'FOO']

sorted( map( lambda s: s.strip(), [" foo ", "    bAR", "BaZ    "]))
# Out:
# ['BaZ', 'bAR', 'foo']


 

Примеры с числовыми списками:

my_list = [3, -4, -2, 5, 1, 7]
sorted( my_list, key=lambda x: abs(x))
# Out:
# [1, -2, 3, -4, 5, 7]

list( filter( lambda x: x>0, my_list))
# Out:
# [3, 5, 1, 7]

list( map( lambda x: abs(x), my_list))
# Out:
[3, 4, 2, 5, 1, 7]
 

Другие функции (с / без аргументов) можно вызывать внутри лямбда-функции.

def foo(msg):
    print(msg)

greet = lambda x = "hello world": foo(x)
greet()

 

печатает:

hello world

 

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

НОТА

Следует иметь в виду , что PEP-8 (официальный гид по стилю Python) не рекомендуется назначать лямбды переменным (как мы это делали в первых двух примерах):

Передача аргумента и изменчивость

Сначала немного терминологии:

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

В Python, аргументы передаются по заданию (в отличие от других языков, где аргументы могут передаваться по значению / задания / указателя).

Мутирование параметра приведет к изменению аргумента (если тип аргумента является изменяемым).

def foo(x):        # here x is the parameter
    x[0] = 9       # This mutates the list labelled by both x and y
    print(x)

y = [4, 5, 6]
foo(y)             # call foo with y as argument
# Out: [9, 5, 6]   # list labelled by x has been mutated
print(y)           
# Out: [9, 5, 6]   # list labelled by y has been mutated too 

Переназначение параметра не переназначит аргумент.

def foo(x):        # here x is the parameter, when we call foo(y) we assign y to x
    x[0] = 9       # This mutates the list labelled by both x and y
    x = [1, 2, 3]  # x is now labeling a different list (y is unaffected)
    x[2] = 8       # This mutates x's list, not y's list

y = [4, 5, 6]      # y is the argument, x is the parameter
foo(y)             # Pretend that we wrote "x = y", then go to line 1
y
# Out: [9, 5, 6] 

В Python, мы на самом деле не присваивать значения переменным, вместо того, чтобы мы связываем (то есть переуступать, присоединять) переменные (рассматриваемые как имена) к объектам.

  • Неизменные: Целые, строки, кортежи, и так далее. Все операции делают копии.
  • Mutable: списки, словари, наборы, и так далее. Операции могут или не могут мутировать.
x = [3, 1, 9]
y = x
x.append(5)    # Mutates the list labelled by x and y, both x and y are bound to [3, 1, 9]
x.sort()       # Mutates the list labelled by x and y (in-place sorting)
x = x + [4]    # Does not mutate the list (makes a copy for x only, not y)
z = x          # z is x ([1, 3, 9, 4])
x += [6]       # Mutates the list labelled by both x and z (uses the extend function).
x = sorted(x)  # Does not mutate the list (makes a copy for x only).
x
# Out: [1, 3, 4, 5, 6, 9]
y
# Out: [1, 3, 5, 9]
z
# Out: [1, 3, 5, 9, 4, 6] 

Return

Замыкания в Python создаются вызовами функций. Здесь вызов makeInc создает привязку для x , ссылка внутри функции inc . Каждый вызов makeInc создает новый экземпляр этой функции, но каждый экземпляр имеет ссылку на другую связыванию x .

 def makeInc(x):
  def inc(y):
     # x is "attached" in the definition of inc
     return y + x

  return inc

incOne = makeInc(1)
incFive = makeInc(5)

incOne(5) # returns 6
incFive(5) # returns 10

 

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

 def makeInc(x):
  def inc(y):
     # incrementing x is not allowed
     x += y  
     return x

  return inc

incOne = makeInc(1)
incOne(5) # UnboundLocalError: local variable 'x' referenced before assignment

 

Python 3 предлагает nonlocal заявление ( https://codecamp.ru/documentation/python/263/variable-scope-and-binding/5712/nonlocal-variables#t=201608272008282346874 ) для реализации полного закрытия с вложенными функциями.

def makeInc (x): def inc (y): нелокальный x # теперь можно присвоить значение x x + = y вернуть x return inc incOne = makeInc (1) incOne (5) # возвращает 6

Рекурсивные функции

Рекурсивная функция — это функция, которая вызывает себя в своем определении. Например, математическая функция, факториала, определяется factorial(n) = n*(n-1)*(n-2)*...*3*2*1 . может быть запрограммирован как

def factorial(n):
    #n here should be an integer
    if n == 0:
        return 1
    else:
        return n*factorial(n-1)
 

выходы здесь:

factorial(0)
#out 1
factorial(1)
#out 1
factorial(2)
#out 2
factorial(3)
#out 6

 

как и ожидалось. Обратите внимание , что эта функция является рекурсивной , потому что второй return factorial(n-1) , где функция называет себя в своем определении.

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

factorial = lambda n: 1 if n == 0 else n*factorial(n-1)

 

Функция выводит то же, что и выше.

Предел рекурсии

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

def cursing(depth):
  try:
    cursing(depth + 1) # actually, re-cursing
  except RuntimeError as RE:
    print('I recursed {} times!'.format(depth))

cursing(0)
# Out: I recursed 1083 times! 

Можно изменить рекурсии предел глубины, используя sys.setrecursionlimit(limit) и проверить этот предел sys.getrecursionlimit() .

sys.setrecursionlimit(2000)
cursing(0)
# Out: I recursed 1997 times! 

Из Python 3.5, исключение составляет RecursionError , который является производным от RuntimeError .

Вложенные функции

Функции в Python являются первоклассными объектами. Они могут быть определены в любой области

 def fibonacci(n):
    def step(a,b):
        return b, a+b
    a, b = 0, 1
    for i in range(n):
        a, b = step(a, b)
    return a

 

Функции захвата их охватывающей области видимости могут передаваться как любой другой вид объекта

def make_adder(n):
    def adder(x):
        return n + x
    return adder
add5 = make_adder(5)
add6 = make_adder(6)
add5(10)
#Out: 15
add6(10)
#Out: 16

def repeatedly_apply(func, n, x):
    for i in range(n):
        x = func(x)
    return x

repeatedly_apply(add5, 5, 1)
#Out: 26 

Повторяемая и распаковка словаря

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

def unpacking(a, b, c=45, d=60, *args, **kwargs):
    print(a, b, c, d, args, kwargs)

>>> unpacking(1, 2)
1 2 45 60 () {}
>>> unpacking(1, 2, 3, 4)
1 2 3 4 () {}
>>> unpacking(1, 2, c=3, d=4)
1 2 3 4 () {}
>>> unpacking(1, 2, d=4, c=3)
1 2 3 4 () {}


>>> pair = (3,)
>>> unpacking(1, 2, *pair, d=4)
1 2 3 4 () {}
>>> unpacking(1, 2, d=4, *pair)
1 2 3 4 () {}
>>> unpacking(1, 2, *pair, c=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'
>>> unpacking(1, 2, c=3, *pair)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'

>>> args_list = [3]
>>> unpacking(1, 2, *args_list, d=4)
1 2 3 4 () {}
>>> unpacking(1, 2, d=4, *args_list)
1 2 3 4 () {}
>>> unpacking(1, 2, c=3, *args_list)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'
>>> unpacking(1, 2, *args_list, c=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c'


>>> pair = (3, 4)
>>> unpacking(1, 2, *pair)
1 2 3 4 () {}
>>> unpacking(1, 2, 3, 4, *pair)
1 2 3 4 (3, 4) {}
>>> unpacking(1, 2, d=4, *pair)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
>>> unpacking(1, 2, *pair, d=4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'



>>> args_list = [3, 4]
>>> unpacking(1, 2, *args_list)
1 2 3 4 () {}
>>> unpacking(1, 2, 3, 4, *args_list)
1 2 3 4 (3, 4) {}
>>> unpacking(1, 2, d=4, *args_list)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
>>> unpacking(1, 2, *args_list, d=4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'


>>> arg_dict = {'c':3, 'd':4}
>>> unpacking(1, 2, **arg_dict)
1 2 3 4 () {}
>>> arg_dict = {'d':4, 'c':3}
>>> unpacking(1, 2, **arg_dict)
1 2 3 4 () {}
>>> arg_dict = {'c':3, 'd':4, 'not_a_parameter': 75}
>>> unpacking(1, 2, **arg_dict)
1 2 3 4 () {'not_a_parameter': 75}


>>> unpacking(1, 2, *pair, **arg_dict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'
>>> unpacking(1, 2, 3, 4, **arg_dict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'd'

# Positional arguments take priority over any other form of argument passing
>>> unpacking(1, 2, **arg_dict, c=3)
1 2 3 4 () {'not_a_parameter': 75}
>>> unpacking(1, 2, 3, **arg_dict, c=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unpacking() got multiple values for argument 'c' 

Принудительное использование именованных параметров

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

def f(*a, b):
    pass

f(1, 2, 3)
# TypeError: f() missing 1 required keyword-only argument: 'b'


 

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

def f(a, b, *, c):
    pass

f(1, 2, 3)
# TypeError: f() takes 2 positional arguments but 3 were given
f(1, 2, c=3)
# No error 

Рекурсивная лямбда с использованием присвоенной переменной

Синтаксис

Параметры

Примечания

Функции Python: 7 примеров. Базовые, встроенные и пользовательские функции

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

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

Базовые функции Python

Давайте рассмотрим пример функции Python, принимающей 2 параметра, а также вычисляющей сумму и возвращающей вычисленное значение:

#определяем и объявляем функцию
def calculate_sum(a,b):
  sum = a+b
  return sum

#инструкция, приведённая ниже, называется вызовом функции
print(calculate_sum(2,3)) # 5

Кроме того, в Python есть встроенные и пользовательские функции.

Пользовательские функции Python

Объявление пользовательской функции осуществляется с применением ключевого слова def. При этом оно должно сопровождаться именем пользовательской функции:

def calculate_si_amount(principal, rate, time):
  interest =  (principal*rate*time)/100
  return principal+interest

В данной функции окончательная сумма может быть рассчитана посредством использования простого процента к основной сумме. Именем функции является Calculate_si_amount. Что касается principal, time и rate — то это параметры, а функция возвращает рассчитанные данные.

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

from random import seed, random
from random import random

def generate_random_number():
  seed(10)
  return random()

Встроенные функции Python

В Python существует много встроенных функций. Одна из наиболее часто используемых — print(). Её работа чрезвычайно проста:

print("Всем привет")
print(len("Меня зовут Андрей"))

Ещё популярны такие функции, как len(),abs(), sum(), str(), int() и другие.

Параметры функции в Python

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

def multiply(a, b=10):
  return a*b

multiply(12) # 120
multiply(2, 3) # 6
multiply(b=9) # Ошибка: None*9 недопустимо

В вышеописанной функции, когда пользователь не задает 2-й параметр b, он предполагает, что параметр равен 10, однако при этом нужно предоставить 1-й параметр.

Неизвестное количество параметров в функции Python

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

Когда число параметров неизвестно, тогда в определение функции в качестве одного из параметров добавляется *args. Данный параметр ожидает кортеж. В нашем случае звёздочка (*) очень важна, т. к. название args просто является соглашением, то есть можно дать любое другое имя.

def calculate_sum(a, *args):
  sum = a
  for i in args:
    sum += i
  return sum

calculate_sum(10) # 10
calculate_sum(10, 11, 12) # 33
calculate_sum(1, 2, 94, 6, 2, 8, 9, 20, 43, 2) # 187

Так же **kwargs ожидает словарь в качестве параметра.

def print_names(f1, l1, **kwargs):
  print(f1, l1, end=' ')
  for key in kwargs:
    print(key, kwargs[key], end=' ')

print_names("andrey", "master")
print_names("andrey", "master", alex="john", leon="elene")
# andrey master andrey master alex john leon elene

Обратите внимание, что фрагмент выше имеет ссылку на цикл for.

Тип данных для возвращаемого значения и параметров в Python

Определение типов данных для параметров функции в Python может быть полезным:

def prime_numbers(x:int) -> (int, list):
  l=[]
  for i in range(x+1):
    if checkPrime(i):
      l.append(i)
  return len(l), l

В нашем примере определение функции указывает, что нужен 1 параметр типа int и вернёт два значения типа list и int соответственно.

Возвращаемое значение функции в Python

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

def prime_numbers(x):
  l=[]
  for i in range(x+1):
    if checkPrime(i):
      l.append(i)
  return len(l), l

no_of_primes, primes_list = prime_numbers(100)

В нашем случае возвращаются 2 значения. Если данная функция вызывается, то возвращаемые значения сохраняются одновременно в 2-х переменных. Если же функция не возвращает ничего, то она неявно возвращает None.

Создание (определение) функции — Python

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

Вот шаблон определения простой функции:

def имя_функции():
    # тело функции, т.е. код
    print("abc")

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

from some-email-package import send

email = '[email protected]'
title = 'Помогите'
body = 'Я написал историю успеха, как я могу получить скидку?'

# Один маленький вызов — и много логики внутри
send(email, title, body)

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

Создадим нашу первую функцию. У неё будет одна задача: выводить на экран текст Today is: December 5.

Нужно назвать функцию так, чтобы из названия была понятна её задача. Давайте дадим ей имя show_date():

# Определение функции
# Определение не вызывает функцию
# Мы лишь говорим, что теперь такая функция существует
def show_date():
    text = 'Today is: December 5'
    print(text)

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

Чтобы на 100% понять происходящее, обязательно сделайте следующее:

  1. Зайдите на https://repl.it/languages/python3. Это онлайн-интерпретатор Python.
  2. В левой части введите код примера выше.
  3. Запустите программу нажатием на «RUN ▶».
  4. Программа выполнится, но на экран ничего не выведется, потому что в программе есть только определение функции, но не запуск.
  5. Чтобы запустить функцию, нужно вызвать её. Добавьте к программе вызов:
  show_date()  # => Today is: December 5
  1. Запустите программу снова и удостоверьтесь, что в правой части на экран вывелся текст.

Соберём всё вместе. Вот полная программа, с определением функции и вызовом:

def show_date():
    text = 'Today is: December 5'
    print(text)

show_date()
Today is: December 5

Понятие «создать функцию» имеет много синонимов: «реализовать», «определить» и даже «заимплементить» (от слова implement). Все они встречаются в повседневной практике на работе.

Задание

Реализуйте функцию print_motto(), которая печатает на экран фразу Winter is coming.

print_motto()  # => Winter is coming

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


Советы


Нашли ошибку? Есть что добавить? Пулреквесты приветствуются https://github.com/hexlet-basics

Мир Python: функционалим по-маленьку — Продвинутый Python

Продвинутый Python

Введение

Существует несколько парадигм в программировании, например, ООП, функциональная, императивная, логическая, да много их. Мы будем говорить про функциональное программирование.

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

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

Теория в теории

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

  • Функции высшего порядка
  • Чистые функции
  • Неизменяемые данные

Это не полный список, но даже этого хватает чтобы сделать «красиво». Если читателю хочется больше, то вот расширенный список:

  • Функции высшего порядка
  • Чистые функции
  • Неизменяемые данные
  • Замыкания
  • Ленивость
  • Хвостовая рекурсия
  • Алгебраические типы данных
  • Pattern matching

Постепенно рассмотрим все эти моменты и как использовать в Python.

А сегодня кратко, что есть что в первом списке.

Чистые функции

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

Плюсы:

  • Легче читать и понимать код
  • Легче тестировать (не надо создавать «условий»)
  • Надежнее, потому что не зависят от «погоды» и состояния окружения, только от аргументов
  • Можно запускать параллельно, можно кешировать результат

Неизменяемые данные

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

Преимущества неизменяемых структур:

  • Безопасно разделять ссылку между потоками
  • Легко тестировать
  • Легко отследить жизненный цикл (соответствует data flow)

theory-source

Функции высшего порядка

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


def f(x):
    return x + 3

def g(function, x):
    return function(x) * function(x)

print(g(f, 7))

Рассмотрели теорию, начнем переходить к практике, от простого к сложному.

Списковые включения или генератор списка

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

Пример кода:


for x in xrange(5, 10):
    if x % 2 == 0:
        x =* 2
    else:
        x += 1

Цикл с условием, подобные встречаются не редко. А теперь попробуем эти 5 строк превратить в одну:

>>> [x * 2 if x % 2 == 0 else x + 1 for x in xrange(5, 10)]
[6, 12, 8, 16, 10]

Недурно, 5 строк или 1. Причем выразительность повысилась и такой код проще понимать — один комментарий можно на всякий случай добавить.

В общем виде эта конструкция такова:

[stmt for var in iterable if predicate] 

Стоит понимать, что если код совсем не читаем, то лучше отказаться от такой конструкции.

Анонимные функции или lambda

Продолжаем сокращать количества кода.

Функция:

def calc(x, y):
    return x**2 + y**2

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

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

>>> lambda x, y: x**2 + y**2
<function <lambda> at 0x7fb6e34ce5f0>

Для программиста это такие же функции и с ними можно также работать.

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

Пример:

>>> (lambda x, y: x**2 + y**2)(1, 4)
17
>>>
>>> func = lambda x, y: x**2 + y**2
>>> func(1, 4)
17

Лямбда-функции могут выступать в качестве аргумента. Даже для других лямбд:

multiplier = lambda n: lambda k: n*k

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

Функции без названия научились создавать, а где использовать сейчас узнаем. Стандартная библиотека предоставляет несколько функций, которые могут принимать в качестве аргумента функцию — map(), filter(), reduce(), apply().

map()

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


>>> list1 = [7, 2, 3, 10, 12]
>>> list2 = [-1, 1, -5, 4, 6]
>>> list(map(lambda x, y: x*y, list1, list2))
[-7, 2, -15, 40, 72]

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

>>> [x*y for x, y in zip(list1, list2)]
[-7, 2, -15, 40, 72]

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

filter()

Функция filter() позволяет фильтровать значения последовательности. В результирующем списке только те значения, для которых значение функции для элемента истинно:

>>> numbers = [10, 4, 2, -1, 6]
>>> list(filter(lambda x: x < 5, numbers))     # В результат попадают только те элементы x, для которых x < 5 истинно
[4, 2, -1]

То же самое с помощью списковых выражений:

>>> numbers = [10, 4, 2, -1, 6]
>>> [x for x in numbers if x < 5]
[4, 2, -1]

reduce()

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

>>> numbers = [2, 3, 4, 5, 6]
>>> reduce(lambda res, x: res*x, numbers, 1)
720

Вычисления происходят в следующем порядке:

((((1*2)*3)*4)*5)*6

Цепочка вызовов связывается с помощью промежуточного результата (res). Если список пустой, просто используется третий параметр (в случае произведения нуля множителей это 1):

>>> reduce(lambda res, x: res*x, [], 1)
1

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

>>> reduce(lambda res, x: [x]+res, [1, 2, 3, 4], [])
[4, 3, 2, 1]

Для наиболее распространенных операций в Python есть встроенные функции:

>>> numbers = [1, 2, 3, 4, 5]
>>> sum(numbers)
15
>>> list(reversed(numbers))
[5, 4, 3, 2, 1]

В Python 3 встроенной функции reduce() нет, но её можно найти в модуле functools.

apply()

Функция для применения другой функции к позиционным и именованным аргументам, заданным списком и словарем соответственно (Python 2):

>>> def f(x, y, z, a=None, b=None):
...     print x, y, z, a, b
...
>>> apply(f, [1, 2, 3], {'a': 4, 'b': 5})
1 2 3 4 5

В Python 3 вместо функции apply() следует использовать специальный синтаксис:

>>> def f(x, y, z, a=None, b=None):
...     print(x, y, z, a, b)
...
>>> f(*[1, 2, 3], **{'a': 4, 'b': 5})
1 2 3 4 5

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

Замыкания

Функции, определяемые внутри других функций, представляют собой замыкания. Зачем это нужно? Рассмотрим пример, который объяснит:

Код (вымышленный):


def processing(element, type_filter, all_data_size):
    filters = Filter(all_data_size, type_filter).get_all()
    for filt in filters:
        element = filt.filter(element)

def main():

    data = DataStorage().get_all_data()

    for x in data:
        processing(x, 'all', len(data))

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

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

Научимся оформлять замыкания:

def multiplier(n):
    "multiplier(n) возвращает функцию, умножающую на n" 
    def mul(k): 
        return n*k 
     return mul 
     # того же эффекта можно добиться выражением 
     # multiplier = lambda n: lambda k: n*k 

mul2 = multiplier(2) # mul2 - функция, умножающая на 2, например, 
mul2(5) == 10

Заключение

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


Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.
Об обучении на Хекслете

Python Лямбда


Лямбда-функция — это небольшая анонимная функция.

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


Синтаксис

лямбда аргументы : выражение

Выражение выполняется и возвращается результат:

Пример

Добавьте 10 к аргументу a , и вернуть результат:

x = лямбда a: a + 10
print (x (5))

Попробуй сам »

Лямбда-функции могут принимать любое количество аргументов:

Пример

Умножение аргумента на на аргумент b и вернуть результат:

x = лямбда a, b: a * b
print (x (5, 6))

Попробуй сам »

Пример

Обобщить аргумент a , b и c и вернуть результат:

x = лямбда a, b, c: a + b + c
print (x (5, 6, 2))

Попробуй сам »

Зачем нужны лямбда-функции?

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

Допустим, у вас есть определение функции, которое принимает один аргумент, и этот аргумент будет умножено на неизвестное число:

определение myfunc (n):
вернуть лямбда a: a * n

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

Пример

определение myfunc (n):
вернуть лямбда a: a * n

mydoubler = myfunc (2)

print (mydoubler (11))

Попробуй сам »

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

Пример

определение myfunc (n):
вернуть лямбда a: a * n

mytripler = myfunc (3)

print (mytripler (11))

Попробуй сам »

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

Пример

определение myfunc (n):
вернуть лямбда a: a * n

mydoubler = myfunc (2)
mytripler = myfunc (3)

print (mydoubler (11))
принт (mytripler (11))

Попробуй сам »

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




Определение вашей собственной функции 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])
Ложь
>>> любое ([False, True, 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 .

Синтаксис для вызова функции 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 доллара
  

Параметры ( кол-во , предмет и цена ) ведут себя как переменные , которые определены локально для функции.Когда функция вызывается, переданные аргументы ( 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 (кол-во = 6, товар = 'бананы', цена = 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 // Пример Pascal # 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 // Пример Pascal # 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 . f () затем вызывается в строке 7 с 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) = 13578
14
15 >>> печать ('x =', x, '/ id (x) =', id (x))
16x = 5 / id (x) = 13578
  

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

Передача аргументов в 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 , кортеж или 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 ()
>>> т
('foo', 'bar', 'baz', '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 '{префикс} {".".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 из двойного и под из символа подчеркивания ( _ ).В будущих уроках этой серии вы встретите еще много неприятных атрибутов и методов.

Вы можете получить доступ к строке документации функции с помощью выражения .__ 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': , 'b': , 'return': }
  

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

>>>
  >>> 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': , 'b': , 'return': }

>>> 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: принудительная проверка типов

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

>>>
  >>> 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': , 'b': , 'return': }
  

По сути, это та же функция со словарем __annotations__ , созданным вручную:

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

>>> f .__ annotations__ = {'a': int, 'b': str, 'return': float}

>>> f .__ annotations__
{'a': , 'b': , 'return': }
  

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

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

>>>
  >>> def f () -> 0:
... f .__ аннотации __ ['return'] + = 1
... print (f "f () был выполнен {f .__ annotations __ ['return']} время (с)")
...

>>> f ()
f () было выполнено 1 раз (а)
>>> f ()
f () было выполнено 2 раза (а)
>>> f ()
f () было выполнено 3 раза (а)
  

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

Заключение

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

Вы узнали:

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

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

Функции в Python - GeeksforGeeks

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

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

Синтаксис:

 def имя_функции (параметры):
    "" "строка документации" ""
    оператор (ы) 

Пример:

Python

def evenOd (x):

if (x % = = 0 ):

печать «четный»

еще :

печать «нечетный»

evenOdd ( 2 )

evenOdd ( 3 )

Docstring

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

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

  Синтаксис:  print (имя_функции .__ doc__) 

Пример:

Python3


1 , скажем, def 900i ):

«Привет, выродки!»

печать (say_Hi.__doc__)

Выход:

 Здравствуйте! выродки! 

Оператор return

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

  Синтаксис:  return [список_выражений] 

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

Пример:

Python3

2 144

Это результат работы программы 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.

Лямбда-функции ограничены одним выражением. Они можно использовать везде, где можно использовать обычные функции. Eсть Лямбда-функции 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)
печать (список (футы))
 

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

ft = map (лямбда t: (9.0 / 5) * t + 32, cs)
 

Функция map () применяет анонимную функцию к каждому элементу списка cs . Он возвращает итерацию из вычисленные температуры по Фаренгейту.

$ ./lambda_fun2.py
[14.0, 32.0, 59.0, 86.0, 104.0]
 

Это пример вывода.

Эта глава была о функциях в Python.

СОДЕРЖАНИЕ Предыдущий Следующий

функций Python - подсказка для Linux

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

Python имеет различные встроенные функции, включая print (), type () и другие. Но мы также можем определить или написать наши функции. Мы называем эти функции «пользовательскими» функциями. В этой статье вы узнаете, как определить функцию на нескольких примерах. Редактор Spyder3 используется для создания и написания скриптов Python, показанных в этой статье.

Как определить функцию

В Python функция начинается с ключевого слова def.

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

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

После написания имени функции и списка параметров поставьте двоеточие [:] и начните писать фрагмент кода или операторов.

Наконец, в функции есть оператор return, который возвращает выходные данные функции.

Ниже приводится основной синтаксис определения функции:

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

Пример функции

Давайте посмотрим на примере функции в Python. Эта функция принимает год в качестве входного параметра и проверяет, является ли данный год високосным или нет. Функция вызывается по имени функции.

# определение функции для проверки, является ли год високосным.
def leap_year (year):
# если год% 4 равен нулю, то это високосный год, в противном случае - нет.
if (year% 4 == 0):
print (год, «високосный год»)
else:
print (год, «не високосный год»)
# вызов функции
leap_year (2020)

Выход

Вывод отображается в правой части консоли Python.

Проходящие аргументы

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

Давайте посмотрим на пример передачи нескольких аргументов в функции.

# определение функции для печати информации о студенте
def student_info (first_name, last_name, Father_name, rollNo, email):
# печать имени ученика
print ("Имя студента:", first_name)
# печать фамилии ученика
print ("Фамилия ученика:", last_name)
# печать имени отца ученика
print ("Имя отца ученика:", имя_ отца)
# печать студенческого списка №
print ("Номер ученического списка:", rollNo)
# печать студенческого электронного письма
print ("Электронная почта студента:", электронная почта)
# вызов функции
student_info («Камран», «Аваиси», «Абдул Саттар», 12, «[электронная почта защищена]»)

Выход

Вывод отображается в правой части консоли Python.

Термины «параметр» и «аргумент» идентичны. Параметр - это значение, записанное в круглых скобках, и мы используем параметр внутри функции. Например, first_name, last_name, Father_name, rollNo и email являются параметрами в примере, приведенном выше.

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

Определение значения аргумента по умолчанию

Вы также можете определить значение аргумента по умолчанию.Например, мы определим функцию, которая принимает в качестве аргумента два числа и вычисляет сумму. Значение второго числа (параметра) по умолчанию равно 10. Мы передадим только значение первого числа в качестве аргумента, и функция вычислит сумму.

# определение функции для вычисления суммы двух чисел
# значение второй переменной по умолчанию установлено равным 10
def calculate_sum (num1, num2 = 10):
print ("The sum is:", num1 + num2 )
# вызов функции
# передача значения первой переменной в качестве аргумента
calculate_sum (15)

Выход

Вывод отображается в правой части консоли Python.

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

# определение функции для вычисления суммы двух чисел
# значение второй переменной по умолчанию установлено равным 10
def calculate_sum (num1, num2 = 10):
print ("The sum is:", num1 + num2 )
# вызов функции
# передача значения первой переменной в качестве аргумента
calculate_sum (15,25)

Выход

Вывод отображается в правой части консоли Python.

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

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

# определение функции для вычисления суммы двух чисел
def calculate_sum (num1, num2):
print ("The sum is:", num1 + num2)
# вызов функции
# передача значения переменных с помощью ключевого слова аргумент
Calcul_sum (num1 = 15, num2 = 25)

Выход

Вывод отображается в правой части консоли Python.

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

# определение функции для вычисления суммы двух чисел
def calculate_sum (num1, num2):
print ("The sum is:", num1 + num2)
# вызов функции
# передача значения переменных с помощью аргумент ключевого слова.
Порядок чисел num1 и num2 изменен
calculate_sum (num2 = 15, num1 = 25)

Выход

Вывод отображается в правой части консоли Python.

Теперь давайте изменим названия ключевых слов и посмотрим, что произойдет.

Выход

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

Аргументы переменной длины

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

# определение функции для печати информации
def print_linuxhint (* myargs):
for i in myargs:
print (i)
# вызов функции
# передача значения нескольких переменных
print_linuxhint ("Hello", "и "," добро пожаловать "," в "," LinuxHint ")

Выход

Вывод отображается в правой части консоли Python.

Заявление о возврате

Оператор return используется в конце для выхода из функции. Этот оператор передает вывод обратно туда, где была вызвана функция.

Давайте посмотрим на пример оператора возврата:

# определение функции для вычисления суммы двух чисел
def calculate_sum (num1, num2):
# добавление оператора return
# оператор return возвращает значение суммы вызывающей стороне.
return num1 + num2
# вызов функции
print (calculate_sum (15,25))

Выход

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

Заключение

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

def square_value (num):

возврат num *

печать (square_value ( 2 ))

print (square_value ( - 4 ))

Выход:


 4
16 

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

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

Пример:

Python

def myFun (x):

x [ 0 ] = 20

lst = [ 10 , 11 , 12 , 13 , 14 , 15 ]

myFun (lst)

print (lst)

Вывод
 [20, 11, 12, 13, 14, 15] 

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

Python

def myFun (x):

x , 30 , 40 ]

lst = [ 10 , 11 , 12 , 13 , 14 , 15 ]

myFun (lst)

печать (lst)

Выход
 [10, 11, 12, 13, 14, 15] 

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

Python

def myFun (x):


2 x

03

x = 10

myFun (x)

print (x)

Упражнение: Попробуйте угадать результат следующего кода.

Python

def swap (x, y):

temp = x

x = y 2 04 y = temp

x = 2

y = 3

swap (x, y)

печать (x)

print (y)

Аргументы по умолчанию:

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

Python

Выход
 ('x:', 10)
('y:', 50) 

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

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

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

Python

def myFun (x, y = 50 ):

печать ( "x:" , x)

печать ( "y:" , y)

myFun ( 10 )

def студент (имя, фамилия):

печать (имя, фамилия)

студент (имя 22 ) «Гики» , фамилия = «Практика» )

студент (фамилия = «Практика» , имя = «Вундеркинды» )

Выход
 («Компьютерщики», «Практика»)
(«Гики», «Практика») 

Аргументы переменной длины:

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

Пример 1:

Python

def myFun ( * argv):

arg arg для arg :

печать (arg)

myFun ( 'Привет' , 'Добро пожаловать' , 'на' , ' GeeksforGeeks ' )

Выход
 Привет
Добро пожаловать
к
GeeksforGeeks 

Пример 2:

Python3

def myFun ( * * kwargs


2
2 значение
2 kwargs значение в кваргс.items ():

print ( "% s ==% s" % (ключ, значение))

myFun (первый = "Компьютерщики" , середина = "для" , последний = "Компьютерщики )

Вывод
 первый == Компьютерщики
mid == для
last == Компьютерщики 

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

Python3

def куб (x): возврат x * x * x

900v2 v2 лямбда x: x * x * x

печать (куб ( 7 ))

печать (куб_v2 ( 7 ))

Ссылки:

Внимание компьютерщик! Укрепите свои основы с помощью курса Python Programming Foundation и изучите основы.

Для начала подготовьтесь к собеседованию. Расширьте свои концепции структур данных с помощью курса Python DS . И чтобы начать свое путешествие по машинному обучению, присоединяйтесь к Машинное обучение - базовый курс

функций Python - работа с функциями в Python

СОДЕРЖАНИЕ Предыдущий Следующий

последнее изменение 6 июля 2020 г.

В этой части руководства по программированию на Python мы рассмотрим функции на Python.

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

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

  • Сокращение дублирования кода
  • Разложение сложных проблем на более простые
  • Повышение четкости кода
  • Повторное использование кода
  • Скрытие информации

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

Типы функций Python

Есть два основных типа функций: встроенные функции и пользовательские. определенные функции. Встроенные функции являются частью языка Python; например dir () , len () или abs () . Пользовательские функции - это функции, созданные с помощью ключевого слова def .

Функции создания Python

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

функция def ():
    проходить
 

За ключевым словом def следует имя функции в круглых скобках и двоеточие. Операторы с отступом образуют тело функции.

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

myfunc ()
 

Чтобы вызвать функцию, мы указываем имя функции в круглых скобках.

рет.py

#! / 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))

печать (ф.__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 () в h () функция.

$ ./fun_coll.py
<функция f в 0x0000015B998E9D08>
<функция g в 0x0000015B998E9E18>
<функция h в 0x0000015B998E9840>
14

Python 3 Примечания: функции, определяемые пользователем

На этой странице: def, return, docstrings, help (), value-return vs.пустые функции

Функции: основы

Давайте откажемся от старой алгебры. Вы узнали «функции» как что-то вроде:
f (x) = x 2 + 1
В Python определение функции работает следующим образом. def - ключевое слово для определения функции. За именем функции следует параметр (ы) в (). Двоеточие: означает начало тела функции, которое отмечено отступом. Внутри тела функции оператор return определяет возвращаемое значение.После завершения определения функции вызов функции с аргументом возвращает значение.
>>> def f (x):
        возврат x ** 2 + 1

>>> f (4)
17
>>>
 
Попробуем другую функцию. Ниже приведена функция, которая принимает глагол (надеюсь) и возвращает герундийную форму:
>>> def get_ing (wd):
        вернуть wd + 'ing'

>>> get_ing ('прогулка')
'гулять пешком'
>>>
 

Несколько параметров, строка документации

Ниже представлена ​​чуть более сложная функция.Он принимает два аргумента, имеет условное выражение в теле функции и начинается со строки:
>>> def same_initial (wd1, wd2):
        "" "Проверяет, начинаются ли два слова с одного и того же символа,
        и возвращает True / False. Различие в регистре игнорируется.
        если wd1 [0] .lower () == wd2 [0] .lower ():
            вернуть True
        еще:
            вернуть ложь

>>> same_initial ('яблоко', 'апельсин')
Ложь
>>> same_initial ('Энни', 'яблоко')
Правда
>>>
 
"" "Проверяет, если... Строка "" "называется" docstring ". Размещенная в самом верху тела функции, она действует как документация для функции. Эта строка распечатывается, когда вы вызываете help () для функции:
>>> справка (same_initial)
Справка по функции same_initial в модуле __main__:

same_initial (wd1, wd2)
    Проверяет, начинаются ли два слова с одного и того же символа,
    и возвращает True / False. Различие в регистре игнорируется.
>>>
 
Вот еще один пример.Эта функция возвращает список символов, общих для двух строк. (Было бы лучше, если бы не было дубликатов. Можно улучшить?)
>>> def in_both (wd1, wd2):
        «Принимает две строки, возвращает отсортированный список общих символов»
        common = []
        для c в wd1:
            если c в wd2:
                common.append (c)
        вернуть отсортированный (общий)

>>> in_both ('груша', 'яблоко')
['a', 'e', ​​'p']
>>> in_both ('лингвистика', 'экономика')
['c', 'i', 'i', 'i', 'n', 's', 's']
>>>
 

Функции: Возврат vs.Пустота

Вы можете подумать: «Погодите минутку, я не видел никакого оператора возврата в учебнике по определению функций». Вы правы - определенная Эд функция get_legal () не включала никакого оператора возврата, а только набор функций печати. В Python можно составить функцию без оператора возврата. Такие функции называются void , и они возвращают None, специальный объект Python "ничего". Вот пример функции void:
>>> def sayhello (кто):
        print ('Привет,', кто + '!')
        print ('Какой прекрасный день.')

>>> Sayhello ('Акбар')
Привет, Акбар!
Какой прекрасный день.
>>>
 
Хорошо, тогда чем отличаются функции void и функции типа "return"? Хороший вопрос. Позвольте мне проиллюстрировать это на примерах. Вот функция get_ing (), определенная выше, и ее недействительный аналог print_ing ():
>>> def get_ing (wd):
        вернуть wd + 'ing'

>>> def print_ing (wd):
        печать (wd + 'ing')

 
Вызывая две функции, вы сначала замечаете небольшую разницу в выводе.Возвращающая функция дает вам строку (примечание ''), а функция печати показывает напечатанный вывод строки - обратите внимание на отсутствие кавычек. Обратите внимание, что возвращаемое значение отображается только в интерактивной среде оболочки; в сценарии только команды печати приводят к отображению вывода.
>>> get_ing ('интерес')
'интересно'
>>> print_ing ('интерес')
интересно
>>>
 
Теперь, поскольку get_ing () возвращает значение, его можно скопировать в переменную с помощью оператора присваивания.Попробуйте сделать то же самое с print_ing (), и вы столкнетесь с непредвиденными последствиями: печать происходит после оператора присваивания, и в итоге вы не получаете ничего в качестве значения переменной, потому что эта функция, будучи недействительной, ничего не возвращает.
>>> foo = get_ing ('интерес')
>>> фу
'интересно'
>>> faa = print_ing ('интерес')
интересно
>>> фаа
>>>
 
Кроме того, функцию, возвращающую значение, можно подключить прямо к другой функции.Опять же, поскольку функции void ничего не возвращают, они не могут. Ниже get_ing ('eat') передается функции len () для успешного результата. С помощью len (print_ing ('eat')) печать происходит независимо, а затем возникает ошибка типа:
>>> len (get_ing ('есть'))
6
>>> len (print_ing ('есть'))
принимать пищу

Отслеживание (последний вызов последний):
  Файл "", строка 1, в 
    len (print_ing ('есть'))
TypeError: объект типа NoneType не имеет len ()
 
Наконец, если вам нужна печать, ее также можно выполнить с помощью функции возврата значения: просто используйте с ней оператор печати.
>>> print (get_ing ('интерес'))
интересно
>>> print_ing ('интерес')
интересно
>>>
 
Это заняло некоторое время, но я надеюсь, что теперь вы ясно видите фундаментальные различия между двумя типами функций. По правде говоря, функции возвращаемого типа гораздо более функциональны и полезны. В других языках функции типа void даже не называются функциями - вместо этого они называются процедурами.

Учебные пособия и примечания по функциям | Python

Функции

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

В этом уроке вы узнаете:

  • Как создать функцию
  • Как вызвать функцию

Как создать функцию:

В Python для создания функции вам нужно написать ее следующим образом. Обратите внимание, что в теле функции отступ в 4 пробела.

  def имя_функции (аргументы):
    '' '
    доктрина функции
    обратите внимание, что функциональный блок имеет отступ в 4 пробела
    '' '
    тело функции
    вернуть возвращаемое значение или выражение
  

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

  def add_two_numbers (num1, num2):
    '' 'возвращает сумму num1 и num2' ''
    результат = число1 + число2
    вернуть результат
  

Вот все части функции:

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

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

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

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

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

Как вызвать функцию

Вызов функции с возвращаемым значением

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

Например, если у вас есть функция, которая складывает два числа

  def add_two_numbers (num1, num2):
    '' 'возвращает сумму num1 и num2' ''
    результат = число1 + число2
    вернуть результат
  

Вы могли бы вызвать функцию так:

  add_two_numbers (1, 2)
  

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

  >>> def add_two_numbers (num1, num2):
... '' 'возвращает сумму num1 и num2' ''
... результат = число1 + число2
... вернуть результат
...
>>> # вызываем функцию add_two_numbers с аргументами 4 и 5 и присваиваем ей
>>> # к переменной sum_of_4_and_5
>>> sum_of_4_and_5 = ​​add_two_numbers (4, 5)
>>>
>>> # показать значение, хранящееся в sum_of_4_and_5
>>> print (сумма_4_и_5)
9
  

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

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

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

  def Printing_side_effects ():
    '' 'функция с побочными эффектами' ''
    print ('это функция с побочными эффектами и выполняет некоторую задачу')
  

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

  >>> Printing_side_effects ()
  

это функция с побочными эффектами и выполняет некоторую задачу

Как вызвать функцию с аргументами

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

  >>> def string_multiplier (string_arg, number):
... '' 'берет string_arg и умножает его на единицу больше, чем число' ''
... вернуть string_arg * (число + 1)
...

>>> # передаем string_arg и number и в таком порядке .