Функции

Содержание
Введение
Пример
def
Hello World!
type hints
Параметры и аргументы
Типы аргументов
Аргументы по умолчанию
Значения по умолчанию Mutable vs Immutable
return
Области видимости
Встроенные функции
Вызываемые объекты
Похожие статьи

Пример использования

Создайте файл с раширением .py

Например functions_demo.py

Рассмотрим простейшую функцию, которая ничего не делает.

Чтобы её объявить используйте слово def затем придумайте название - например lazy поставьте круглые скобки () и двоеточие

Общий синтаксис следующий

def имя_функции(): какой-то код

В нашем случае получается

def lazy(): pass

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

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

Но не делает. Чтобы функция что-то делала её нужно вызвать. В нашем случае достаточно написать её имя и круглые скобки.

lazy()

python functions_demo.py

Если никаких ошибок не допущено вывод будет пустым

def

Ключевое слово def используется для определения новых функций.

Оно связывает объект функции с именем

Выполняется в runtime

Hello World!

Объявим и вызовем функцию, которая пишет Hello World!

def hello(): print("Hello World!") hello()

python functions_demo.py

Hello World!

Функцию не обязательно писать в одну строку. Лучше после двоеточия перейти на новую строку и сделать отступ из четырёх пробелов.

def hello(): print("Hello World!") hello()

python functions_demo.py

Hello World!

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

def sum(first, second): print(first + second) sum(3,4)

python functions_demo.py

7

type hints

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

def sum(first: float, second: float) -> float: print(first + second) sum(3.0, 4.6)

python functions_demo.py

7.6

Никаких ограничений эти подсказки не накладывают. Можно спокойно выполнить

sum("a", "b")

python functions_demo.py

И получить

ab

Подсказки нужны скорее для сторонней проверки, каким-либо инструментом.

Параметры и аргументы

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

В некоторых источниках вместо термина параметры используется термин формальные аргументы (formal arguments)

Проще всего понять на примере

def add(a, b): return a+b add(2, 3)

a и b это параметры, а 2 и 3 это аргументы

Типы аргументов

Аргументы могут передаваться как позиционные (positional) и как именованные (keyword).

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

Позиционные аргументы сопоставляются с параметрами (parameter или formal argument) в соответсвии с порядком следования.

Пример передачи двух позиционных аргументов

a = sub(2, 3)

Предположим, функция sub() вычитает из первого аргумента второй.

sub(2, 3) = -1, sub(3, 2) = 1. Порядок имеет значение

Именованные аргументы

Именованные аргументы сопоставляются с параметрами по их имени.

Пример передачи двух именованных аргументов

a = div(divident=4, divisor=2)

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

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

Один и тот же аргумент может быть передан как позиционный и как именованный.

def main(): print(div()) print(div(9, 3)) print(div(divisor=5, divident=25)) def div(divident=2, divisor=1): return divident/divisor if __name__ == "__main__": main()

2.0 3.0 5.0

Сперва нужно передавать позиционные аргументы, затем именованные

# Вызов print(div(divisor=5, 25)) # Приведёт к ошибке

print(div(divisor=5, 25)) ^ SyntaxError: positional argument follows keyword argument

Ещё один пример здесь

Про передачу заранее неопределёного количества аргументов читайте статью *args **kwargs

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

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

# Arguments with default values must come # after those without default values. def banner(message, border="-"): line = border * len(message) print(line) print(message) print(line) banner("www.HeiHei.ru") # will use default "-" banner("www.TopBicycle.ru", "*") banner("www.KickBrains.ru", border="|")

python default_argumet_values.py

------------- www.HeiHei.ru ------------- ***************** www.TopBicycle.ru ***************** ||||||||||||||||| www.KickBrains.ru |||||||||||||||||

Значения по умолчанию

Mutable vs Immutable

В качестве значений по умолчанию лучше использовать неизменяемые (immutable) объекты.

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

Пример

import time print("time.ctime()", time.ctime()) def show_default(arg=time.ctime()): print(arg) show_default() time.sleep(2) print("time.ctime()", time.ctime()) show_default()

time.ctime() Wed Jun 8 11:16:04 2022 Wed Jun 8 11:16:04 2022 time.ctime() Wed Jun 8 11:16:06 2022 Wed Jun 8 11:16:04 2022

Как видно из вывода в терминал - время уже ушло вперёд - 11:16:06 а функция как возвращала значение по умолчанию созданное в 11:16:04 так и продолжает это делать.

Рассмотрим ещё один пример. Теперь в качестве изменяемого объекта возьмём список

def add_spam(menu=[]): menu.append("spam") return menu breakfast = ['bacon', 'eggs'] print(add_spam(breakfast)) lunch = ['borsh'] print(add_spam(lunch)) print(add_spam()) print(add_spam()) print(add_spam())

['bacon', 'eggs', 'spam'] ['borsh', 'spam'] ['spam'] ['spam', 'spam'] ['spam', 'spam', 'spam']

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

Решить эту проблему можно сделав аргумент по умолчанию неизменяемым

def add_spam(menu=None): if menu is None: menu = [] menu.append("spam") return menu breakfast = ['bacon', 'eggs'] print(add_spam(breakfast)) lunch = ['borsh'] print(add_spam(lunch)) print(add_spam()) print(add_spam()) print(add_spam())

['bacon', 'eggs', 'spam'] ['borsh', 'spam'] ['spam'] ['spam'] ['spam']

return

Рассмотрим скрипт test_return.py

def test_return(): return "A" v = test_return() print(v)

python test_return.py

A

Всё выглядит хорошо, функция вернула строку, мы видим её в терминале.

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

tree return_ex

return_ex ├── parent_test_return.py └── test_return.py 0 directories, 2 files

# test_return def test_return(): return "A"

# parent_test_return from test_return import test_return v = test_return() print(v)

python parent_test_return.py

A

Области видимости

Рассмотрим четыре стандартные области видимости

Local: Внутри текущей функции
Enclosing: Внутри функции, вызывающей текущую
Global: Внутри модуля
Built-in: Встроенные в Python функции

Эта четвёрка описывается акронимом LEGB

Области видимости не имеют прямой связи с блоками кода.

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

count = 0 def show_count(): print(count) def set_count(c): count = c show_count() # 0 set_count(5) show_count() # 0

0 0

count = 0 def set_count(c): global count count = c show_count() # 0 set_count(5) show_count() # 0

0 5

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

Вызываемые объекты

Рассмотрим файл callables.py

def is_even(x): return x % 2 == 0 print(callable(is_even)) # True is_odd = lambda x: x % 2 == 1 print(callable(is_odd)) # True # Classes are callable print(callable(list)) # True # Methods are callable print(callable(list.append)) # True class CallMe: def __call__(self): print("Called!") my_call_me = CallMe() print(callable(my_call_me)) # True # Strings are not callable print(callable("This is no callable")) # False

python callables.py

True True True True True False

from functools import reduce import operator print(operator.add(8, 9)) print(reduce(operator.add, [1, 2, 3, 4, 5])) numbers = [1, 2, 3, 4, 5] accumulator = operator.add(numbers[0], numbers[1]) for item in numbers[2:]: accumulator = operator.add(accumulator, item) print(accumulator) def mul(x, y): print(f"mul {x} {y}") return x * y print(reduce(mul, range(1, 10))) # reduce(mul, []) # TypeErr reduce(mul, [1]) # returns element without calling reduce print(reduce(mul, [1])) # 1 # Initial value is added as a first accumulated value values = [1, 2, 3]

17 15 15 mul 1 2 mul 2 3 mul 6 4 mul 24 5 mul 120 6 mul 720 7 mul 5040 8 mul 40320 9 362880 1 6 0 6

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

Встроенные функции Python
all()
any()
chr()
copy()
enumerate()
isinstance()
iter()
map()
next()
ord()
random()
sorted()
type()
uuid()
unichr()
zip()