# Функции и их особенности

### **1. Что такое функция**

* **Функция** — это блок кода, который выполняет определённое действие и может возвращать результат.
* Определяется с помощью ключевого слова `def` или `lambda` (анонимные функции).

```python
def add(a, b):
    return a + b
```

***

### **2. Особенности функций в Python**

#### **2.1 Аргументы функций**

* **Позиционные**: передаются по порядку.
* **Именованные**: передаются по имени.
* **По умолчанию**: если не указаны, берутся значения по умолчанию.
* **`*args`**: кортеж всех дополнительных позиционных аргументов.
* **`**kwargs`**: словарь всех дополнительных именованных аргументов.

```python
def foo(a, b=2, *args, **kwargs):
    print(a, b, args, kwargs)

foo(1, 3, 4, 5, x=10, y=20)
# 1 3 (4, 5) {'x': 10, 'y': 20}
```

***

#### **2.2 Возврат значений**

* Через `return`.
* Если `return` нет — возвращается `None`.

```python
def greet(name):
    print(f"Hello, {name}")

result = greet("Alice")  # вывод Hello, Alice
print(result)            # None
```

***

#### **2.3 Функции как объекты**

* Функции — это объекты Python, их можно передавать как аргументы, присваивать переменным, хранить в списках.

```python
def square(x):
    return x*x

func = square
print(func(5))  # 25
```

***

#### **2.4 Анонимные функции (`lambda`)**

* Однострочные функции без имени.
* Используются для коротких операций, сортировки, фильтрации.

```python
square = lambda x: x*x
print(square(4))  # 16
```

***

#### **2.5 Вложенные функции**

* Функции можно определять внутри других функций.
* Позволяет инкапсулировать логику и использовать замыкания.

```python
def outer(x):
    def inner(y):
        return x + y
    return inner

f = outer(5)
print(f(3))  # 8
```

***

#### **2.6 Декораторы**

* Позволяют **оборачивать функцию** для изменения её поведения.
* Используются для логирования, тайминга, проверки прав доступа.

```python
def decorator(func):
    def wrapper():
        print("Before")
        func()
        print("After")
    return wrapper

@decorator
def say_hello():
    print("Hello")

say_hello()
# Before
# Hello
# After
```

***

#### **2.7 Документирование**

* Через **docstring**.
* Позволяет видеть описание функции через `help()`.

```python
def add(a, b):
    """Возвращает сумму a и b"""
    return a + b
```

***

#### **2.8 Рекурсия**

* Функция может вызывать саму себя.
* Важна базовая ветка выхода, иначе — `RecursionError`.

```python
def factorial(n):
    if n == 0:
        return 1
    return n * factorial(n-1)
```
