

15.10.2022, 11:11 |
7. Функции - Jupyter Notebook |
In [33]:
1 def hello_i18n(name):
2if lang == 'ru':
3print("Привет,",name)
4else:
5 |
print("Hello,",name) |
6 |
|
7 |
lang = 'ru' |
8 |
print("Hello world") |
9 |
hello_i18n('Ivan') |
10
11lang = 'en'
12hello_i18n('John')
Hello world
Привет, Ivan Hello, John
Как видите, сейчс поведение функции зависит от того, чему равняется переменная lang , определенная вне функции. Может быть и в функции factorial() можно было обратиться к переменной f до того момента, как мы положили в неё число 1? Давайте попробуем:
In [34]:
1 def factorial(n):
2print("In the function, before assignment, f =", f)
3f = 1
4for i in range(2, n+1):
5f = f * i
6 print("In the function, f =", f)
7return f
In [35]:
1 factorial(2)
---------------------------------------------------------------------------
UnboundLocalError |
Traceback (most recent call last) |
|
<ipython-input-35-26972ebb8a51> in <module> |
||
----> 1 |
factorial(2) |
|
<ipython-input-34-9edfcfd8c667> in factorial(n) |
||
1 |
def factorial(n): |
|
----> 2 |
print("In the function, before assignment, f =", f) |
3f = 1
4for i in range(2, n+1):
5f = f * i
UnboundLocalError: local variable 'f' referenced before assignment
В этом случае Python выдаёт ошибку: локальная переменная f использовалась до присвоения значения. В чём разница между этим кодом и предыдущим?
127.0.0.1:8888/notebooks/EXONTOOLS/2/Доп. занятия/7. Функции.ipynb |
11/17 |

15.10.2022, 11:11 |
7. Функции - Jupyter Notebook |
Оказывается, Python очень умный: прежде, чем выполнить функцию, он анализирует её код и определяет, какая из переменных является локальной, а какая глобальной. В качестве глобальных переменных по умолчанию используются те, которые не меняются в теле функции (то есть такие, к которым не применяются операторы типа приравнивания или += ). Иными словами, по умолчанию глобальные переменные доступны только для чтения, но не для модификации изнутри функции.
Ситуация, при которой функция модифицирует глобальную переменную, обычно не очень желательна: функции должны быть изолированы от кода, который из запускает, иначе вы быстро перестанете понимать, что делает ваша программа. Тем не менее, иногда модификация глобальных переменных необходима. Например, мы хотим написать функцию, которая будет устанавливать значение языка пользовавателя. Она может выглядеть примерно так:
In [36]:
1 |
def set_lang(): |
2 |
useRussian = input("Would you like to speak Russian (Y/N): ") |
3 |
if useRussian == 'Y': |
4lang = 'ru'
5else:
6lang = 'en'
In [39]:
1 lang = 'en'
2 print(lang)
3 set_lang()
4 print(lang)
en
Would you like to speak Russian (Y/N): N en
Как видим, эта функция не работает — собственно, и не должна. Чтобы функция set_lang смогла менять значение переменной lang , её необходимо явно объявить как глобальную с помощью ключевого слова global .
In [40]:
1 def set_lang():
2global lang
3 useRussian = input("Would you like to speak Russian (Y/N): ") 4 if useRussian == 'Y':
5lang = 'ru'
6else:
7lang = 'en'
In [43]:
1 lang = 'en'
2 print(lang)
3 set_lang()
4 print(lang)
en
Would you like to speak Russian (Y/N): Y ru
127.0.0.1:8888/notebooks/EXONTOOLS/2/Доп. занятия/7. Функции.ipynb |
12/17 |

15.10.2022, 11:11 |
7. Функции - Jupyter Notebook |
Теперь всё работает!
Передача аргументов
Есть разные способы передавать аргументы функции. С одним из них мы уже знакомы:
In [44]:
1 def hello(name, title):
2print("Hello", title, name)
In [45]:
1 hello("Potter", "Mr.")
Hello Mr. Potter
В некоторым случаях мы хотим, чтобы какие-то аргументы можно было не указывать. Скажем, мы хотим иметь возможность вызвать функцию hello() , определённую выше, не указывая title . В этом случае сейчас нам выдадут ошибку:
In [46]:
1 hello("Harry")
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-46-4266b7e1b9aa> in <module>
----> 1 hello("Harry")
TypeError: hello() missing 1 required positional argument: 'title'
Это неудивительно: мы сказали, что функция hello() должна использовать аргумент title , но не передали его — какое же значение тогда использовать? Для преодоления этой трудности используютя значения по умолчанию (default values).
In [48]:
1 |
def hello(name, title=""): |
2 |
print("Hello", title, name) |
3 |
hello("Harry") |
|
|
Hello Harry
In [49]:
1 hello("Smith", "Mrs.")
Hello Mrs. Smith
Аргументы можно передавать, указывая их имена.
127.0.0.1:8888/notebooks/EXONTOOLS/2/Доп. занятия/7. Функции.ipynb |
13/17 |

15.10.2022, 11:11 |
7. Функции - Jupyter Notebook |
|
In [50]: |
|
|
1 |
hello("Smith", title = "Mr.") |
|
Hello Mr. Smith |
|
|
In [51]: |
|
|
1 |
hello(name = "Smith", title= "Mr.") |
|
Hello Mr. Smith
В этом случае порядок будет неважен.
In [89]:
1 hello(title= "Mr.", name = "Smith")
Hello Mr. Smith
Ещё бывают функции, которые принимают неограниченное число аргументов. Например, так ведёт себя функция print() .
In [61]:
1 print(8, 7, 5, 'hello', 8)
8 7 5 hello 8
Как она устроена? Примерно вот так:
In [52]:
1 def my_print(*args):
2for x in args:
3print(x)
In [53]:
1 my_print(6, 8, 9, 'hello', 88, 55)
6
8
9 hello 88 55
Обратите внимание на звёздочку перед args в сигнатуре функции. Давайте посмотрим повнимательнее, как работает этот код:
127.0.0.1:8888/notebooks/EXONTOOLS/2/Доп. занятия/7. Функции.ipynb |
14/17 |

15.10.2022, 11:11 |
7. Функции - Jupyter Notebook |
In [54]:
1 def test(*args):
2print(args)
3 test(1,2,3, 'hello')
(1, 2, 3, 'hello')
Оказывается, что в args теперь лежит так называемые кортеж, состоящий из элементов, которые мы передали функции.
Отступление: кортежи
Кортеж ( tuple ) — это почти то же самое, что и список, только его элементы неизменяемы. Обозначается он круглыми скобками.
In [92]:
1 t = (2,3, 5, 1) 2 print(t[1])
3 print(t[0:2])
3 (2, 3)
In [97]:
1 for x in t:
2print(x)
2
3
5
1
In [93]:
1 t[0] = 10
---------------------------------------------------------------------------
TypeError Traceback (most recent call last) <ipython-input-93-eaf187d38884> in <module>()
----> 1 t[0] = 10
TypeError: 'tuple' object does not support item assignment
127.0.0.1:8888/notebooks/EXONTOOLS/2/Доп. занятия/7. Функции.ipynb |
15/17 |

15.10.2022, 11:11 7. Функции - Jupyter Notebook
In [94]:
1 t.append(1)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last) <ipython-input-94-2337caf868e4> in <module>()
----> 1 t.append(1)
AttributeError: 'tuple' object has no attribute 'append'
Тот факт, что нельзя изменять кортеж, не означает, что нельзя переопределить переменную t :
In [99]:
1 t = (8, 1, 2, 3)
In [100]:
1 t
Out[100]:
(8, 1, 2, 3)
Можно думать о списке как о меловой доске, расчерченной на отдельные ячейки, в которые можно записывать разные значения. Тогда кортеж — это глинянная (или каменная) дощечка, на которой выбиты какие-то значения. Вы не можете изменить значения, которые на ней выбиты, но вы можете разбить старую дощечку и изготовить новую.
Можно также конвертировать списки в кортежи и наоборот.
In [101]:
1 print( list( (1, 2, 3) ) )
2 print( tuple( [1, 2, 3] ) )
[1, 2, 3] (1, 2, 3)
Возвращаясь к функциям
Таким образом, звёздочка в сигнатуре как бы ставит дополнительные скобки вокруг аргументов. Например, следующие два вызова приводят к одинаковым результатам.
127.0.0.1:8888/notebooks/EXONTOOLS/2/Доп. занятия/7. Функции.ipynb |
16/17 |

15.10.2022, 11:11 |
7. Функции - Jupyter Notebook |
|||
In [56]: |
|
|||
1 |
|
def test1(*args): |
|
|
|
|
|||
2 |
|
|
print(args) |
|
3 |
|
test1(1, 2, 3) |
|
|
4 |
|
|
|
|
5 |
|
def test2(args): |
|
|
6 |
|
|
print(args) |
|
7 |
|
test2( (1,2,3) ) |
|
|
|
|
|
|
|
(1, |
2, |
3) |
|
|
(1, |
2, |
3) |
|
Можно комбинировать списочные переменные и обычные (при условии, что переменная со звёздочкой только одна):
In [57]:
1 def my_print(sep, *args):
2for x in args:
3 print(x, end = sep)
4
In [58]: |
|
|
||
|
|
|
||
|
1 |
my_print(' |
----', 7, 8, 9, 'hello') |
|
|
|
|
|
|
7 |
----8---- |
9---- |
hello---- |
На сегодня всё :)
127.0.0.1:8888/notebooks/EXONTOOLS/2/Доп. занятия/7. Функции.ipynb |
17/17 |