Передача функции другой функции в качестве параметра
Поскольку функции являются объектами, можно передавать их в качестве аргументов другим функциям. Функция talk() , которая изменяет строку, используя переданный ей объект функции, а затем печатает ее:
def talk(say): prt = say('Мир') print(prt)
Вы можете влиять на полученное сообщение, передавая различные функции:
def hello(name): return f'Привет name>.' def goodbye(name): return f'Пока name>.' >>> talk(hello) # Привет Мир. >>> talk(goodbye) # Пока Мир.
Важно. Функция hello передается функции talk() без скобок. Это означает, что передается только ссылка на функцию hello . Функция при этом не выполняется. Функция talk() , записывается со скобками, поэтому она будет вызываться как обычно.
Возможность передавать функциональные объекты в качестве аргументов другим функциям является мощной фишкой. Это позволяет абстрагироваться от функционала и передать поведение. В примере выше функция talk() остается прежней, но сохраняет возможность влиять на ее вывод, передавая различные варианты сообщений.
Функции, которые могут принимать другие функции в качестве аргументов, также называются функциями высшего порядка. Они необходимы для функционального стиля программирования.
Классическим примером функций высшего порядка в Python является встроенная функция map() . Она принимает в качестве аргументов функцию и итерируемую последовательность и вызывает функцию для каждого элемента в последовательности.
Вот как можно отформатировать последовательность имен, сопоставив им функцию приветствия hello() :
>>> list(map(hello, ['Юля', 'Миша', 'Андрей', 'София'])) # ['Привет Юля.', 'Привет Миша.', # 'Привет Андрей.', 'Привет София.']
- КРАТКИЙ ОБЗОР МАТЕРИАЛА.
- Функции это объекты
- Функции могут иметь атрибуты
- Функции могут храниться в структурах данных
- Функции могут быть вложенными
- Передача функции в качестве аргумента другой функции
- Область видимости переменных функции
- Операторы global и nonlocal
- Параметры (аргументы) функции
- Ключевые аргументы в определении функции Python
- Значение аргумента по умолчанию в функциях Python
- Варианты передачи аргументов в функцию Python
- Переменные аргументов *args и **kwargs в функции Python
- Распаковка аргументов для передачи в функцию Python
- Как оцениваются аргументы при вызове функции?
- Строгие правила передачи аргументов в функцию Python
- Инструкция return
- Анонимные функции (lambda-выражения)
- Строки документации в функциях Python
- Рекурсия
- Замыкания в функциях Python
- Перегрузка функций
Ограничение способов передачи аргументов в функцию Python
По умолчанию аргументы могут передаваться в функцию Python либо по положению, либо явно по ключевому слову. Для производительности и удобочитаемости имеет смысл ограничить способ передачи аргументов.
Определение функции может выглядеть так (доступно c версии Python3.8):
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2): ----------- ---------- ---------- | | | | позиционные или | | по ключу - только по ключевому слову | -- только по позиции
где символы / и * являются НЕобязательными. Эти символы указывают тип аргумента в зависимости от того, как они могут быть переданы в функцию:
- только по позиции,
- по позиции или по ключевому слову
- только по ключевому слову.
Аргументы, которые передаются ключевому слову также называются именованными аргументами (ключевые аргументы).
ВНИМАНИЕ: ограничение способов передачи аргументов, символами / и * в виде def f(. /, . *, . ) , стало доступно с версии Python3.8 и выше.
Позиционные или ключевые аргументы.
Если в определении функции нет специальных символов / и * , то аргументы могут быть переданы функции по позиции или по ключевому слову.
Только позиционные параметры .
При определении параметров функции можно указать область, в которой требуется передача только позиционных аргументов. Если указана такая область, то передать ключевое слово (имя аргумента), в этой области, при вызове функции становиться невозможным. Перед символом / (косая черта) могут располагаться только позиционные аргументы. Символ ‘/’ используются для логического разделения только позиционных аргументов от остальных передаваемых аргументов в функцию. Если в определении функции нет символа / , значит и нет только позиционных аргументов.
Параметры, следующие за / , могут быть позиционными или ключевыми аргументами или только ключевыми аргументами.
Только ключевые аргументы.
Чтобы определить область параметров функции, которые будут принимать только ключевые аргументы, нужно поместить их после маркера * — который означает список аргументов только для ключевых слов.
Примеры способов передачи аргументов функций.
Напоминаем, что эта функциональность доступна с версии Python3.8 и выше.
Рассмотрим следующие примеры определений функций с маркерами / (только позиционные) и * (только ключевые):
>>> def standard_arg(arg): . print(arg) . >>> def pos_only_arg(arg, /): . print(arg) . >>> def kwd_only_arg(*, arg): . print(arg) . >>> def combined_example(pos_only, /, standard, *, kwd_only): . print(pos_only, standard, kwd_only)
Первое определение функции standard_arg , наиболее знакомая форма передачи аргументов, не накладывает ограничений на соглашение о вызовах, и аргументы могут передаваться по позиции или ключевому слову:
>>> standard_arg(2) # 2 >>> standard_arg(arg=2) # 2
Вторая функция pos_only_arg , ограничена использованием только позиционных параметров, поскольку / в определении функции есть:
>>> pos_only_arg(1) # 1 >>> pos_only_arg(arg=1) # Traceback (most recent call last): # File "", line 1, in # TypeError: pos_only_arg() got an unexpected keyword argument 'arg'
Третья функция kwd_only_args , допускает только ключевые аргументы, как указано * в определении функции:
>>> kwd_only_arg(3) # Traceback (most recent call last): # File "", line 1, in # TypeError: kwd_only_arg() takes 0 positional arguments but 1 was given >>> kwd_only_arg(arg=3) # 3
И последний использует все три соглашения о вызовах в одном и том же определении функции:
>>> combined_example(1, 2, 3) # Traceback (most recent call last): # File "", line 1, in # TypeError: combined_example() takes 2 positional arguments but 3 were given >>> combined_example(1, 2, kwd_only=3) # 1 2 3 >>> combined_example(1, standard=2, kwd_only=3) # 1 2 3 >>> combined_example(pos_only=1, standard=2, kwd_only=3) # Traceback (most recent call last): # File "", line 1, in # TypeError: combined_example() got an unexpected keyword argument 'pos_only'
Наконец, рассмотрим определение этой функции, которое имеет потенциальную коллизию между позиционным аргументом name и **kwds которое имеет name в качестве ключа:
def foo(name, **kwds): return 'name' in kwds
Функция никогда не вернет True , поскольку ключевое слово name всегда будет привязываться к первому параметру. Например:
>>> foo(1, **'name': 2>) # Traceback (most recent call last): # File "", line 1, in # TypeError: foo() got multiple values for argument 'name' >>>
Но, используя / (только позиционные аргументы), это возможно, так как он допускает name в качестве позиционного аргумента и name в качестве ключа в аргументах ключевое слово:
def foo(name, /, **kwds): return 'name' in kwds foo(1, **'name': 2>) # True
Другими словами имена только позиционных параметров могут использоваться в ‘**kwds’ без двусмысленности.
В качестве руководства к использованию.
Рассмотренные варианты показывают, как использовать параметры / и * в определении функции:
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
Хорошие практики использования специальных параметров / и * в определении функции:
- Используйте только позиционные параметры, если вы хотите, чтобы имя параметров было недоступно для пользователя. Это полезно, когда имена параметров не имеют реального значения, если вы хотите установить порядок аргументов при вызове функции или если вам нужно взять некоторые позиционные параметры и произвольные ключевые слова.
- Используйте только ключевые аргументы, когда имена параметров имеют значение, а определение функции более понятно, если явно указывать имена или если вы хотите, чтобы пользователи не полагались на позицию передаваемого аргумента.
- Для API используйте только позиционное, чтобы предотвратить нарушение API, если имя параметра будет изменено в будущем.
- КРАТКИЙ ОБЗОР МАТЕРИАЛА.
- Функции это объекты
- Функции могут иметь атрибуты
- Функции могут храниться в структурах данных
- Функции могут быть вложенными
- Передача функции в качестве аргумента другой функции
- Область видимости переменных функции
- Операторы global и nonlocal
- Параметры (аргументы) функции
- Ключевые аргументы в определении функции Python
- Значение аргумента по умолчанию в функциях Python
- Варианты передачи аргументов в функцию Python
- Переменные аргументов *args и **kwargs в функции Python
- Распаковка аргументов для передачи в функцию Python
- Как оцениваются аргументы при вызове функции?
- Строгие правила передачи аргументов в функцию Python
- Инструкция return
- Анонимные функции (lambda-выражения)
- Строки документации в функциях Python
- Рекурсия
- Замыкания в функциях Python
- Перегрузка функций
Как передать переменную по ссылке в Python?

В Питоне аргументы функций передаются путем присваивания. Поскольку присваивание просто создает новые ссылки на объекты, то между именами аргумента в вызывающем и вызываемом методе нет общей ссылки.
Как же передать аргумент по ссылке? Вы можете добиться нужного эффекта несколькими способами.
Возвращение кортежа
def my_func(x, y): # x и y локальные имена, которым присвоены новые объекты x = 'новое значение' y = y + 1 # возвращаем новые значения return x, y a, b = 'старое значение', 9 a, b = my_func(a, b) print(a, b) результат: новое значение 10
Это почти всегда самое ясное решение.
Использование глобальных переменных
Использование глобальных переменных не рекомендуется, т. к. не потокобезопасно.
Передача изменяемого (mutable) объекта
def func1(a): # 'a' ссылается на изменяемый список a[0] = 'новое значение' a[1] = a[1] + 1 args = ['старое значение', 9] func1(args) print(args) результат: ['новое значение', 10]
Передача словаря
def func2(args): # args - изменяемый словарь args['a'] = 'новое значение' args['b'] = args['b'] + 1 args = func2(args) print(args) результат:
Передача экземпляра класса
class MyNamespace: def __init__(self, /, **args): for key, value in args.items(): setattr(self, key, value) def func3(args): args.a = 'новое значение' args.b = args.b + 1 args = Namespace(a='старое значение', b=9) func3(args) vars(args) результат:
Почти никогда не бывает веской причины, чтобы все так усложнять.
Лучший вариант из представленных – это вернуть кортеж, содержащий несколько возвращаемых значений.
Параметры и аргументы функции
В программировании функции могут не только возвращать данные, но также принимать их, что реализуется с помощью так называемых параметров, которые указываются в скобках в заголовке функции. Количество параметров может быть любым.
Параметры представляют собой локальные переменные, которым присваиваются значения в момент вызова функции. Конкретные значения, которые передаются в функцию при ее вызове, будем называть аргументами. Следует иметь в виду, что встречается иная терминология. Например, формальные параметры и фактические параметры. В Python же обычно все называют аргументами.
Рассмотрим схему и поясняющий ее пример:
Когда функция вызывается, то ей передаются аргументы. В примере указаны глобальные переменные num1 и num2 . Однако на самом деле передаются не эти переменные, а их значения. В данном случае числа 100 и 12. Другими словами, мы могли бы писать mathem(100, 12) . Разницы не было бы.
Когда интерпретатор переходит к функции, чтобы начать ее исполнение, он присваивает переменным-параметрам переданные в функцию значения-аргументы. В примере переменной a будет присвоено 100, b будет присвоено 12.
Изменение значений a и b в теле функции никак не скажется на значениях переменных num1 и num2 . Они останутся прежними. В Python такое поведение характерно для неизменяемых типов данных, к которым относятся, например, числа и строки. Говорят, что в функцию данные передаются по значению. Можно сказать, когда a присваивалось число 100, то это было уже другое число, не то, на которое ссылается переменная num1 . Число 100 было скопировано и помещено в отдельную ячейку памяти для переменной a .
На самом деле переменная a в момент присваивания значения может указывать на то же число 100, что и переменная num1 . Однако, когда a в результате вычислений в теле функции получает новое значение, то связывается с другой ячейкой памяти, потому что числа относятся к неизменяемым типам данных, то есть нельзя переписать значение содержащей их ячейки. При этом переменная num1 остается связанной со старым значением.
Существуют изменяемые типы данных. Для Питона, это, например, списки и словари. В этом случае данные передаются по ссылке. В функцию передается ссылка на них, а не сами данные. И эта ссылка связывается с локальной переменной. Изменения таких данных через локальную переменную обнаруживаются при обращении к ним через глобальную. Это есть следствие того, что несколько переменных ссылаются на одни и те же данные, на одну и ту же область памяти.
Необходимость передачи по ссылке связана в первую очередь с экономией памяти. Сложные типы данных, по сути представляющие собой структуры данных, обычно копировать не целесообразно. Однако, если надо, всегда можно сделать это принудительно.
Произвольное количество аргументов
Обратим внимание еще на один момент. Количество аргументов и параметров совпадает. Нельзя передать три аргумента, если функция принимает только два. Нельзя передать один аргумент, если функция требует два обязательных. В рассмотренном примере они обязательные.
Однако в Python у функций бывают параметры, которым уже присвоено значение по-умолчанию. В таком случае, при вызове можно не передавать соответствующие этим параметрам аргументы. Хотя можно и передать. Тогда значение по умолчанию заменится на переданное.
def cylinder(h, r = 1): side = 2 * 3.14 * r * h circle = 3.14 * r**2 full = side + 2 * circle return full figure1 = cylinder(4, 3) figure2 = cylinder(5) print(figure1) print(figure2)
131.88 37.68
При втором вызове cylinder() мы указываем только один аргумент. Он будет присвоен переменной-параметру h . Переменная r будет равна 1.
Согласно правилам синтаксиса Python при определении функции параметры, которым присваивается значение по-умолчанию должны следовать (находиться сзади) за параметрами, не имеющими значений по умолчанию.
А вот при вызове функции, можно явно указывать, какое значение соответствует какому параметру. В этом случае их порядок не играет роли:
… figure3 = cylinder(10, 2) figure4 = cylinder(r=2, h=10) print(figure3) print(figure4)
В данном случае оба вызова – это вызовы с одними и теми же аргументами-значениями. Просто в первом случае сопоставление параметрам-переменным идет в порядке следования. Во-втором случае – по ключам, которыми выступают имена параметров.
В Python определения и вызовы функций имеют и другие нюансы, рассмотрение которых мы пока опустим, так как они требуют более глубоких знаний, чем у нас есть на данный момент. Скажем лишь, что функции может быть определена так, что в нее можно передать хоть ни одного аргумента, хоть множество:
def few_or_many(*a): print(a) few_or_many(1) few_or_many('1', 1, 2, 'abc') few_or_many()
(1,) ('1', 1, 2, 'abc') ()
Опять же, судя по скобкам, здесь возникает упомянутый в прошлом уроке кортеж.
Практическая работа
Напишите программу, в которой определена функция int_test , имеющая один параметр. Функция проверяет, можно ли переданное ей значение преобразовать к целому числу. Если можно, возвращает логическое True . Если нельзя – False .
В основной ветке программы присвойте переменной s то, что пользователь вводит с клавиатуры. Вызовите функцию int_test() , передав ей значение s . Если функция возвращает истину, преобразуйте строку s в число n и выведите на экран значение n + 10 .
Примеры решения и дополнительные уроки в pdf-версии курса
X Скрыть Наверх
Python. Введение в программирование