Kodduu Python
1.08K subscribers
311 photos
28 videos
186 links
Научись программировать на Python на интересных примерах

Самый быстрый курс https://stepik.org/a/187914
Самый нескучный курс https://stepik.org/a/185238

Во вопросам сотрудничества: @AlexErf
Download Telegram
Вот интересный и полезный лайфхак на чистом Python: реализация LRU (Least Recently Used) кэша без использования дополнительных библиотек.

### Что это?
LRU-кэш сохраняет результаты вызовов функций для ускорения последующих вычислений. Если кэш переполняется, удаляется самый "старый" элемент.

---

### Реализация LRU-кэша:

from collections import deque

class LRUCache:
def __init__(self, capacity: int):
self.cache = {} # Хранение данных
self.order = deque() # Порядок использования
self.capacity = capacity

def get(self, key):
if key not in self.cache:
return -1 # Если ключ не найден
# Обновляем порядок использования
self.order.remove(key)
self.order.append(key)
return self.cache[key]

def put(self, key, value):
if key in self.cache:
# Обновляем значение и порядок использования
self.order.remove(key)
elif len(self.cache) >= self.capacity:
# Удаляем самый старый элемент
oldest_key = self.order.popleft()
del self.cache[oldest_key]
# Добавляем новый элемент
self.cache[key] = value
self.order.append(key)

# Пример использования
cache = LRUCache(3)
cache.put(1, "A") # Добавляем ключ 1
cache.put(2, "B") # Добавляем ключ 2
cache.put(3, "C") # Добавляем ключ 3

print(cache.get(1)) # "A" - обновляем порядок ключа 1
cache.put(4, "D") # Добавляем ключ 4, удаляем самый старый (ключ 2)

print(cache.get(2)) # -1 (удалён из-за переполнения)
print(cache.get(3)) # "C"
print(cache.get(4)) # "D"


---

### Как это работает:
1. Кэш:
- Хранит значения по ключам.
- self.cache — словарь для хранения данных.
2. Порядок использования:
- deque отслеживает порядок добавления/обновления ключей.
- Если кэш переполняется, удаляется элемент, добавленный раньше всех.
3. Методы:
- get: Возвращает значение по ключу и обновляет порядок.
- put: Добавляет новый элемент, удаляя самый старый при необходимости.

---

### Чем полезно:
- Позволяет ускорить функции, повторяющие одни и те же вычисления.
- Это компактная реализация кэша без использования библиотек, которая полезна в ограниченных средах.

Подпишись 👉🏻 @KodduuPython 🤖
👍5
Проблема, связанная с переходом на 2000 год (известная как Y2K), возникала из-за хранения годов в виде двух цифр вместо четырёх, что приводило к ошибкам в вычислениях и интерпретации дат. Вот пример кода, демонстрирующего подобную проблему:


from datetime import datetime

# Демонстрация хранения года в виде двух цифр
def process_date(two_digit_year):
try:
# Преобразуем дату с фиксированным форматом
date = datetime.strptime(f"01-01-{two_digit_year}", "%d-%m-%y")
return date
except ValueError as e:
return f"Ошибка обработки даты: {e}"

# Пример с корректной интерпретацией дат
print(process_date("99")) # Ожидается: 1999
print(process_date("00")) # Проблема: интерпретируется как 2000

# Пример возможной ошибки
print(process_date("50")) # В интервале 1950-2049 интерпретируется как 2050
print(process_date("49")) # Интерпретируется как 1949


### Объяснение:
1. В datetime.strptime двухзначный год (`%y`) интерпретируется следующим образом:
- Если год в диапазоне 00-68, он считается частью 2000-х годов (например, 00 = 2000, 50 = 2050).
- Если год в диапазоне 69-99, он считается частью 1900-х годов (например, 99 = 1999).

### Возможные проблемы:
1. Неправильная интерпретация годов, выходящих за рамки 1900-2099.
2. Зависимость от правил интерпретации двухзначных годов, которые могут быть разными в других системах.

#### Исправление:
Всегда использовать четырёхзначный формат года (`%Y`), чтобы избежать таких проблем:


def process_date(four_digit_year):
try:
date = datetime.strptime(f"01-01-{four_digit_year}", "%d-%m-%Y")
return date
except ValueError as e:
return f"Ошибка обработки даты: {e}"

# Теперь даты интерпретируются корректно
print(process_date("1999"))
print(process_date("2000"))
print(process_date("2050"))


Подпишись 👉🏻 @KodduuPython 🤖
Проблема, связанная с миллисекундным отсчетом от определенной эпохи, известна как "Unix Y2K" или "2038 Year Problem". Эта проблема возникает из-за того, что в системах, использующих 32-битные целые числа со знаком для представления времени (например, количество секунд, прошедших с эпохи Unix — 1 января 1970 года), число переполняется 19 января 2038 года.

### Демонстрация проблемы "2038 года" в Python

В этом примере используется библиотека datetime, но мы специально ограничим время 32-битным целым числом, чтобы воспроизвести ошибку:


import time
from datetime import datetime, timedelta

# Симуляция 32-битного ограничения
def simulate_32bit_time(seconds_since_epoch):
# Ограничение на 32-битное значение со знаком (-2^31 до 2^31-1)
MAX_INT_32 = 2**31 - 1
MIN_INT_32 = -2**31

if not (MIN_INT_32 <= seconds_since_epoch <= MAX_INT_32):
raise OverflowError("Время вышло за пределы 32-битного диапазона!")

# Преобразуем в дату
return datetime(1970, 1, 1) + timedelta(seconds=seconds_since_epoch)

# Текущее время в секундах с 1 января 1970 года
current_time = int(time.time())
print("Текущее время:", simulate_32bit_time(current_time))

# Пример даты до переполнения
future_time = 2**31 - 1 # Максимальное значение для 32-битного числа
print("Дата на границе 32-битного диапазона:", simulate_32bit_time(future_time))

# Попытка перейти за границу 32-битного диапазона
try:
overflow_time = 2**31 # Переполнение
print("Дата после переполнения:", simulate_32bit_time(overflow_time))
except OverflowError as e:
print("Ошибка:", e)


### Объяснение:
1. Эпоха Unix: Отсчет времени начинается с 1 января 1970 года, 00:00:00 UTC.
2. 32-битное ограничение: Максимальное значение 32-битного целого числа со знаком — 2,147,483,647 секунд, что соответствует времени 19 января 2038 года, 03:14:07 UTC.
3. Переполнение: При превышении этого значения число переходит в отрицательное, что может быть интерпретировано как время в 1901 году.

### Выход из ситуации:
1. Использование 64-битных целых чисел для представления времени, что решает проблему до 292 млрд лет (в случае signed int).
2. Обновление всех систем, работающих с 32-битным временем.

### Пример безопасного решения:
Современные версии Python уже используют 64-битные значения для работы с временем, поэтому проблемы переполнения нет. Однако, в системах с жестким ограничением разрядности (например, встроенные системы) всё ещё может быть актуальной.

Подпишись 👉🏻 @KodduuPython 🤖
👍4👀1
Вот пример кода на Python, который демонстрирует Year 2107 Bug, связанную с ограничениями дат в файловой системе FAT32. Эта файловая система использует 7 бит для представления года (с 1980 года), поэтому максимальный год, который она может представить, — 2107.

### Пример кода:


import datetime

def fat32_date_encoding(year, month, day):
"""
Кодирование даты в формате FAT32.
"""
if not (1980 <= year <= 2107):
raise ValueError("Год должен быть в диапазоне от 1980 до 2107 для FAT32!")

# Вычисляем двоичный формат даты FAT32:
encoded_date = ((year - 1980) << 9) | (month << 5) | day
return encoded_date

def fat32_date_decoding(encoded_date):
"""
Декодирование даты из формата FAT32.
"""
year = 1980 + ((encoded_date >> 9) & 0x7F) # 7 бит на год
month = (encoded_date >> 5) & 0x0F # 4 бита на месяц
day = encoded_date & 0x1F # 5 бит на день
return datetime.date(year, month, day)

# Демонстрация
try:
# Кодируем дату 2107-12-31 (максимально возможная дата)
encoded_date = fat32_date_encoding(2107, 12, 31)
print(f"Дата 2107-12-31 закодирована как: {encoded_date:#018b}")

# Декодируем дату обратно
decoded_date = fat32_date_decoding(encoded_date)
print(f"Декодированная дата: {decoded_date}")

# Попытка закодировать дату за пределами допустимого диапазона
encoded_invalid_date = fat32_date_encoding(2108, 1, 1)
print(f"Дата 2108-01-01 закодирована как: {encoded_invalid_date:#018b}")

except ValueError as e:
print("Ошибка:", e)


### Объяснение:

1. Кодирование даты в FAT32:
- Год: Хранится в 7 битах (1980-2107).
- Месяц: Хранится в 4 битах (1-12).
- День: Хранится в 5 битах (1-31).
- Итоговое значение даты представляет 16-битное число.

2. Максимальная дата:
- Максимально возможный год — 2107.
- После 31 декабря 2107 года невозможно корректно представить дату, так как значение года переполняется.

3. Результат работы:
- Корректные даты (например, 2107-12-31) кодируются и декодируются без проблем.
- Попытка закодировать дату 2108-01-01 вызывает ошибку.

### Вывод:

Этот пример демонстрирует, как FAT32 использует ограниченное пространство для представления дат. После 2107 года все операции с датами будут некорректны. Это ограничение связано с жестко заданным форматом данных в FAT32, и для решения проблемы потребуется либо сменить файловую систему, либо обновить формат хранения метаданных.

Подпишись 👉🏻 @KodduuPython 🤖
Рекурсия — это мощный инструмент, но в Python её использование ограничено максимальной глубиной рекурсии, которая по умолчанию составляет 1000 уровней (можно узнать через `sys.getrecursionlimit()`). Это ограничение установлено для предотвращения переполнения стека вызовов, которое может привести к краху программы.

---

### Пример кода: Ограничение на рекурсию


import sys

# Посмотрим текущий лимит рекурсии
print("Текущий лимит рекурсии:", sys.getrecursionlimit())

# Пример рекурсивной функции
def recursive_function(n):
if n == 0:
return 0
return 1 + recursive_function(n - 1)

try:
# Попробуем вызвать рекурсию глубже, чем лимит
result = recursive_function(1500) # Увеличьте число, чтобы проверить лимит
print("Результат:", result)
except RecursionError as e:
print("Ошибка рекурсии:", e)


---

### Увеличение лимита рекурсии

Если нужно увеличить глубину рекурсии, можно использовать sys.setrecursionlimit(). Это может быть полезно в задачах, где необходимы глубокие рекурсивные вызовы (например, обходы деревьев).

#### Код с увеличением лимита:


# Установим новый лимит рекурсии
sys.setrecursionlimit(2000)
print("Новый лимит рекурсии:", sys.getrecursionlimit())

try:
# Теперь функция может углубиться больше
result = recursive_function(1500)
print("Результат:", result)
except RecursionError as e:
print("Ошибка рекурсии даже с увеличением лимита:", e)


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

---

### Итеративный подход как альтернатива рекурсии

Во многих случаях рекурсию можно заменить итерацией, что позволяет избежать ограничений стека.

#### Пример итеративной версии:


def iterative_function(n):
count = 0
while n > 0:
count += 1
n -= 1
return count

# Проверим итеративный метод на большом входном значении
result = iterative_function(15000)
print("Результат итеративной функции:", result)


---

### Практическое применение: Обход дерева

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

#### Пример:


# Рекурсивный обход дерева
class Node:
def __init__(self, value):
self.value = value
self.children = []

def recursive_tree_traversal(node):
print(node.value)
for child in node.children:
recursive_tree_traversal(child)

# Построим дерево
root = Node(1)
current = root
for i in range(2, 1500): # Глубокое дерево
new_node = Node(i)
current.children.append(new_node)
current = new_node

try:
recursive_tree_traversal(root)
except RecursionError as e:
print("Ошибка рекурсии при обходе дерева:", e)


#### Итеративный обход дерева:


def iterative_tree_traversal(node):
stack = [node]
while stack:
current = stack.pop()
print(current.value)
stack.extend(reversed(current.children)) # Добавляем детей в стек

# Обход дерева итеративно
iterative_tree_traversal(root)


---

### Вывод:
1. Рекурсия удобна, но ограничена глубиной, что делает её непрактичной для очень больших структур.
2. Увеличение лимита через sys.setrecursionlimit() может быть временным решением, но увеличивает риск краха программы.
3. Итеративные методы — более безопасная альтернатива для задач с большими объемами данных.

Подпишись 👉🏻 @KodduuPython 🤖
5👍2🔥1
Распродажи Stepik курсов и программ которые сгорят под бой курантов🎄Можно купить себе или подарить 🎁

1️⃣ Python: самый быстрый курс

2️⃣ Python Data Science: самый быстрый курс

👉 Junior Python Data Scientist (программа из курсов 1️⃣ и 2️⃣)

3️⃣ Python в нескучных примерах (50)

👉 Junior Python Developer and Data Scientist (программа из курсов 1️⃣, 2️⃣ и 3️⃣)

4️⃣ Топ 100 вопросов с реальных собеседований по Python (шпаргалка) 👉 бесплатный курс

5️⃣ Язык программирования BrainFuck или ВыносМозга! 👉 бесплатный курс

Подпишись 👉🏻 @KodduuPython 🤖
В Python концепция контекста реализована с помощью менеджеров контекста и ключевого слова with. Менеджеры контекста предоставляют способ работы с ресурсами (например, файлами, сетевыми соединениями или блокировками) и автоматически управляют их открытием и закрытием, даже в случае возникновения исключений.

---

### Пример: Использование менеджера контекста для работы с файлами


# Работа с файлом без менеджера контекста
file = open("example.txt", "w")
try:
file.write("Hello, World!")
finally:
file.close() # Закрываем файл вручную

# Работа с файлом через менеджер контекста
with open("example.txt", "w") as file:
file.write("Hello, World!") # Файл будет автоматически закрыт


---

### Пример: Создание собственного менеджера контекста

Для создания собственного менеджера контекста можно использовать класс с методами __enter__ и __exit__.


class MyContextManager:
def __enter__(self):
print("Входим в контекст")
return self # Можно вернуть объект, если нужно
def __exit__(self, exc_type, exc_value, traceback):
print("Выходим из контекста")
if exc_type:
print(f"Произошла ошибка: {exc_value}")
return True # Подавляет исключение, если нужно

# Используем менеджер контекста
with MyContextManager() as cm:
print("Внутри контекста")
raise ValueError("Что-то пошло не так") # Исключение будет обработано
print("Контекст завершен")


#### Результат:

Входим в контекст
Внутри контекста
Произошла ошибка: Что-то пошло не так
Выходим из контекста
Контекст завершен


---

### Пример: Менеджер контекста с использованием contextlib

Модуль contextlib предоставляет декоратор @contextmanager, упрощающий создание менеджеров контекста.


from contextlib import contextmanager

@contextmanager
def my_context():
print("Входим в контекст")
try:
yield "Ресурс" # Передаем управление блоку `with`
except Exception as e:
print(f"Произошла ошибка: {e}")
finally:
print("Выходим из контекста")

# Используем менеджер контекста
with my_context() as resource:
print(f"Используем {resource}")
raise RuntimeError("Пример ошибки")


#### Результат:

Входим в контекст
Используем Ресурс
Произошла ошибка: Пример ошибки
Выходим из контекста


---

### Пример: Контекст для блокировки ресурсов

Менеджеры контекста часто применяются для управления блокировками (например, с помощью `threading.Lock`).


import threading

lock = threading.Lock()

def critical_section():
with lock: # Блокировка автоматически освобождается после завершения блока
print(f"Поток {threading.current_thread().name} выполняет критическую секцию")

# Создание потоков
threads = [threading.Thread(target=critical_section) for _ in range(5)]

# Запуск потоков
for thread in threads:
thread.start()

for thread in threads:
thread.join()


---

### Вывод:
Контексты в Python позволяют безопасно управлять ресурсами, упрощая такие задачи, как открытие и закрытие файлов, управление соединениями или блокировками, и делают код чище и устойчивее к ошибкам.

Подпишись 👉🏻 @KodduuPython 🤖
5👍4
Работа с GPS в Python может быть выполнена с использованием модулей, таких как gpsd, pyserial или pynmea2. Эти модули позволяют подключаться к GPS-устройствам, получать данные о местоположении и разбирать их.

---

### Пример 1: Использование gpsd

gpsd — это сервер, который предоставляет данные от GPS-устройства. В Python можно использовать библиотеку gpsd-py3 для взаимодействия с gpsd.

#### Установка:

pip install gpsd-py3


#### Код:

import gpsd

# Подключаемся к gpsd
gpsd.connect()

# Получаем данные от GPS
packet = gpsd.get_current()

# Вывод информации о местоположении
if packet.mode >= 2: # Режим 2D или 3D
print(f"Широта: {packet.lat}")
print(f"Долгота: {packet.lon}")
if packet.mode == 3: # Режим 3D
print(f"Высота: {packet.alt}")
else:
print("Нет данных о местоположении")


---

### Пример 2: Использование pyserial для чтения данных NMEA

Данные от GPS-устройства часто передаются в формате NMEA (текстовый формат), который можно обработать вручную или с помощью библиотек, например, pynmea2.

#### Установка:

pip install pyserial pynmea2


#### Код:

import serial
import pynmea2

# Подключение к GPS через COM-порт (здесь используется примерный порт)
gps_port = "/dev/ttyUSB0" # Укажите порт вашего устройства
baud_rate = 9600 # Типичная скорость GPS
timeout = 5 # Тайм-аут

try:
# Открываем соединение
with serial.Serial(gps_port, baudrate=baud_rate, timeout=timeout) as ser:
print("Чтение данных от GPS...")

while True:
line = ser.readline().decode('ascii', errors='replace').strip()
if line.startswith('$GPGGA'): # Проверяем тип сообщения
msg = pynmea2.parse(line)
print(f"Широта: {msg.latitude} {msg.lat_dir}")
print(f"Долгота: {msg.longitude} {msg.lon_dir}")
print(f"Высота: {msg.altitude} {msg.altitude_units}")
except serial.SerialException as e:
print(f"Ошибка подключения к порту: {e}")
except pynmea2.ParseError as e:
print(f"Ошибка разбора NMEA данных: {e}")


---

### Пример 3: Работа с эмуляцией GPS

Для тестирования можно использовать файлы с NMEA-данными, которые эмулируют работу реального GPS. Такой подход полезен, если у вас нет физического устройства.

#### Тестовые данные (пример NMEA):

$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47


#### Код для эмуляции:

import pynmea2

# Пример NMEA-строки
nmea_data = "$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47"

# Разбор строки
try:
msg = pynmea2.parse(nmea_data)
print(f"Время: {msg.timestamp}")
print(f"Широта: {msg.latitude} {msg.lat_dir}")
print(f"Долгота: {msg.longitude} {msg.lon_dir}")
print(f"Высота: {msg.altitude} {msg.altitude_units}")
except pynmea2.ParseError as e:
print(f"Ошибка разбора NMEA данных: {e}")


---

### Вывод
Этот код демонстрирует, как получать и обрабатывать GPS-данные. В зависимости от вашего устройства и протокола взаимодействия, вы можете:
1. Использовать gpsd для высокоуровневого доступа к GPS.
2. Работать напрямую с портом через pyserial и разбирать данные в формате NMEA.
3. Эмулировать GPS-сигналы для тестирования.

Подпишись 👉🏻 @KodduuPython 🤖
👍6
Код 👆👆👆


import time
import os
import random

# Настройка размеров "экрана"
SCREEN_WIDTH = 40
SCREEN_HEIGHT = 20

# Новогодняя елка
TREE = [
" 🎄",
" 🎄🎄",
" 🎄🎄🎄",
" 🎄🎄🎄🎄",
" 🎄🎄🎄🎄🎄",
" 🎄🎄🎄🎄🎄🎄",
" 🎄🎄🎄🎄🎄🎄🎄",
" 🎄🎄🎄🎄🎄🎄🎄🎄",
" 🎄🎄🎄🎄🎄🎄🎄🎄🎄",
" ||",
" ||",
]

# Генерация начальных снежинок
snowflakes = [[random.randint(0, SCREEN_WIDTH - 1), random.randint(0, SCREEN_HEIGHT - 1)] for _ in range(50)]

# Функция рисования экрана
def draw_screen():
os.system('cls' if os.name == 'nt' else 'clear') # Очистка экрана

# Рисуем "снежный экран"
screen = [[" " for _ in range(SCREEN_WIDTH)] for _ in range(SCREEN_HEIGHT)]

# Добавляем снежинки
for flake in snowflakes:
x, y = flake
if 0 <= y < SCREEN_HEIGHT and 0 <= x < SCREEN_WIDTH:
screen[y][x] = "❄️"

# Рисуем елку
for i, line in enumerate(TREE):
if SCREEN_HEIGHT - len(TREE) + i >= 0:
screen[SCREEN_HEIGHT - len(TREE) + i][:len(line)] = line

# Вывод экрана
for row in screen:
print("".join(row))

# Главный цикл
try:
while True:
draw_screen()

# Обновляем положение снежинок
for flake in snowflakes:
flake[1] += 1 # Снежинка падает вниз
if flake[1] >= SCREEN_HEIGHT: # Перезапускаем снежинку сверху
flake[1] = 0
flake[0] = random.randint(0, SCREEN_WIDTH - 1)

# Добавляем задержку для анимации
time.sleep(0.2)

except KeyboardInterrupt:
print("\nС Новым Годом! 🎅🎁🎉")


Подпишись 👉🏻 @KodduuPython 🤖
7
This media is not supported in your browser
VIEW IN TELEGRAM
С наступающим 🎄❄️☃️ Сбычи мечт и много хорошего кода в новом 2025 году 🎁👩‍💻🧑‍💻

Подпишись 👉🏻 @KodduuPython 🤖
👍82🔥2
Не успели купить 🎁, подарите знания (любой курс можно подарить):

1️⃣ Python: самый быстрый курс

2️⃣ Python Data Science: самый быстрый курс

👉 Junior Python Data Scientist (программа из курсов 1️⃣ и 2️⃣)

3️⃣ Python в нескучных примерах (50)

👉 Junior Python Developer and Data Scientist (программа из курсов 1️⃣, 2️⃣ и 3️⃣)

4️⃣ Топ 100 вопросов с реальных собеседований по Python (шпаргалка) 👉 бесплатный курс

5️⃣ Язык программирования BrainFuck или ВыносМозга! 👉 бесплатный курс

Подпишись 👉🏻 @KodduuPython 🤖
👍41