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 концепция контекста реализована с помощью менеджеров контекста и ключевого слова 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
Ниже пример простого скрипта на Python, который собирает новогоднее поздравление из случайно выбранных слов и фраз. Его можно расширять, добавлять дополнительные списки или логику по своему вкусу.


import random

def generate_new_year_greeting():
"""
Генерирует новогоднее поздравление, выбирая слова из списков случайным образом.
"""

# Приветствия/начальные фразы
starts = [
"Поздравляю",
"Сердечно поздравляю",
"От всей души приветствую",
"С огромной радостью поздравляю"
]

# Прилагательные/эпитеты
adjectives = [
"счастливого",
"волшебного",
"радостного",
"прекрасного",
"блестящего"
]

# Основные пожелания
wishes = [
"здоровья",
"удачи",
"радости",
"любви",
"тепла",
"творческих успехов",
"исполнения всех желаний"
]

# Дополнительные фразы
extras = [
"чтобы каждый день был наполнен чудесами",
"пусть все мечты сбываются",
"желаю верить в себя и покорять любые вершины",
"пусть в сердце живёт только добро",
"и пусть этот год принесёт много ярких событий"
]

# Заключительные фразы/пожелания
endings = [
"С Новым годом!",
"Пусть в этом году будет всё на высоте!",
"Пусть в новом году будет только лучше!",
"С праздником!",
"Свершений и новых побед!"
]

# Собираем предложение
greeting = (
f"{random.choice(starts)} с наступившим {random.choice(adjectives)} Новым годом!\n\n"
f"Желаю {random.choice(wishes)}, {random.choice(wishes)}, а также {random.choice(wishes)}.\n"
f"И, конечно, {random.choice(extras)}.\n\n"
f"{random.choice(endings)}"
)

return greeting

def main():
# Генерируем и выводим поздравление
print(generate_new_year_greeting())

if __name__ == "__main__":
main()


### Как это работает:
1. Списки со словами и фразами: Для разных частей поздравления (`starts`, adjectives, wishes, extras, `endings`) заведены отдельные списки.
2. Модуль `random`: При помощи random.choice выбирается по одной фразе/слову из каждого списка.
3. Сборка текста: Формируем итоговую строку (`greeting`), используя f-строки с подстановками.
4. Вывод результата: Вызов print(generate_new_year_greeting()) выдаёт нам случайное поздравление на каждом запуске.

При желании можно:
- Добавить больше слов в списки.
- Формировать более сложные конструкции предложений.
- Сохранять поздравление в файл или отправлять его по электронной почте.

Подпишись 👉🏻 @KodduuPython 🤖
👍84
Ниже приведён шуточный пример кода на Python, который «оценивает», сколько салата «Оливье» было съедено во всём мире на Новый год. Все расчёты, конечно, условны и сделаны для иллюстрации, а не на основе реальной статистики.


import random

def estimate_olivier_eaten():
"""
Возвращает приблизительное (и шуточное) количество килограммов Оливье,
которые были съедены на планете в новогоднюю ночь.
"""

# (1) Численность населения (приблизительно, в миллиардах)
world_population = 8.05 # млрд (примерно к 2024 году)

# (2) Процент людей, отмечающих Новый год
# Условно предположим, что его празднуют 80% населения
celebrating_people_percent = 0.8

# (3) Процент любителей Оливье среди тех, кто празднует
# Пусть из празднующих минимум 50% едят Оливье
olivier_lovers_percent = 0.5

# (4) Средняя порция Оливье на человека (в граммах)
# Предположим 300 г на душу – кто-то съест больше, кто-то меньше
avg_portion_per_person_grams = 300

# (5) Считаем
# Сколько людей ест Оливье
number_of_olivier_eaters = world_population * 1_000_000_000 \
* celebrating_people_percent \
* olivier_lovers_percent

# Сколько всего граммов Оливье пришлось на этих людей
total_grams_olivier = number_of_olivier_eaters * avg_portion_per_person_grams

# Переводим в килограммы
total_kilos_olivier = total_grams_olivier / 1000

return total_kilos_olivier

def main():
# Получим оценку
kilos_olivier = estimate_olivier_eaten()

# Для «дополнительной реалистичности» внесём случайный разброс ±10%
# Ведь точное число никто не знает 🙂
fluctuation_percent = random.uniform(-0.1, 0.1)
kilos_olivier *= (1 + fluctuation_percent)

# Красиво форматируем число (например, с разделением разрядов)
result_str = f"{kilos_olivier:,.0f}" # округлим до целых
print(f"По приблизительным (шуточным) оценкам, в новогоднюю ночь "
f"на планете было съедено около {result_str} кг Оливье!")

if __name__ == "__main__":
main()


### Как работает код

1. Параметры «мировой» статистики
- world_population — приблизительная численность населения Земли в миллиардах.
- celebrating_people_percent — доля тех, кто отмечает Новый год.
- olivier_lovers_percent — доля тех, кто в праздничную ночь ест Оливье (из тех, кто вообще празднует).

2. Средняя порция
В примере для простоты взято \(300\) граммов на человека. Кто-то съедает больше, кто-то меньше — но пусть будет так.

3. Вычисление
- Находим общее число людей, которые (гипотетически) ели Оливье.
- Умножаем на 300 г.
- Переводим всё это в килограммы.

4. Случайный разброс
В коде мы добавляем ±10% (переменная `fluctuation_percent`), чтобы сделать оценку ещё менее «точной» и более шутливой.

5. Вывод
В main() печатаем итоговое «псевдо-число» в красиво отформатированном виде.

---

Это, конечно, не настоящее научное исследование, а лишь пример того, как можно реализовать в Python «виртуальный счётчик» чего угодно — например, салата Оливье в новогоднюю ночь.

Подпишись 👉🏻 @KodduuPython 🤖
51
Ниже приведён упрощённый пример на Python, демонстрирующий базовые идеи, которые могли использоваться для плановых расчётов в экономике (как, например, в СССР). Он не претендует на историческую точность и полноту, но иллюстрирует общий подход к задачам планирования с применением математической оптимизации.

---

Краткое введение в задачу

Предположим, что у нас есть несколько типов ресурсов (например, металл, дерево, электроэнергия и т.д.), и мы хотим произвести несколько видов товаров (станки, мебель, автомобили и т.д.). У каждого товара есть:
1. План по выпуску (то есть минимальное количество, которое нужно произвести по указу «сверху»).
2. Потребление ресурсов на единицу выпуска (например, один автомобиль требует 1 тонну металла, 10 кВт⋅ч электроэнергии и т.п.).
3. Ограниченное количество ресурсов, доступных в нашей «народно-хозяйственной» системе.

Основная задача: найти, сколько каждого вида товара нужно произвести, чтобы:
- Выполнить (или превысить) плановые задания (заказ государства).
- Не превысить доступные объёмы ресурсов.
- Максимизировать (или минимизировать) некую целевую функцию — например, суммарную “пользу” (удовлетворение потребностей народа / вклад в экономику).

В реальном СССР и других плановых экономиках задач было в разы больше и сложнее: расчёты производились по десяткам тысяч наименований продукции, учитывалась логистика, взаимозаменяемость ресурсов, отраслевые приоритеты и т.д. В 70–80-х годах это было крайне затруднительно из-за недостатка вычислительной техники и несовершенства методов планирования, что приводило к неточностям, дефицитам и дисбалансам.

Сегодня же, используя современные вычислительные мощности и продвинутые алгоритмы (линейное и нелинейное программирование, машинное обучение, системы принятия решений в реальном времени и т.п.), можно в теории гораздо эффективнее решать плановые задачи. Хотя, конечно, сама концепция плановой экономики поднимает множество вопросов и проблем, выходящих за рамки чисто вычислительной стороны дела.

Сложность плановых расчётов в 70–80-х

Недостаток вычислительной техники. ЭВМ в СССР (например, «Минск», «Урал», ЕС ЭВМ) имели на порядки меньшую производительность по сравнению с современными ПК. В 70–80-е годы такие машины могли обрабатывать относительно простые и не слишком большие задачи. Полноценный учёт сотен тысяч наименований товаров и ресурсов представлял колоссальную computational-проблему.
Ручной труд экономистов и плановиков. Многие расчёты производились вручную, с помощью арифмометров, перфокарт. Часть плановых заданий корректировалась “на местах”, что приводило к искажению общей картины.
Ограничения математических моделей. Методологии линейного программирования, многокритериальной оптимизации и т. п. тогда не были развиты так широко, как сейчас. Вдобавок многие экономические и социальные факторы трудно формализовать линейной моделью.
В результате получался грубый (и часто запаздывающий) план, который вёл к дефициту одних товаров и избытку других, очередям, бартерным схемам и так далее.

Подпишись 👉🏻 @KodduuPython 🤖
## Пример кода на Python

Для решения подобных задач часто применяют библиотеки для линейного программирования (Linear Programming). Одна из популярных библиотек в Python — PuLP. Если её нет, установите командой:

pip install pulp


Ниже приведён пример задачи, где мы хотим произвести три вида продукции: A, B и C.
- Каждый вид продукции требует определённое количество ресурсов (R1 и R2).
- Есть плановый минимум по каждому товару.
- Есть ограничения на объём ресурсов.
- Мы хотим максимизировать так называемую “общественную пользу” (условный показатель важности каждого товара).

### Код


# Пример кода, иллюстрирующего подход к задаче планирования

from pulp import LpProblem, LpMaximize, LpVariable, LpInteger, lpSum, LpStatus, value

# Создаём задачу линейного программирования (ЛП)
problem = LpProblem("SovietPlan", LpMaximize)

# Объявим переменные:
# xA, xB, xC — количество единиц продукции A, B и C, которое мы собираемся произвести.
# для наглядности используем целочисленное программирование (LpInteger),
# хотя в реальности могут быть и вещественные переменные.
xA = LpVariable('xA', lowBound=0, cat=LpInteger)
xB = LpVariable('xB', lowBound=0, cat=LpInteger)
xC = LpVariable('xC', lowBound=0, cat=LpInteger)

# Плановые задания (минимальное количество, которое нужно произвести)
planA = 10
planB = 20
planC = 5

# Коэффициенты потребления ресурсов на единицу каждого товара.
# Пусть ресурс R1 (например, металл) и ресурс R2 (например, электроэнергия).
# Допустим, на производство 1 единицы A нужно 3 ед. R1 и 1 ед. R2,
# на производство 1 единицы B — 2 ед. R1 и 2 ед. R2,
# на производство 1 единицы C — 4 ед. R1 и 3 ед. R2
r1_for_A = 3
r2_for_A = 1

r1_for_B = 2
r2_for_B = 2

r1_for_C = 4
r2_for_C = 3

# Доступное количество ресурсов
R1_available = 100 # например, 100 тонн металла
R2_available = 90 # например, 90 кВт⋅ч условной электроэнергии

# "Польза" (или приоритет) от каждой единицы товара
# В реальном случае это могло бы учитывать потребности населения,
# важность для военной промышленности, экспортный потенциал и т.п.
benefitA = 5
benefitB = 4
benefitC = 6

# Целевая функция: максимизируем суммарную "пользу"
problem += (benefitA * xA + benefitB * xB + benefitC * xC), "Total_Benefit"

# Добавим ограничения

# 1. Выполнение плановых заданий
problem += xA >= planA, "Min_A"
problem += xB >= planB, "Min_B"
problem += xC >= planC, "Min_C"

# 2. Ограничение по ресурсам
problem += (r1_for_A * xA + r1_for_B * xB + r1_for_C * xC) <= R1_available, "Res_R1"
problem += (r2_for_A * xA + r2_for_B * xB + r2_for_C * xC) <= R2_available, "Res_R2"

# Решаем задачу
problem.solve()

# Вывод результатов
print(f"Статус решения: {LpStatus[problem.status]}")
print(f"Оптимальное количество продукции A (xA): {xA.varValue}")
print(f"Оптимальное количество продукции B (xB): {xB.varValue}")
print(f"Оптимальное количество продукции C (xC): {xC.varValue}")
print(f"Максимальная польза: {value(problem.objective)}")


### Интерпретация результатов

1. Статус решения может показать, что задача решена оптимально (`Optimal`) или что оптимального решения нет (если, например, требования слишком высоки и ресурсы не позволяют их удовлетворить).
2. Количество продукции (xA, xB, xC) — сколько штук каждого товара в итоге планируется выпускать.
3. Максимальная польза (value(problem.objective)) показывает значение целевой функции.

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

Пример:
- Есть два завода (Factory1, Factory2), на которых производятся два вида товаров (Product A и Product B).
- Есть два распределительных центра (склада) (DC1, DC2).
- Есть два региона с конечным спросом (Market1, Market2).
- Мы знаем спрос в каждом регионе по каждому товару, ограничения по мощности заводов (сколько каждого товара они могут произвести) и ёмкость складов (сколько там можно держать товаров).
- Мы хотим минимизировать совокупные затраты (произвести товар, перевезти с завода на склад, затем со склада — к конечному потребителю).

Подобная постановка задачи — задача оптимизации в цепочке поставок (supply chain optimization), которая, как и плановая задача, может вырасти до огромных масштабов и требовать значительных вычислительных ресурсов.

---

## Иллюстративный пример на Python (используем библиотеку PuLP)

> Для решения потребуется библиотека PuLP. Установить её можно командой:
>

> pip install pulp
>



from pulp import (
LpProblem, LpMinimize, LpVariable, LpStatus, lpSum, LpInteger, value
)

# ---------------------------
# 1. ДАННЫЕ ЗАДАЧИ
# ---------------------------

# Заводы (factories), Склады (distribution centers), Рынки/регионы (markets)
factories = ["Factory1", "Factory2"]
distribution_centers = ["DC1", "DC2"]
markets = ["Market1", "Market2"]
products = ["ProductA", "ProductB"]

# Производственные мощности (максимальное кол-во единиц товара,
# которое может быть выпущено на каждом заводе)
# form: capacity[завод][продукт]
capacity = {
"Factory1": {"ProductA": 100, "ProductB": 80},
"Factory2": {"ProductA": 120, "ProductB": 100}
}

# Ёмкость складов (сколько всего единиц любых товаров может храниться на складе)
# form: dc_capacity[склад]
dc_capacity = {
"DC1": 150,
"DC2": 150
}

# Спрос в регионах (сколько единиц каждого товара нужно в каждом рынке)
# form: demand[рынок][продукт]
demand = {
"Market1": {"ProductA": 60, "ProductB": 40},
"Market2": {"ProductA": 80, "ProductB": 70}
}

# Себестоимость производства (cost of production) на каждом заводе
# form: production_cost[завод][продукт]
production_cost = {
"Factory1": {"ProductA": 2.0, "ProductB": 3.0},
"Factory2": {"ProductA": 2.5, "ProductB": 2.8}
}

# Стоимость транспортировки с завода до склада (за 1 единицу товара)
# form: transport_cost_factory_dc[(завод, склад)]
transport_cost_factory_dc = {
("Factory1", "DC1"): 0.5,
("Factory1", "DC2"): 0.6,
("Factory2", "DC1"): 0.7,
("Factory2", "DC2"): 0.4
}

# Стоимость транспортировки со склада к рынку (за 1 единицу товара)
# form: transport_cost_dc_market[(склад, рынок)]
transport_cost_dc_market = {
("DC1", "Market1"): 0.3,
("DC1", "Market2"): 0.8,
("DC2", "Market1"): 0.6,
("DC2", "Market2"): 0.5
}

# ---------------------------
# 2. ПОСТАНОВКА ЗАДАЧИ
# ---------------------------
# Создадим задачу линейного программирования: минимизация общих затрат
problem = LpProblem("SupplyChainOptimization", LpMinimize)

# ---------------------------
# 3. ПЕРЕМЕННЫЕ
# ---------------------------
# Пусть:
# x_fdc[p, f, dc] = количество товара p, производимого на заводе f,
# и отправляемого на склад dc
#
# y_dcm[p, dc, m] = количество товара p, отгружаемого со склада dc на рынок m

# Объявим переменные как неотрицательные целые (или неотрицательные непрерывные — зависит от контекста)
x_fdc = {}
for p in products:
for f in factories:
for dc in distribution_centers:
x_fdc[(p, f, dc)] = LpVariable(
f"x_{p}_{f}_{dc}",
lowBound=0,
cat='Continuous'
)
y_dcm = {}
for p in products:
for dc in distribution_centers:
for m in markets:
y_dcm[(p, dc, m)] = LpVariable(
f"y_{p}_{dc}_{m}",
lowBound=0,
cat='Continuous'
)

# ---------------------------
# 4. ЦЕЛЕВАЯ ФУНКЦИЯ
# ---------------------------
# Общие затраты = затраты на производство + затраты на перевозку от завода к складу + от склада к рынку
problem += lpSum(
production_cost[f][p] * x_fdc[(p, f, dc)]
+ transport_cost_factory_dc[(f, dc)] * x_fdc[(p, f, dc)]
for p in products
for f in factories
for dc in distribution_centers
) + lpSum(
transport_cost_dc_market[(dc, m)] * y_dcm[(p, dc, m)]
for p in products
for dc in distribution_centers
for m in markets
), "Total_Cost"

# ---------------------------
# 5. ОГРАНИЧЕНИЯ
# ---------------------------

# (A) Ограничения по производственным мощностям заводов:
# сумма отправленного товара p с завода f на все склады dc <= capacity[f][p]
for f in factories:
for p in products:
problem += lpSum(x_fdc[(p, f, dc)] for dc in distribution_centers) <= capacity[f][p], \
f"ProdCapacity_{f}_{p}"

# (B) Ограничения по ёмкости складов:
# на складе dc общее кол-во хранимых товаров (прибывших от всех заводов)
# не должно превышать dc_capacity[dc],
# но! нужно учесть, что то, что пришло на склад, может сразу уехать на рынок.
# Если мы считаем, что склад одновременно может хранить всё, что приходит,
# и лимит — это некая "пропускная способность", то упростим до:
# Σ(продуктов, заводов) x_fdc <= capacity_dc
# В реальности часто вводят дополнительные переменные для учёта запасов.
# Сделаем упрощённо.
for dc in distribution_centers:
problem += lpSum(x_fdc[(p, f, dc)] for p in products for f in factories) <= dc_capacity[dc], \
f"StorageCapacity_{dc}"

# (C) Баланс на складе (поток товаров через склад):
# кол-во товара p, пришедшее на склад dc, должно быть равно
# кол-ву, которое отгружается дальше в рынки (если мы предполагаем 0 складских запасов в конце).
# Σ(factories) x_fdc = Σ(markets) y_dcm
for dc in distribution_centers:
for p in products:
problem += lpSum(x_fdc[(p, f, dc)] for f in factories) == lpSum(y_dcm[(p, dc, m)] for m in markets), \
f"FlowBalance_{dc}_{p}"

# (D) Удовлетворение спроса в каждом рынке:
# Σ(dc) y_dcm >= demand[m][p]
for m in markets:
for p in products:
problem += lpSum(y_dcm[(p, dc, m)] for dc in distribution_centers) >= demand[m][p], \
f"Demand_{m}_{p}"

# ---------------------------
# 6. РЕШЕНИЕ ЗАДАЧИ
# ---------------------------
problem.solve()

# ---------------------------
# 7. ВЫВОД РЕЗУЛЬТАТОВ
# ---------------------------
print(f"Статус решения: {LpStatus[problem.status]}")
print(f"Минимальные совокупные затраты: {value(problem.objective):.2f}\n")

for (p, f, dc) in x_fdc:
qty = x_fdc[(p, f, dc)].varValue
if qty > 0:
print(f"Производство {p} на {f}, отправка на {dc}: {qty}")

for (p, dc, m) in y_dcm:
qty = y_dcm[(p, dc, m)].varValue
if qty > 0:
print(f"Отгрузка {p} со склада {dc} в {m}: {qty}")


В реальной задаче, особенно если нужно учитывать наличие запасов на складах и временные интервалы, логистические (транспортные) ограничения (наличие вагонов, машин, графики перевозок), затраты на хранение, несколько периодов планирования и прочее, модель становится значительно более сложной и крупной.

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

Здесь мы используем библиотеку OR-Tools от Google (а не `pulp`). Если библиотеки нет, установите её:

pip install ortools


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


from ortools.constraint_solver import routing_enums
from ortools.constraint_solver import pywrapcp

def create_data_model():
"""
Создаём структуру с входными данными.
distance_matrix: матрица расстояний между всеми точками (0-я точка — «Лапландия»).
num_vehicles: количество "транспортных средств" (один Дед Мороз).
depot: индекс начальной/конечной точки (тоже «Лапландия»).
"""
data = {}

# Пример: у нас есть 6 домов + 1 "домик Деда Мороза" (всего 7 точек).
# Матрицу расстояний можно задать произвольно или сгенерировать.
# Ниже — условный пример (симметричная матрица).
data['distance_matrix'] = [
# От каждой точки до каждой (0-я строка — расстояния из «Лапландии»).
[0, 10, 15, 20, 25, 30, 12], # Lapland (0) -> ...
[10, 0, 18, 13, 28, 15, 22], # House1 (1) -> ...
[15, 18, 0, 17, 16, 22, 15], # House2 (2)
[20, 13, 17, 0, 14, 19, 23], # House3 (3)
[25, 28, 16, 14, 0, 25, 20], # House4 (4)
[30, 15, 22, 19, 25, 0, 18], # House5 (5)
[12, 22, 15, 23, 20, 18, 0 ], # House6 (6)
]
data['num_vehicles'] = 1 # Дед Мороз «один»
data['depot'] = 0 # Начальная (и конечная) точка — 0, то есть «Лапландия»
return data

def main():
# Создаём данные
data = create_data_model()
distance_matrix = data['distance_matrix']
num_locations = len(distance_matrix) # Всего точек (включая «Лапландию»)
num_vehicles = data['num_vehicles']
depot = data['depot']

# Создаём менеджер маршрутов и модель
manager = pywrapcp.RoutingIndexManager(
num_locations, # кол-во локаций (вершин)
num_vehicles, # кол-во «трансп. средств»
depot # индекс депо (старт/финиш)
)

routing = pywrapcp.RoutingModel(manager)

# Функция-«коллбек», возвращающая расстояние между двумя точками
def distance_callback(from_index, to_index):
# Преобразуем внутренние индексы маршрутизатора в индексы из матрицы
from_node = manager.IndexToNode(from_index)
to_node = manager.IndexToNode(to_index)
return distance_matrix[from_node][to_node]

# Регистрируем функцию коллбека и присваиваем ей ID
transit_callback_index = routing.RegisterTransitCallback(distance_callback)
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)

# Зададим параметры поиска (например, стратегию поиска маршрута)
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.first_solution_strategy = (
routing_enums.FirstSolutionStrategy.PATH_CHEAPEST_ARC
)

# По желанию — включим какую-нибудь эвристику локального поиска
# search_parameters.local_search_metaheuristic = (
# routing_enums.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH
# )
# search_parameters.time_limit.seconds = 5 # ограничение по времени

# Запускаем решение
solution = routing.SolveWithParameters(search_parameters)
if solution:
# Выводим итоговый маршрут
print("Оптимальный маршрут Деда Мороза (минимальное суммарное расстояние):")
index = routing.Start(0) # начинаем с депо (Лапландия)
plan_output = "Лапландия -> "
route_distance = 0
while not routing.IsEnd(index):
next_index = solution.Value(routing.NextVar(index))
route_distance += routing.GetArcCostForVehicle(index, next_index, 0)
plan_output += f"House{manager.IndexToNode(next_index)} -> "
index = next_index
plan_output += "Лапландия (конец)"
print(plan_output)
print(f"Общее расстояние: {route_distance}")
else:
print("Решение не найдено!")

if __name__ == '__main__':
main()


### Пояснения

1. OR-Tools — это мощная библиотека от Google для решения задач оптимизации (в том числе маршрутизации, линейного и целочисленного программирования, расписаний и т. д.).
2. Ключевые моменты:
- distance_matrix: матрица расстояний между всеми точками (включая точку «Лапландии», где начинается и заканчивается маршрут).
- RoutingIndexManager и RoutingModel: объекты, которые отвечают за «оптимизационную модель».
- distance_callback: функция, которая для каждой пары «откуда–куда» возвращает расстояние.
- В конце мы получаем итоговый маршрут (последовательность посещения домов), чтобы суммарное расстояние было минимальным.

3. Мы предположили, что Дед Мороз должен объехать все дома (узлы) один раз и вернуться в исходную точку (в классической постановке — задача коммивояжёра). В результате мы ищем маршрут, минимизирующий общее расстояние путешествия.

4. В реальном мире можно добавлять множество дополнительных условий:
- Временные окна (должен доставить подарок до определённого времени).
- Ограничения по весу и объёму подарков (если у Деда Мороза несколько волшебных саней).
- Разные скорости движения или разные стоимости поездки (например, снежные заносы).

Но даже в таком упрощённом виде пример показывает, как другая библиотека (OR-Tools), а не PuLP, применяется для решения оптимизационной задачи на тему «доставки подарков Дедом Морозом».

Подпишись 👉🏻 @KodduuPython 🤖
🔥5
NetworkX — это удобная и мощная библиотека для работы с графами на Python. С её помощью можно:

- Создавать графы (ориентированные и неориентированные)
- Добавлять вершины и рёбра
- Находить кратчайшие пути (алгоритмы Дейкстры, Беллмана — Форда и др.)
- Искать связные компоненты, вычислять центральности, кластеризации и многое другое

Ниже — короткий пример, где мы создаём простой граф, добавляем рёбра и ищем кратчайший путь между двумя узлами:


import networkx as nx

# Создадим неориентированный граф
G = nx.Graph()

# Добавим вершины (можно неявно при добавлении рёбер)
G.add_nodes_from(["A", "B", "C", "D", "E"])

# Добавим рёбра с весами
G.add_edge("A", "B", weight=2)
G.add_edge("A", "C", weight=5)
G.add_edge("B", "D", weight=3)
G.add_edge("C", "D", weight=1)
G.add_edge("D", "E", weight=4)

# Ищем кратчайший путь (по весам) из A в E
path = nx.dijkstra_path(G, source="A", target="E", weight="weight")
distance = nx.dijkstra_path_length(G, source="A", target="E", weight="weight")

print("Кратчайший путь A -> E:", path)
print(f"Общая длина пути: {distance}")


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

Подпишись 👉🏻 @KodduuPython 🤖
🔥2👍1