Практикум: создание пяти приложений на Python

Раздел: Python -> Практические примеры

Практические примеры программ на Python

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

Основное решение: использование среза для разворота строки и сравнения с оригиналом. Этот подход лаконичен и эффективен.
def is_palindrome(s):
    s = s.lower().replace(' ', '')
    return s == s[::-1]

print(is_palindrome("А роза упала на лапу Азора"))  # True

пять программ на языке python (пять примеров программ на python)

Вариант 1: решение с циклом.

Как реализовать проверку без создания новой строки?

def is_palindrome_loop(s):
    s = ''.join(filter(str.isalnum, s)).lower()
    left, right = 0, len(s) - 1
    while left < right:
        if s[left] != s[right]:
            return False
        left += 1
        right -= 1
    return True

print(is_palindrome_loop("Madam, I'm Adam"))  # True
Вариант 2: использование рекурсии.

Как применить рекурсивный подход?

def is_palindrome_rec(s):
    s = ''.join(c.lower() for c in s if c.isalnum())
    if len(s) <= 1:
        return True
    if s[0] != s[-1]:
        return False
    return is_palindrome_rec(s[1:-1])

print(is_palindrome_rec("No 'x' in Nixon"))  # True
Типичные ошибки: - Не учитывается регистр: "Hello" != "olleh". Решение: привести к нижнему регистру. - Не удаляются пробелы и знаки препинания: "А роза упала на лапу Азора" содержит пробелы. Решение: отфильтровать только буквы и цифры. - Проблема с пустой строкой: '' возвращает True, что корректно. - Для длинных строк рекурсия может вызвать RecursionError.

Как создать надёжный случайный пароль с заданными параметрами?

Основное решение: использование модуля random и строк констант.
import random
import string

def generate_password(length=12):
    characters = string.ascii_letters + string.digits + string.punctuation
    return ''.join(random.choice(characters) for _ in range(length))

print(generate_password(16))  # Пример: 'Kj2@#dL9&xP7%zQw'
Вариант 1: пароль с гарантированным включением каждого типа символов.

Как обеспечить наличие букв, цифр и спецсимволов?

import random
import string

def generate_strong_password(length=12):
    if length < 4:
        raise ValueError("Длина пароля должна быть не менее 4")
    # Обязательно по одному символу каждого типа
    required = [
        random.choice(string.ascii_lowercase),
        random.choice(string.ascii_uppercase),
        random.choice(string.digits),
        random.choice(string.punctuation)
    ]
    remaining = length - 4
    all_chars = string.ascii_letters + string.digits + string.punctuation
    rest = [random.choice(all_chars) for _ in range(remaining)]
    password_list = required + rest
    random.shuffle(password_list)
    return ''.join(password_list)

print(generate_strong_password(12))  # Пример: 'A3$bC9!kLmN2'
Вариант 2: использование модуля secrets для криптографически стойкой генерации.

Как создать пароль, устойчивый к взлому?

import secrets
import string

def generate_secure_password(length=12):
    alphabet = string.ascii_letters + string.digits + string.punctuation
    return ''.join(secrets.choice(alphabet) for _ in range(length))

print(generate_secure_password(20))  # Пример: '7&xYz#PqR2!wEoL0AbC'
Распространённые ошибки: - Использование random для паролей: random не является криптостойким, для серьёзных целей нужен secrets. - Слишком короткая длина: менее 8 символов легко подбирается. - Отсутствие проверки на наличие всех категорий символов: пароль может состоять только из букв. - Кодировка: при использовании punctuation в некоторых локалях могут быть непечатные символы.

Как вычислить последовательность чисел Фибоначчи до n-го элемента?

Основное решение: итеративный метод с использованием цикла. Это эффективно и не вызывает переполнения стека.
def fibonacci(n):
    a, b = 0, 1
    for _ in range(n):
        yield a
        a, b = b, a + b

print(list(fibonacci(10)))  # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
Вариант 1: рекурсивная реализация с мемоизацией.

Как использовать кэширование для ускорения рекурсии?

from functools import lru_cache

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

print([fib_rec(i) for i in range(10)])  # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
Вариант 2: через матричное возведение в степень (быстрый алгоритм).

Как вычислить большое число Фибоначчи за O(log n)?

import numpy as np

def fib_matrix(n):
    M = np.array([[1, 1], [1, 0]], dtype=object)
    result = np.linalg.matrix_power(M, n)
    return result[0, 1]

print(fib_matrix(10))  # 55
Возможные проблемы: - Чистая рекурсия без мемоизации приводит к экспоненциальной сложности (O(2^n)) и переполнению стека для n > 30. - Итеративный метод даёт O(n) по времени и O(1) памяти, но для больших n числа становятся огромными, требуется поддержка длинной арифметики (в Python это встроено). - Матричный метод использует numpy, который может быть избыточен, и для больших n требуется dtype=object, что замедляет.

Как отсортировать список чисел методом пузырька с визуализацией процесса?

Основное решение: классическая реализация с двумя вложенными циклами.
def bubble_sort(arr):
    n = len(arr)
    for i in range(n):
        for j in range(0, n-i-1):
            if arr[j] > arr[j+1]:
                arr[j], arr[j+1] = arr[j+1], arr[j]

data = [64, 34, 25, 12, 22, 11, 90]
bubble_sort(data)
print(data)  # [11, 12, 22, 25, 34, 64, 90]
Вариант 1: оптимизация с флагом для преждевременного выхода.

Как улучшить пузырьковую сортировку при частично отсортированных данных?

def bubble_sort_opt(arr):
    n = len(arr)
    for i in range(n):
        swapped = False
        for j in range(0, n-i-1):
            if arr[j] > arr[j+1]:
                arr[j], arr[j+1] = arr[j+1], arr[j]
                swapped = True
        if not swapped:
            break

data = [1, 2, 3, 4, 5, 6]
bubble_sort_opt(data)
print(data)  # [1, 2, 3, 4, 5, 6] (не меняет)
Вариант 2: рекурсивная реализация пузырьковой сортировки.

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

def bubble_sort_rec(arr, n=None):
    if n is None:
        n = len(arr)
    if n == 1:
        return
    for i in range(n-1):
        if arr[i] > arr[i+1]:
            arr[i], arr[i+1] = arr[i+1], arr[i]
    bubble_sort_rec(arr, n-1)

data = [64, 34, 25, 12, 22, 11, 90]
bubble_sort_rec(data)
print(data)  # [11, 12, 22, 25, 34, 64, 90]
Частые ошибки: - Выход за границы индекса: условие j+1 может выйти за len(arr)-1, если не использовать n-i-1. - Ошибка в условии обмена: сравнение должно быть по возрастанию/убыванию. - Пузырьковая сортировка неэффективна для больших наборов (O(n^2)), лучше использовать встроенную sort() или Timsort.

Как загрузить все изображения с указанной веб-страницы на локальный диск?

Основное решение: использование библиотек requests и BeautifulSoup для парсинга и скачивания.
import requests
from bs4 import BeautifulSoup
import os

def download_images(url, folder='images'):
    os.makedirs(folder, exist_ok=True)
    response = requests.get(url)
    soup = BeautifulSoup(response.text, 'html.parser')
    img_tags = soup.find_all('img')
    for i, img in enumerate(img_tags):
        img_url = img.get('src')
        if not img_url.startswith('http'):
            # относительная ссылка
            from urllib.parse import urljoin
            img_url = urljoin(url, img_url)
        try:
            img_data = requests.get(img_url).content
            with open(f'{folder}/image_{i}.jpg', 'wb') as f:
                f.write(img_data)
        except Exception as e:
            print(f'Ошибка при скачивании {img_url}: {e}')

download_images('https://example.com')
Вариант 1: асинхронное скачивание для ускорения.

Как параллельно загружать много изображений?

import asyncio
import aiohttp
import aiofiles
from bs4 import BeautifulSoup
import os

async def download_one(session, img_url, folder, index):
    async with session.get(img_url) as resp:
        if resp.status == 200:
            async with aiofiles.open(f'{folder}/image_{index}.jpg', 'wb') as f:
                await f.write(await resp.read())

async def download_images_async(url, folder='images'):
    os.makedirs(folder, exist_ok=True)
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            html = await resp.text()
        soup = BeautifulSoup(html, 'html.parser')
        img_tags = soup.find_all('img')
        tasks = []
        for i, img in enumerate(img_tags):
            img_url = img.get('src')
            if not img_url.startswith('http'):
                from urllib.parse import urljoin
                img_url = urljoin(url, img_url)
            tasks.append(download_one(session, img_url, folder, i))
        await asyncio.gather(*tasks)

# asyncio.run(download_images_async('https://example.com'))
Вариант 2: сохранение с оригинальными именами файлов.

Как сохранить изображения с оригинальными названиями?

import requests
from bs4 import BeautifulSoup
import os
from urllib.parse import urlparse

def download_images_named(url, folder='images'):
    os.makedirs(folder, exist_ok=True)
    response = requests.get(url)
    soup = BeautifulSoup(response.text, 'html.parser')
    img_tags = soup.find_all('img')
    for img in img_tags:
        img_url = img.get('src')
        if not img_url.startswith('http'):
            from urllib.parse import urljoin
            img_url = urljoin(url, img_url)
        # извлечь имя файла
        parsed = urlparse(img_url)
        filename = os.path.basename(parsed.path)
        if not filename:
            filename = f'image_{img_tags.index(img)}.jpg'
        save_path = os.path.join(folder, filename)
        if not os.path.exists(save_path):
            try:
                img_data = requests.get(img_url).content
                with open(save_path, 'wb') as f:
                    f.write(img_data)
            except Exception as e:
                print(f'Ошибка: {e}')

download_images_named('https://example.com')
Типичные ошибки: - Отсутствие обработки относительных ссылок: img src может быть "/images/photo.jpg". Использовать urljoin. - Неправильные коды ответов сервера (404, 403): проверять статус. - Ограничения по количеству запросов: сервер может блокировать. Добавлять задержки. - Отсутствие папки для сохранения: создать через os.makedirs(exist_ok=True). - Конфликт имён: если несколько изображений имеют одинаковое имя, перезаписываются. В варианте 2 добавлена проверка существования, но лучше использовать уникальные имена.

Расширенные примеры и нестандартные подходы

Дополнительные методы для палиндрома

Пример
import re
def is_palindrome_regex(s):
    s = re.sub(r'[^a-zA-Zа-яА-Я0-9]', '', s).lower()
    return all(s[i] == s[-i-1] for i in range(len(s)//2))

print(is_palindrome_regex("Was it a car or a cat I saw?"))  # True

Оценка энтропии пароля

Пример
import string
import secrets
import math

def estimate_entropy(password):
    pool = 0
    if any(c.islower() for c in password):
        pool += 26
    if any(c.isupper() for c in password):
        pool += 26
    if any(c.isdigit() for c in password):
        pool += 10
    if any(c in string.punctuation for c in password):
        pool += len(string.punctuation)
    entropy = len(password) * math.log2(pool) if pool else 0
    return entropy

password = ''.join(secrets.choice(string.ascii_letters + string.digits + string.punctuation) for _ in range(16))
print(f'Пароль: {password}, энтропия: {estimate_entropy(password):.2f} бит')

Формула Бине для чисел Фибоначчи

Пример
import math
def fib_binet(n):
    phi = (1 + math.sqrt(5)) / 2
    return int((phi**n - (1-phi)**n) / math.sqrt(5))
print(fib_binet(10))  # 55

Визуализация шагов пузырьковой сортировки через генератор

Пример
def bubble_sort_steps(arr):
    n = len(arr)
    for i in range(n):
        for j in range(0, n-i-1):
            if arr[j] > arr[j+1]:
                arr[j], arr[j+1] = arr[j+1], arr[j]
                yield arr

data = [5, 3, 8, 2]
for step in bubble_sort_steps(data):
    print(step)  # вывод каждого шага
[3, 5, 8, 2]
[3, 5, 8, 2]
[3, 5, 2, 8]
[3, 5, 2, 8]
[3, 2, 5, 8]
[2, 3, 5, 8]

Сохранение метаданных изображений в CSV

Пример
import requests
from bs4 import BeautifulSoup
import csv
from PIL import Image
from io import BytesIO

def download_images_metadata(url, csv_path='metadata.csv'):
    response = requests.get(url)
    soup = BeautifulSoup(response.text, 'html.parser')
    with open(csv_path, 'w', newline='', encoding='utf-8') as f:
        writer = csv.writer(f)
        writer.writerow(['URL', 'Width', 'Height', 'Format'])
        for img in soup.find_all('img'):
            img_url = img.get('src')
            if not img_url.startswith('http'):
                from urllib.parse import urljoin
                img_url = urljoin(url, img_url)
            try:
                r = requests.get(img_url)
                img_data = Image.open(BytesIO(r.content))
                writer.writerow([img_url, img_data.width, img_data.height, img_data.format])
            except Exception as e:
                writer.writerow([img_url, 'Error', 'Error', str(e)])

download_images_metadata('https://example.com')

пять примеров программ на Python - comments

En
пять программ на языке python (python)