📖 Теория: повторение уроков 60–62

⚡ Кратко

Урок 60 — регулярные выражения: re, сырые строки, классы, квантификаторы, якоря, группы. Урок 61 — закрепление на практике. Урок 62 — вложенные функции, области видимости, nonlocal, замыкания, декораторы.

  • Регулярные выражения описывают шаблоны для поиска в тексте.
  • Вложенная функция видит переменные внешней через Enclosing-область.
  • Замыкание сохраняет переменные внешней функции после её завершения.

Регулярные выражения

Регулярные выражения (RegEx) — это инструмент для поиска, сравнения, замены и проверки строк по заданному шаблону. В Python они реализованы в модуле re.

Зачем нужны

  • Проверка формата строки (email, телефон, дата).
  • Поиск текста по шаблону.
  • Разделение строки на части.
  • Замена текста.

Основные функции модуля re

ФункцияНазначение
re.search(pattern, string)Первое совпадение шаблона в любой части строки
re.match(pattern, string)Проверка, начинается ли строка с шаблона
re.findall(pattern, string)Список всех совпадений
re.finditer(pattern, string)Итератор объектов Match для всех совпадений
re.sub(pattern, repl, string)Замена совпадений на строку или результат функции
re.split(pattern, string)Разделение строки по шаблону
re.compile(pattern)Компиляция шаблона для повторного использования

Сырые строки

В регулярных выражениях много обратных слэшей. Python обрабатывает \ как управляющий символ, поэтому шаблоны рекомендуется писать в «сырых» строках: r"...".

import re

# Без r строка \d превратится в управляющую последовательность
pattern = r"\d+"
print(re.findall(pattern, "Price: 123"))  # ['123']

Специальные символы

СимволЗначение
\dЛюбая цифра (0–9)
\DЛюбой символ, кроме цифры
\wБуквы, цифры и подчёркивание
\WЛюбой символ, кроме \w
\sПробельный символ (пробел, \t, \n)
\SЛюбой непробельный символ
.Любой символ, кроме \n

Классы символов

Классы символов задаются квадратными скобками [...] и позволяют искать любой из указанных символов.

ЗаписьЗначение
[abc]Один из символов a, b или c
[0-9]Любая цифра
[a-z]Любая строчная буква
[A-Z]Любая заглавная буква
[^0-9]Всё, кроме цифр

Квантификаторы

Квантификаторы задают количество повторений.

КвантификаторЗначение
+Один или более раз
*Ноль или более раз
?Ноль или один раз
{n}Ровно n раз
{n,}n и более раз
{n,m}От n до m раз

По умолчанию квантификаторы жадные: они захватывают максимально возможное количество символов. Чтобы сделать их ленивыми, добавьте ?.

import re

text = "<div>Hello</div><div>World</div>"
print(re.findall(r"<.*>", text))   # ['<div>Hello</div><div>World</div>'] — жадно
print(re.findall(r"<.*?>", text))  # ['<div>', '</div>', '<div>', '</div>'] — лениво

Якоря

ЯкорьЗначение
^Начало строки
$Конец строки
\bГраница слова
\BНе граница слова

Группы и альтернативы

Круглые скобки (...) объединяют часть шаблона в группу. С их помощью можно извлекать подстроки. Негруппирующие скобки (?:...) нужны только для логики. Оператор | задаёт альтернативы.

import re

text = "Meeting on 2024-05-10 or 10/05/2024 at 14:30"
dates = re.findall(r"(\d{4}-\d{2}-\d{2}|\d{2}/\d{2}/\d{4})", text)
print(dates)  # ['2024-05-10', '10/05/2024']

Вложенные функции и области видимости

В Python функция может быть определена внутри другой функции. Такая функция называется вложенной (nested). Она не доступна снаружи внешней функции.

def outer_function():
    print("Inside outer function")

    def inner_function():
        print("Inside inner function")

    inner_function()


outer_function()
# inner_function()  # NameError

Правило LEGB

Python ищет имена в следующем порядке:

  1. Local — локальная область текущей функции.
  2. Enclosing — ближайшая внешняя функция.
  3. Global — глобальная область модуля.
  4. Built-in — встроенные имена.

nonlocal

Если вложенная функция должна изменить переменную внешней функции, используйте nonlocal. Без него присваивание создаст новую локальную переменную.

def outer_function():
    message = "Outer function"

    def inner_function():
        nonlocal message
        message = "Changed inside inner function"

    inner_function()
    print(message)


outer_function()  # Changed inside inner function

Замыкания

Замыкание (closure) — это объект, содержащий функцию и сохранённое окружение: переменные из Enclosing-области, которые остаются доступными даже после завершения внешней функции.

def counter():
    count = 0

    def increment() -> int:
        nonlocal count
        count += 1
        return count

    return increment


counter_function = counter()
print(counter_function())  # 1
print(counter_function())  # 2
print(counter_function())  # 3

Декораторы

Декоратор — это функция, которая принимает другую функцию, добавляет поведение и возвращает новую функцию. Внутри используется вложенная функция-обёртка, поэтому декораторы строятся на замыканиях.

def simple_decorator(func):
    def wrapper():
        print("Before call")
        func()
        print("After call")
    return wrapper


@simple_decorator
def say_hello():
    print("Hello!")


say_hello()

Функция как объект

У функций есть служебные атрибуты, к которым можно обращаться напрямую.

def greet():
    """Greeting function."""
    print("Hello!")


print(greet.__name__)  # greet
print(greet.__doc__)   # Greeting function.