Функциональные возможности Python: глубокое погружение в код

Раздел: Прочее -> Написание кода

Основы работы с функциями в Python

Стандартное определение функции

Наиболее распространённый способ создания функции в Python - использование ключевого слова def. Такой подход позволяет задать имя, параметры и тело функции, а также возвращать результат с помощью return. Это решение эффективно для большинства задач, так как обеспечивает читаемость и возможность повторного использования.

def sum_numbers(a, b):
    '''Возвращает сумму двух чисел.'''
    return a + b

result = sum_numbers(5, 3)
print(result)  # 8

Python код (код на python)

Пояснение: после def указывается имя функции, в скобках - параметры, затем двоеточие и тело с отступом. Документация в тройных кавычках - хорошая практика.

Типичная ошибка: забыть двоеточие в конце строки с def. Это вызовет синтаксическую ошибку SyntaxError. Также стоит помнить, что если функция не содержит return, она возвращает None.

Как создать анонимную функцию?

Если требуется короткая функция без имени, используется lambda. Она состоит из единственного выражения и не содержит операторов. Применяется в качестве аргумента для функций высшего порядка, таких как map, filter, sorted.

add = lambda x, y: x + y
print(add(2, 3))  # 5

# Пример с filter
numbers = [1, 2, 3, 4, 5]
even = list(filter(lambda n: n % 2 == 0, numbers))
print(even)  # [2, 4]

Ограничение: lambda не может содержать присваивания, циклы или несколько выражений. Для сложной логики следует использовать def. Также сложно отлаживать, так как имя функции отсутствует в трассировке.

Как передать произвольное количество аргументов?

Для этих целей служат *args (позиционные) и **kwargs (именованные). Это удобно при создании обёрток или функций, количество параметров которых заранее неизвестно.

def sum_all(*args):
    return sum(args)

print(sum_all(1, 2, 3, 4))  # 10

def print_info(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_info(name="Alice", age=30)

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

Как задать значения параметров по умолчанию?

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

def greet(name, greeting="Привет"):
    return f"{greeting}, {name}!"

print(greet("Иван"))            # Привет, Иван!
print(greet("Мария", "Здравствуйте"))  # Здравствуйте, Мария!

Опасная практика: использование изменяемого объекта (список, словарь) в качестве значения по умолчанию. Этот объект создаётся один раз при определении функции и будет общим для всех вызовов, что приводит к неожиданному поведению.

Как изменить поведение функции без изменения её кода?

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

def logger(func):
    def wrapper(*args, **kwargs):
        print(f"Вызов {func.__name__} с аргументами {args}")
        return func(*args, **kwargs)
    return wrapper

@logger
def multiply(a, b):
    return a * b

print(multiply(3, 4))  # Вызов multiply с аргументами (3, 4) \n 12

Проблема: декоратор скрывает метаданные исходной функции (имя, документацию). Решение: использовать functools.wraps для копирования метаданных.

Расширенные примеры функций Python

1. Рекурсивный факториал

Функция, вызывающая саму себя, называется рекурсивной. Рассмотрим вычисление факториала. Важно следить за базовым случаем и глубиной рекурсии.

Пример
def factorial(n):
    if n == 0:
        return 1
    return n * factorial(n - 1)

print(factorial(5))  # 120
120

Пояснение: при n=0 возвращается 1, иначе вызывается factorial(n-1). Глубина рекурсии ограничена (по умолчанию 1000). Для больших значений лучше использовать итеративный подход.

2. Замыкание для создания счетчика

Замыкание - это функция, которая запоминает состояние внешней функции даже после её завершения. Пример: генератор последовательных номеров.

Пример
def make_counter():
    count = 0
    def counter():
        nonlocal count
        count += 1
        return count
    return counter

c1 = make_counter()
print(c1())  # 1
print(c1())  # 2
c2 = make_counter()
print(c2())  # 1 (независимый счётчик)
1
2
1

3. Декоратор с аргументами (повторение вызова)

Иногда требуется декоратор, который принимает собственные параметры. Реализация через дополнительный уровень вложенности.

Пример
def repeat(num_times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(num_times):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(3)
def say_hello():
    print("Hello!")

say_hello()  # Hello! Hello! Hello!
Hello!
Hello!
Hello!

4. Частичное применение (functools.partial)

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

Пример
from functools import partial

def power(base, exp):
    return base ** exp

square = partial(power, exp=2)
cube = partial(power, exp=3)

print(square(5))  # 25
print(cube(5))    # 125
25
125

5. Генераторная функция (yield)

Функция, использующая yield, возвращает итератор, который генерирует последовательность значений по одному, экономя память.

Пример
def fibonacci(limit):
    a, b = 0, 1
    while a < limit:
        yield a
        a, b = b, a + b

for num in fibonacci(100):
    print(num, end=' ')
0 1 1 2 3 5 8 13 21 34 55 89

6. Мемоизация (кэширование результатов)

Декоратор, который запоминает результаты вызовов функции для заданных аргументов. Ускоряет рекурсивные вычисления, например, чисел Фибоначчи.

Пример
from functools import lru_cache

@lru_cache(maxsize=None)
def fib(n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)

print(fib(100))  # 354224848179261915075
354224848179261915075

Код на Python - comments

En
Python код (python)