Python. Аргументы в функциях. Передача аргументов в функцию. Изменение аргументов в теле функции

Аргументы в функциях. Передача аргументов в функцию. Изменение аргументов в теле функции


Содержание


Поиск на других ресурсах:




1. Как осуществляется передача аргументов в функцию? Работа механизма передачи аргумента в функцию

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

Например, к изменяемым объектам относятся списки и словари. К неизменяемым объектам относятся числа, строки, кортежи.

Если в функцию передается неизменяемый объект, то этот объект передается «по значению». Это значит, что изменение этого объекта внутри функции не изменит его в вызывающем коде.

Если в функцию передается изменяемый объект, то этот объект передается по «указателю». Изменение такого объекта внутри функции повлияет на этот объект в вызывающем коде.

 

2. Примеры передачи неизменяемых объектов в функцию
2.1. Передача числа в функцию.

В примере, в демонстрационных целях реализована функция Mult2(), которая получает параметром число. В теле функции это число удваивается. Полученный результат выводится.

# Передача числа в функцию
# Число - это неизменяемый объект, значит передается "по значению"

# Объявить функцию, которая получает некоторое число и умножает его на 2
def Mult2(number):
    # умножить число на 2
    number = number*2

    # вивести значение числа всередине функции
    print("Mult2.number = ", number)

# Использовать функцию
num = 25 # некоторое число
Mult2(num) # вызвать функцию

# вывести число num после вызова функции
print("num = ", num) # num = 25 - число не изменилось

После запуска программа выдаст следующий результат

Mult2.number =   50
num = 25

Как видно из результата, в функции значение числа num умножается на 2 и составляет 50. Однако, этот результат не передается в вызывающий код, здесь значение num остается равным 25 как до вызова функции. Это подтверждает передачу «по значению» неизменяемого объекта, которым есть число.

 

2.2. Передача строки в функцию

Демонстрируется работа функции ReverseStr(), которая реверсирует строку, получаемую параметром.

# Передача строки в функцию
# Строка - это неизменяемый объект, поэтому передается "по значению"

# Объявить функцию, получающую строку,
# реверсирует ее и выводит на экран
def ReverseStr(text):
    # Реверсировать строку
    txt = ''

    # цикл перебора строки
    for c in text:
        txt = c + txt

    text = txt

    # вывести реверсованный текст
    print('ReveseStr.text = ', text)

# Вызов функции ReverseStr()
Text = "Hello world!"
ReverseStr(Text)
print("Text = ", Text)

Результат выполнения программы следующий

ReveseStr.text =   !dlrow olleH
Text = Hello world!

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

 

2.3. Передача кортежа в функцию

 

# Передача кортежа в функцию

# Функция, получающая параметром кортеж
def PassTuple(T):
    # Изменить кортеж
    T = ([1,2], 'a', 25.88)
    print('PassTuple.T = ', T)

# Создать кортеж
TT = ( [2, 3.5], True, 'abcd')

# Вызвать функцию и передать ей кортеж TT
PassTuple(TT)

# Вывести кортеж TT
print('TT = ', TT)

Результат выполнения программы

PassTuple.T = ([1, 2], 'a', 25.88)
TT = ([2, 3.5], True, 'abcd')

Так же, как и в предыдущих двух примерах, передача кортежа в функцию происходит по значению.

 

3. Примеры передачи изменяемых объектов в функцию
3.1. Передача списка в функцию

Демонстрируется функция, которая получает список в качестве параметра. Затем в теле функции этот список изменяется (изменяются первый и второй элементы списка).

# Передача списка в функцию. Список - изменяемый объект

# Функция, которая получает параметром список
def ChangeList(L):
    # Изменить список
    L[0] = 777 # Изменить первый элемент списка
    L[1] = (2, 3) # Изменить второй элемент списка

    # Вывести список в теле функции
    print('ChangeList.L = ', L)

# Создать список
LL = [ [2, 3.5], True, 'abcd' ]

# Вывести список LL для контроля
print('LL = ', LL)

# Вызвать функцию и передать ей список LL
ChangeList(LL)

# Вывести список LL после вызова функции
print('LL = ', LL)

Результат работы программы

LL = [[2, 3.5], True, 'abcd']
ChangeList.L =   [777, (2, 3), 'abcd']
LL = [777, (2, 3), 'abcd']

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

 

3.2. Передача словаря в функцию

Демонстрируется функция ChangeDict() которая получает словарь в качестве параметра. В теле функции изменяются отдельные элементы словаря, лежащие на позициях с номерами 0 и 2.

# Передача словаря в функцию. Словарь - изменяемый объект

# Функция, получающая параметром словарь
def ChangeDict(D):
    # Изменить словарь
    D['A'] = 100 # Изменить первый элемент списка
    D['C'] = 300 # Изменить третий элемент списка

    # Вывести список в теле функции
    print('ChangeDict.D = ', D)

# Создать словарь
DD = { 'A':5, 'B':10, 'C':20 }

# Вывести словарь DD для контроля
print('DD = ', DD)

# Вызвать функцию и передать ей словарь DD
ChangeDict(DD)

# Вывести список DD после вызова функции
print('DD = ', DD)

Результат работы программы

DD = {'A': 5, 'B': 10, 'C': 20}
ChangeDict.D =   {'A': 100, 'B': 10, 'C': 300}
DD = {'A': 100, 'B': 10, 'C': 300}

 

4. Способы избежания изменения объектов-аргументов в вызывающем коде

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

Способ 1. При передаче списка в функцию можно конвертировать этот список в кортеж с помощью операции tuple(). После этого изменить список в теле функции не удастся.

Нижеследующий код демонстрирует использование операции tuple() для конвертирования списка в кортеж.

# Передача списка в функцию с конвертированием в кортеж
def PassList(L):
    # Попытка изменить список
    L[0] = 100 # Ошибка!

    # Вывести список в теле функции
    print('PassList.L = ', L)

# Создать список
LL = [ 1, 3, 8, 10 ]

# Вызвать функцию и передать ей список LL, который конвертирован в кортеж
PassList(tuple(LL))

# Вывести список L после вызова функции
print('LL = ', LL)

Список LL передается в функцию PassList() как кортеж

PassList(tuple(LL))

После этого, изменить элемент списка LL в функции PassList() не удастся. Если запустить программу, то будет сгенерировано исключение с сообщением

TypeError: 'tuple' object does not support item assignment

Способ 2. При передаче списка в функцию можно использовать операцию среза [:], как показано в следующей программе

# Передача списка в функцию с конвертированием в срез
def PassList(L):
    # Попытка изменить список
    L[0] = 100 # Это изменение не повлияет на вызывающй код

    # Вывести список в теле функции
    print('PassList.L = ', L)

# Создать список
LL = [ 1, 3, 8, 10 ]

# Вызвать функцию и передать ей список как срез [:]
PassList(LL[:])

# Вывести список L после вызова функции
print('LL = ', LL)

В вышеприведенном коде при вызове функции с помощью строки

...

PassList(LL[:])

...

срез LL[:] осуществляет копию списка. Таким образом, изменения списка внутри функции не приведут к изменению списка в вызывающем коде, поскольку эти изменения будут выполняться над копией.

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

PassList.L = [100, 3, 8, 10]
LL = [1, 3, 8, 10]

 

5. Особенности передачи аргументов в функцию. Итоги

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

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

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

# Аргументы.
# Передача аргумента в функцию

# Функция, которая получает аргумент и выводит его на экран
def Argument(v):
    print('Argument.v = ', v)
    return

# Демонстрация неявного присваивания
value = 'Hello world!' # некоторый объект

# передать объект value в функцию Argument(),
# происходит неявное присваивание Argument.v = value
Argument(value) # Argument.v = Hello world!

2. Аргументы функции – это ссылки на объекты. При передаче аргумента в функцию передается ссылка на объект. Передаваемые ссылки реализованы как указатели в языке C. Поскольку, при передаче в функцию аргумента, копируется ссылка на объект, то сам объект никогда не копируется. Иными словами, не создается автоматическая копия объекта при передаче его в функцию, осуществляется только копия ссылки.

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

Например. В примере, в функции Func() изменяется значение параметра D на 25. В вызывающем коде был передан аргумент с таким самым именем D со значением 30. Однако, после вызова функции из вызывающего кода, значение внешнего аргумента D не изменилось, что и надо было доказать.

# Аргументы.
# Передача аргумента в функцию - копия объекта не делается

# Функция, которая получает аргумент-список
def Func(D):
    D = 25 # здесь D - новое имя
    print('Func.D = ', D)

D = 30
Func(D) # вызов функции

print('D = ', D) # D = 30 - значение объекта в функции не изменилось

4. Если в функцию передается аргумент (объект), который есть изменяемым (список, словарь), то изменение этого аргумента внутри функции приведет к изменению аргумента в вызывающем коде. Это касается только изменения составных элементов объекта (отдельный элемент словаря или списка). Если попробовать изменить объект по его общему имени (с помощью операции присваивания =), то изменений в вызывающем коде не будет (передается ссылка на объект, а именно ссылку изменить нельзя).

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

  • функция ChangeList() – пробует изменить список по имени ссылки L. Это изменение не влияет на внешний список LL, переданный из вызывающего кода. Это связано с тем, что делается копия ссылки, изменения копии не изменяют оригинал;
  • функция ChangeList2() – пробует изменить элемент списка по имени ссылки L и позицией элемента. Результат – изменение влияет на внешний список LL в вызывающем коде. Это связано с тем, что копия и оригинал указывают на одни и те же данные (один и тот же участок памяти);

 

# Аргументы.
# Передача изменяемого объекта в качестве аргумента

# Функция, которая получает параметр-список и изменяет весь список
def ChangeList(L):
    # Изменить список всередине функции по имени
    L = [ 1, 2, 3] # не влияет на внешний код

    # Вывести измененный список
    print('ChangeList.L = ', L) # ChangeList.L = [1, 2, 3]

# Функция, которая получает параметр-список и изменяет элемент списка
def ChangeList2(L):
    # Изменить составной элемент списка
    L[1] = 'abcd' # влияет на внешний код
    print('ChangeList2.L = ', L)

# ----- Вызывающий код модуля -------
LL = [ 'a', 'b', 'c' ] # некоторый список

# 1. Передача списка в функцию ChangeList() и его вывод
ChangeList(LL) # передать список в функцию
print('LL = ', LL) # LL = ['а', 'b', 'с'] - список не изменился

# 2. Передать список LL в функцию ChangeList2()
ChangeList2(LL)
print('LL = ', LL) # LL = ['a', 'abcd', 'c' ] - список изменился

После выполнения программа выдаст следующий результат

ChangeList.L =   [1, 2, 3]
LL = ['a', 'b', 'c']
ChangeList2.L =   ['a', 'abcd', 'c']
LL = ['a', 'abcd', 'c']

 


Связанные темы