Практикум: создание пяти приложений на 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)