Перейти до змісту

Стратегії обчислення

Стратегія обчислення — це семантика використання формальних і фактичних параметрів функції.

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

Існує декілька стратегій обчислення, ось деякі:

  • Виклик по значенню (call-by-value). Сама розповсюджена стратегія обчислення. При виклику по значенню, вираз-аргумент обчислюється, і отримане значенння зв'язується з відповідним формальним параметром функції (зазвичай за допомогою копіювання цього значення у новую ділянку пам'яті). При цьому, якщо мова програмування дозволяє функціям присвоювати значення своїм параметрам, то зміни будуть стосуватися лише цих локальних копій, але видимі у місці виклика функції значення залишаться незміненими після повернення.
  • Виклик по посиланню При виклику по посиланню (call-by-reference), або передачі по посиланню (pass-by- reference), функція неявно отримує посилання на змінну, яку було використано у якості аргумента, змість копії її значення. Зазвичай це означає, що функція може здійснювати модифікацію (тобто змінювати стан) змінної, переданої в якості параметра, і це також матиме ефект у контексті, що викликав функцію.
  • Виклик по співвикористанню (виклик зі спільним використанням ресурсів, call-by-sharing). Значення у мові програмування основані на об'єктах, а не на примітивних типах. При виклику по співвикористанню функція отримує значення, яке містить копію посилання на об'єкт. Сам об'єкт не копіюється — він буде використовуватись спільно. Як наслідок, присвоєння аргументу у тілі функції не має ефекта у контексті, що її викликав, але присвоєння компонентам цього аргумента — має.

Стратегія обчислення в Python

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

>>> def double(obj):
...     print(f'До: {obj}')
...     obj = obj * 2
...     print(f'Після: {obj}')
...
>>> x = 7
>>> double(x)
До: 7
Після: 14
>>> x
7
>>>

Значенн змінної x не змінилось оскільки вона вказує на немутабельний int.

Спробуємо інший виклик:

>>> x = [1, 2]
>>> double(x)
До: [1, 2]
Після: [1, 2, 1, 2]
>>> x
[1, 2]
>>>

Функції було передано мутабельний list. Але значенн змінної x не змінилось! Чому так?

  1. Функція приймає параметр obj.
  2. В функції змінній obj присвоюється значення.
  3. Спочатку обчислюється вираз після знака присвоєння. Це значення на який вказує парамет obj
  4. Потім локальній змінній obj присвоюється обчислене значення.
  5. Об'єкт, на який вказував параметр obj не змінюється

Давайте все ж таки спробуємо змінити переданий функції об'єкт:

>>> def append(obj):
...     print(f'До: {obj}')
...     obj.append(7)
...     print(f'Після: {obj}')
...
>>> x = [1, 2]
>>> append(x)
До: [1, 2]
Після: [1, 2, 7]
>>> x
[1, 2, 7]
>>>

Значенн змінної x змінилось оскільки вона вказує на мутабельний list і цей об'єкт було змінено всередині функції.

Дуже часто можна зустріти ствердження, що у Python аргументи передаються по посиланню. Однак, як ми впевнились вище, це не зовсім відповідає дійсності. Просто завжди пам'ятайте про це.

Резюме

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

Додаткові матеріали

"Стратегії обчислення" у Wikipedia

Завдання

Не запускаючи код на виконання визначте яке значення буде відповідати змінній my_list після його виконання і поясніть чому саме так. Можете перевірити себе запустивши код.

def modify_list(lst):
    lst = [777]

my_list = [1, 2]
modify_list(my_list)
Back to top