Теоретичні відомості#

Функції — це багаторазово використовувані фрагменти програми, які забезпечують кращу модульність програми та значно підвищують рівень повторного використання коду (див. [1], стр. 118-130). Функції дозволяють надати ім’я визначеному блоку команд з тим, щоб згодом запускати цей блок за вказаним ім’ям у будь-якому місці програми. Це називається викликом функції. Існують правила для створення функцій у Python.

  • Блок функції починається з ключового слова def, після якого записано назву функції і круглі дужки.

  • Будь аргументи, які приймає функція, повинні бути розміщені всередині цих дужок.

  • Після дужок йде двокрапка і з нового рядка з відступом починається тіло функції (блок команд, які складають функцію).

На прикладі можна побачити простоту застосування функції.

def sayHello():
    print('Привіт студенти!') # блок, що належить функції
# Кінець функції
sayHello() # виклик функції
sayHello() # ще один виклик функції
Привіт студенти!
Привіт студенти!

Як це працює#

Визначено функцію з ім’ям sayHello, використовуючи описаний вище синтаксис. Ця функція не приймає параметрів, тому в дужках не оголошені будь-які змінні. Параметри функції — це якісь вхідні дані, які можна передати функції, щоб отримати відповідний їм результат.

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

Параметри функцій#

Функції можуть приймати параметри, тобто деякі значення, що передаються функції для того, щоб вона щось зробила з ними. Ці параметри схожі на змінні, за винятком того, що значення цих змінних вказується при виклику функції, і під час роботи функції їм уже присвоєні їх значення.

Параметри вказуються в дужках при оголошенні функції і розділяються комами. Аналогічно передаються значення, коли викликається функція. Слід звернути увагу на термінологію: імена, зазначені в оголошенні функції, називаються параметрами, тоді як значення, які передаються в функцію при її виклику — аргументами.

def printMax(a, b):
    if a > b:
        print(a, 'максимально')
    elif a == b:
        print(a, 'дорівнює ', b)
    else:
        print(b, 'максимально')
printMax(3, 4) # пряма передача значень 
x = 5
y = 7
printMax(x, y) # передача змінних в якості аргументів 
4 максимально
7 максимально

Як це працює#

Тут визначена функція з ім’ям printMax, яка використовує два параметри з іменами \(a\) і \(b\). Знаходиться найбільше число із застосуванням простого оператора if..else і виводиться це число. При першому виклику функції printMax безпосередньо передаються числа в якості аргументів. У другому випадку викликається функція зі змінними в якості аргументів. printMax(x, y) призначає значення аргументу \(x\) параметру \(a\), а значення аргументу \(y\) — параметру \(b\). В обох випадках функція printMax працює однаково.

Аргументи функції в Python#

Викликаючи функцію, можна передавати їй такі типи аргументів:

  • Обов’язкові аргументи (Required arguments)

  • Аргументи за замовчуванням (Default argument)

  • Аргументи-ключові слова (Keyword argument)

  • Аргументи довільної довжини (Variable-length argumens)

Обов’язкові аргументи функції#

Якщо при створенні функції ми вказали кількість переданих їй аргументів і їх порядок, то і викликати її ми повинні з тією ж кількістю аргументів, заданих в потрібному порядку.

def bigger(a, b):
    if a > b:
        print(a)
    else:
        print(b)
# В описі функції зазначено, що вона приймає 2 аргументи
# Коректне використання функції
bigger(5, 6)  
6
# Некоректне використання функції 
bigger()
bigger(3)
bigger(12, 7, 3)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-6-67f6a73dfbf1> in <module>
      1 # Некоректне використання функції
----> 2 bigger()
      3 bigger(3)
      4 bigger(12, 7, 3)

TypeError: bigger() missing 2 required positional arguments: 'a' and 'b'

Аргументи за замовчуванням#

Найчастіше частина параметрів функцій можуть бути необов’язковими, і для них будуть використовуватися деякі задані значення за замовчуванням, якщо користувач не вкаже власних. Цього можна досягти за допомогою значень аргументів за замовчуванням. Їх можна вказати, додавши до імені параметра у визначенні функції оператор присвоювання (=) з подальшим значенням.

Значення за замовчуванням має бути константою. Або точніше кажучи, воно має бути незмінним.

def say(message, times=1):
    print(message * times)
say('Привіт')
say('Світ', 5)
Привіт
СвітСвітСвітСвітСвіт

Як це працює#

Функція під ім’ям say використовується для виведення на екран рядку вказане число раз. Якщо не вказується значення, за замовчанням рядок виводиться один раз. Це досягається вказанням значення аргументу за замовчуванням, рівного \(1\) для параметра \(times\). При першому виклику say вказується тільки рядок, і функція виводить його один раз. При другому виклику say вказується також і аргумент \(5\), позначаючи таким чином, що фраза сказана \(5\) разів. Важливо: Значеннями за замовчанням можуть бути наділені тільки ті параметри, що знаходяться в кінці списку параметрів. Таким чином, в списку параметрів функції параметр із значенням за замовчанням не може передувати параметру без значення за замовчанням. Це пов’язано з тим, що значення присвоюються параметрам відповідно до їх положення. Наприклад,

def func(a, b=5) 

допустимо, а

def func(a=5, b)

не допустимо.

Аргументи-ключові слова#

Якщо є деяка функція з великим числом параметрів, і при її виклику потрібно вказати тільки деякі з них, значення цих параметрів можуть задаватися по їх імені - це називається ключові параметри. В цьому випадку для передачі аргументів функції використовується ім’я (ключ) замість позиції (як було досі). Є дві переваги такого підходу: по-перше, використання функції стає легше, оскільки немає необхідності відстежувати порядок аргументів; по-друге, можна задавати значення тільки деяким обраним аргументів, за умови, що інші параметри мають значення аргументу за замовчуванням.

def func(a, b=5, c=10):
    print('a дорівнює', a, ', b дорівнює', b, ', а c дорівнює', c)
func(3, 7)
func(25, c=24)
func(c=50, a=100)
a дорівнює 3 , b дорівнює 7 , а c дорівнює 10
a дорівнює 25 , b дорівнює 5 , а c дорівнює 24
a дорівнює 100 , b дорівнює 5 , а c дорівнює 50

Як це працює#

Функція з ім’ям func має один параметр без значення за замовчуванням, за яким слідують два параметра із значеннями за замовчуванням.

При першому виклику func(3, 7) параметр a отримує значення \(3\), параметр b отримує значення \(7\), а c отримує своє значення за замовчуванням, яке дорівнює \(10\).

При другому виклику func(25, c=24) змінна a отримує значення \(25\) в через позицію аргументу. Після цього параметр c отримує значення \(24\) по імені, тобто як ключовий параметр. Змінна b отримує значення за замовчуванням, яке дорівнює \(5\).

При третьому зверненні func(c=50, a=100) ключові аргументи використовуються для всіх вказаних значень. Звертається увага на те, що значення для параметра c указується перед значенням для a, навіть, незважаючи на те, що у визначенні функції параметр a вказано раніше c.

Аргументи довільної довжини#

Іноді буває потрібно визначити функцію, здатну приймати будь-яке число параметрів. Цього можна досягти за допомогою синтаксису із використанням зірочок (так званого *args/**kwargs синтаксису).

def total(a=5, *numbers, **phonebook):
    print('a', a) 
    # Прохід по всіх елементах кортежу
    for single_item in numbers:
        print('single_item', single_item) # прохід по всіх елементах словника
    for first_part, second_part in phonebook.items():
        print(first_part, second_part)
print(total(10, 1, 2, 3, Jack=1123, John=2231, Inge=1560))
a 10
single_item 1
single_item 2
single_item 3
Jack 1123
John 2231
Inge 1560
None

Як це працює#

Коли оголошується параметр із зірочкою (наприклад, *param), всі позиційні аргументи, починаючи з цієї позиції і до кінця, будуть зібрані в кортеж під ім’ям param.

Аналогічно, коли оголошуються параметри зі двома зірочками (**param), всі ключові аргументи, починаючи з цієї позиції і до кінця, будуть зібрані в словник під ім’ям param.

Тільки ключові параметри#

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

def total(initial=5, *numbers, extra_number):
    count = initial
    for number in numbers:
        count += number
    count += extra_number
    print(count)
    
total(10, 1, 2, 3, extra_number=50)
total(10, 1, 2, 3)
# викличе помилку, оскільки ми не вказали значення
# аргументу за замовчуванням для 'extra_number'.
66
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-14-bb778dc9f85d> in <module>
      7 
      8 total(10, 1, 2, 3, extra_number=50)
----> 9 total(10, 1, 2, 3)
     10 # викличе помилку, оскільки ми не вказали значення
     11 # аргументу за замовчуванням для 'extra_number'.

TypeError: total() missing 1 required keyword-only argument: 'extra_number'

Як це працює#

Оголошення параметрів після параметра із зірочкою дає тільки ключові аргументи. Якщо для таких аргументів не вказано значення за замовчуванням, і воно не передано при виклику, звернення до функції викличе помилку, що показано в прикладі.

Використання +=, який представляє собою скорочений оператор, дозволяє замість x = x+y просто написати x += y.

Якщо потрібні аргументи, що передаються тільки по ключу, але не потрібен параметр із зірочкою, то можна просто вказати одну зірочку без вказівки імені: def total (initial = 5, *, extra_number).

Область видимості змінних#

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

У Python є дві базових області видимості змінних:

  • Локальні змінні

  • Глобальні змінні

Локальні змінні#

При оголошенні змінних всередині визначення функції, вони жодним чином не пов’язані з іншими змінними з таким же ім’ям за межами функції — тобто імена змінних є локальними в функції. Це називається областю видимості змінної. Область видимості всіх змінних обмежена блоком, в якому вони оголошені, починаючи з точки оголошення імені.

x = 50
def func(x):
    print('x дорівнює ', x)
    x = 2
    print('Заміна локального x на ', x)
    
func(x)
print('x як і раніше ', x)
x дорівнює  50
Заміна локального x на  2
x як і раніше  50

Як це працює#

При першому виведенні значення, присвоєного імені x, в першому рядку функції Python використовує значення параметра, оголошеного в основному блоці, вище визначення функції.

Далі x призначається значення \(2\). Ім’я x локально для даної функції. Тому коли замінюється значення x в функції, x, оголошений в основному блоці, залишається незмінним.

Останнім викликом функції print виводиться значення x, вказане в основному блоці, підтверджуючи таким чином, що воно не змінилося при локальному присвоєнні значення в раніше викликаної функції.

Зарезервоване слово global#

Щоб надати деяке значення змінної, визначеної на вищому рівні програми (тобто не в якій-небудь області видимості, як-то функції або класи), необхідно вказати Python, що її ім’я не локально, а глобально (global). Робиться це за допомогою зарезервованого слова global. Без застосування зарезервованого слова global неможливо привласнити значення змінної, визначеної за межами функції.

Можна використовувати вже існуючі значення змінних, визначених за межами функції (за умови, що всередині функції не було оголошено змінної з таким же ім’ям). Однак, це не вітається, і такого слід уникати, оскільки людині, що читає текст програми, буде незрозуміло, де знаходиться оголошення змінної. Використання зарезервованого слова global досить чітко показує, що змінна оголошена в самому зовнішньому блоці.

x = 50
def func():
    global x
    print('x дорівнює', x)
    x = 2
    print('Замінюємо глобальне значення x на', x)

func()
print('Значення x становить', x)
x дорівнює 50
Замінюємо глобальне значення x на 2
Значення x становить 2

Як це працює#

Зарезервоване слово global використовується для того, щоб оголосити, що x — це глобальна змінна, а значить, коли присвоюється значення імені x всередині функції, це зміна відіб’ється на значенні змінної x в основному блоці програми.

Використовуючи одне зарезервоване слово global, можна оголосити відразу кілька змінних:

global x,y,z

Зарезервоване слово nonlocal#

Раніше розглянуто отримання доступу до змінних в локальній і глобальній області видимості. Є ще один тип області видимості, званий “нелокальною” (nonlocal) областю видимості, який є чимось середнім між першими двома. Нелокальні області видимості зустрічаються, коли визначається функція всередині функцій.

Оскільки в Python все є виконуваним кодом, функції можна визначати де завгодно.

def func_outer():
    x = 2
    print('x дорівнює', x)
    def func_inner():
        nonlocal x
        x = 5
    func_inner()
    print('Локальне x змінилося на', x)
func_outer()
x дорівнює 2
Локальне x змінилося на 5

Як це працює#

Усередині func_inner, змінна x, визначена в першому рядку func_outer розташована ані в локальній області видимості (визначення змінної не входить в блок func_inner), ані в глобальному контексті (вона також і не в основному блоці програми). Оголошується використання саме цієї змінної x наступним чином:

nonlocal x

Оператор return#

Оператор return використовується для повернення з функції, тобто для припинення її роботи і виходу з неї. При цьому можна також повернути деяке значення з функції.

def maximum(x,y):
    if x > y:
        return x
    elif x == y:
        return 'Числа рівні.'
    else:
        return y
    
print(maximum(2, 3))
3

Як це працює#

Функція maximum повертає максимальний з двох параметрів, які в даному випадку передаються їй при виклику. Вона використовує звичайний умовний оператор if..else для визначення найбільшого числа, а потім повертає це число.

Оператор return без вказівки значення, що повертається, еквівалентний вислову return None. None — це спеціальний тип даних в Python, що позначає “нічого”. Наприклад, якщо значення змінної встановлено в None, це означає, що їй не присвоєно ніякого значення.

Кожна функція містить в неявній формі оператор return None в кінці, якщо не вказано свій власний оператор return. У цьому можна переконатися, запустивши print(someFunction()), де функція someFunction — це якась функція, яка не має оператора return в явному вигляді. Наприклад:

def someFunction():
    pass

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

Порада:

Існує вбудована функція max, в якій вже реалізований функціонал “пошук максимуму”, тому рекомендується користуватися цією вбудованою функцією, де це можливо.

lambda-функції#

lambda-функція — це безіменна функція з довільним числом аргументів і обчислює один вираз. Тіло такої функції не може містити більше однієї інструкції (або виразу). Дану функцію можна використовувати в рамках будь-яких конвеєрних обчислень (наприклад, всередині filter(), map() і reduce()) або самостійно, в тих місцях, де потрібно провести якісь обчислення, які зручно “загорнути” у функцію.

(lambda x: x**2)(5)
25

lambda-функцію можна присвоїти будь-якій змінній і надалі використовувати її в якості імені функції.

sqrt = lambda x: x**0.5
sqrt(25)
5.0

Наступний фрагмент коду показує різницю між звичайним визначенням функції f і lambda-функції g

def f (x): return x**2
print(f(8))

g = lambda x: x**2
print(g(8))
64
64

Як видно, f() і g() роблять одне і теж, і можуть використовуватися в одних і тих же місцях. Визначення lambda-функції не включає оператор return - ця конструкція завжди містить вираз, результат якого повертається. Визначення lambda-функції може використовуватися скрізь, де очікується функція і немає потреби присвоювати значення змінній.

Узагальнюючи, можна констатувати, що lambda-функція — це функція, яка має довільне число аргументів (включаючи необов’язкові аргументи) і повертає значення одного виразу. lambda-функції не можуть містити інструкцій або більше одного виразу. Не треба включати в lambda-функцію занадто багато. Якщо необхідно щось більш складне — визначайте звичайну функцію.

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

Основну частину можливостей Python, які демонструє lambda-функція можна побачити в зворотних викликах Tkinter. Tkinter — це включений в Python набір інструментів, для створення графічних інтерфейсів. Розглянуто досить багато аспектів функцій, але, тим не менше, треба розуміти, що це далеко не всі їхні аспекти. У той же час, представлено більшість того, з чим можна зіткнутися при повсякденному використанні функцій в Python.