Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

describe lists as default values #36

Merged
merged 8 commits into from
Oct 6, 2022
Merged
128 changes: 110 additions & 18 deletions docs/base/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def print_theme():
# Выше была определена print_theme, ее и вызовем.
print_theme()
```
```
```bash
Лекция про функции!
Тело кончилось
```
Expand Down Expand Up @@ -152,7 +152,7 @@ def add_two(x):
from_print_theme = print_theme()
print(from_print_theme is None)
```
```
```bash
Лекция про функции!
Тело кончилось
True
Expand All @@ -167,7 +167,7 @@ True
from_add_two = add_two(2)
print(from_add_two)
```
```
```bash
4
```

Expand All @@ -187,7 +187,7 @@ def change_num(num):
print(change_num(4))
print(change_num(5))
```
```
```bash
2
10
```
Expand Down Expand Up @@ -217,7 +217,7 @@ try:
except NameError as ne:
print(ne)
```
```
```bash
name 'result' is not defined
```

Expand Down Expand Up @@ -273,7 +273,7 @@ def foo():

foo()
```
```
```bash
name
10
20
Expand All @@ -299,7 +299,7 @@ def make_adder(arg1):
add_three = make_adder(3)
print(add_three(2))
```
```
```bash
5
```

Expand All @@ -318,7 +318,7 @@ def adder(arg1, arg2):
add_three = partial(adder, 3)
print(add_three(2))
```
```
```bash
5
```

Expand Down Expand Up @@ -431,7 +431,7 @@ print(two_var_sum(-1, 2), two_var_sum(2, -1))
# Указывается название параметра и значение после =
print(two_var_sum(var2=2, var1=-1))
```
```
```bash
3 1
3
```
Expand All @@ -449,7 +449,7 @@ def many_arg_sum(*args):

many_arg_sum(1, 2, 3, 4, 5, 6)
```
```
```bash
21
```

Expand Down Expand Up @@ -484,7 +484,7 @@ hello(phrase="Здарова", name="Игорь")
# Если не указать значение именованного параметра, используется что по умолчанию
hello("Вася")
```
```
```bash
Приветствую, Саша
Здорова, Игорь
Привет, Вася
Expand Down Expand Up @@ -513,14 +513,106 @@ def congrats(today, everyone=False, **names_dates_mapper):

congrats("2021-09-17", Paul="2001-03-08", Lena="1997-01-31", Mark="1997-09-17")
```
```
```bash
Happy Birthday, Mark
```

!!! question "Что это за комментарий в тройных кавычках внутри функции?"

Это один из общепринятых способов написания [docstring](https://www.python.org/dev/peps/pep-0257/) — документации по функции.

### Списки как значения по умолчанию

Рассмотрим следующую функцию:

```python linenums="1"
def fn(ls=[1]):
ls.append(2)
return ls

print(fn())
print(fn())
```
```bash
[1, 2]
[1, 2, 2]
```

Второй вызов функции привел к результату, отличающемуся от первого вызова. Почему так произошло? Значение `ls` по умолчанию мы объявили равным `[1]`. Оба вызова используют значение по умолчанию. Но при втором вызове в данном случае произошло обращение к тому же списку, который был создан в качестве значения по умолчанию при первом вызове. Как это можно проверить?

В Python определена встроенная функция [id](https://docs.python.org/3/library/functions.html#id). Она возвращает целочисленный идентификатор объекта (уникальный и постоянный, пока объект существует). Используем ее, чтобы посмотреть идентификаторы списков.

```python linenums="1"
def fn_with_id(ls=[1]):
print(id(ls))
ls.append(2)
return ls

print(fn_with_id())
print(fn_with_id())
print(fn_with_id([3]))
print(fn_with_id())
```
```bash
123928376604123
[1, 2]
123928376604123
[1, 2, 2]
113928976643254
[3, 2]
123928376604123
[1, 2, 2, 2]
```

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

Одним из решений может быть следующее:

```python linenums="1"
def fixed_fn(ls=None):
if ls is None:
return [2]

ls.append(2)
return ls

print(fixed_fn())
print(fixed_fn())
print(fixed_fn([1]))
print(fixed_fn())
```
```bash
[2]
[2]
[1, 2]
[2]
```

Обратите внимание, что с `set`-ом ситуация другая.

```python linenums="1"
def fn_with_set(_set=set()):
_set.add(2)
print(id(_set))
return _set

print(fn_with_set())
print(fn_with_set())
print(fn_with_set({3}))
print(fn_with_set())
```
```bash
140214028693696
{2}
140214028693696
{2}
129928985405920
{2, 3}
140214028693696
{2}
```


## Анонимные функции

Функции, определенные при помощи `def`, имеют название, по которому их можно вызвать, но также существуют и анонимные или неименованные функции. Такие функции могут быть определены при помощи оператора `lambda`. Он позволяет задать входные и выходные данные. Самостоятельно можете почитать [документацию](https://docs.python.org/3/reference/expressions.html#grammar-token-lambda-expr).
Expand All @@ -537,7 +629,7 @@ lambda x: abs(x)

lambda num, div=2: "нет" if num % div else "да"
```
```
```bash
<function __main__.<lambda>(num, div=2)>
```

Expand All @@ -555,7 +647,7 @@ print(check_div(3), check_div(5, 5))
# Возможен вызов и без сохранения в переменную
print((lambda x: abs(x))(-120))
```
```
```bash
нет да
120
```
Expand All @@ -567,7 +659,7 @@ print((lambda x: abs(x))(-120))
```python linenums="1"
list(map(lambda x: x**2, [1, 2, 3]))
```
```
```bash
[1, 4, 9]
```

Expand All @@ -579,7 +671,7 @@ list(map(lambda x: x**2, [1, 2, 3]))
perform_computation = lambda: 2 ** 10_000_000 / 2 ** 10_000_000
perform_computation()
```
```
```bash
1.0
```

Expand Down Expand Up @@ -628,7 +720,7 @@ many_arg_sum = time_decorator(many_arg_sum)
# Поведение функции поменялось, а код вызова — нет
summed = many_arg_sum(10, 0, -120, 333)
```
```
```bash
Прошло 1.9073486328125e-06 секунд
```

Expand All @@ -644,7 +736,7 @@ def primitive_exponentiation(x, power=5):

powered = primitive_exponentiation(10)
```
```
```bash
Прошло 4.0531158447265625e-06 секунд
```

Expand Down