Код на салфетке

Description
Канал для тех, кому интересно программирование на Python и не только.

Сайт канала: https://pressanybutton.ru/
Чат канала: https://t.me/+Li2vbxfWo0Q4ZDk6
Заметки автора: https://t.me/writeanynotes

Реклама и взаимопиар: @Murzyev1995
Advertising
We recommend to visit
HAYZON
HAYZON
6,053,581 @hayzonn

لا اله الا الله محمد رسول الله

👤 𝐅𝐨𝐮𝐧𝐝𝐞𝐫: @Tg_Syprion
🗓 ᴀᴅᴠᴇʀᴛɪsɪɴɢ: @SEO_Fam
Мои каналы: @mazzafam

Last updated 3 weeks, 1 day ago

Architec.Ton is a ecosystem on the TON chain with non-custodial wallet, swap, apps catalog and launchpad.

Main app: @architec_ton_bot
Our Chat: @architec_ton
EU Channel: @architecton_eu
Twitter: x.com/architec_ton
Support: @architecton_support

Last updated 2 weeks, 2 days ago

Канал для поиска исполнителей для разных задач и организации мини конкурсов

Last updated 1 month ago

5 days, 10 hours ago
**Знаете ли вы о возможностях multistage …

Знаете ли вы о возможностях multistage build в Docker для снижения размера образов?

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

```
# Стадия сборки
FROM golang:1.20-alpine AS builder
WORKDIR /app

# Копируем только нужные файлы
COPY go.mod go.sum ./
RUN go mod download

# Копируем source и build
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o myapp -ldflags="-w -s"

# Финальная версия
FROM alpine:3.18
RUN apk --no-cache add ca-certificates

WORKDIR /root/
# Копируем только скомпилированный бинарник
COPY --from=builder /app/myapp .

# Ставим non-root пользователя
USER nobody

CMD ["./myapp"]
```

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

6 days, 10 hours ago
Привет, друзья!

Привет, друзья!

Прошла еще одна неделя, и у нас накопилось много интересных материалов: статьи, новости и полезные советы. Вот наш недельный дайджест:

Понедельник (09.12.2024) Дайджест за предыдущую неделю

Вторник (10.12.2024) Хотите узнать, как сочетать asyncio и aiohttp для асинхронного веб-скрапинга?

Пятница (13.12.2024) Пятничный кинорелакс

Спасибо, что остаетесь с нами! Надеемся, что эти материалы будут вам полезны. Удачи в новой неделе!

С уважением,
Команда канала "Код на салфетке".

#дайджест #материалы #новости #код_на_салфетке

1 week ago

Всем привет!

Помимо программирования, я активно изучаю и DevOps направление: Администрирование серверов, контейнеризацию, CI/CD и это только малая часть того, что нужно знать и уметь.

В своих проектах я применяю CI/CD для проверки кода линтером, тестирования (если написаны тесты), сборки и деплоя. На любом из этих этапов может произойти ошибка, и если GitHub уведомляет по почте, то собственный git на базе Gitea так не делает (или я не разобрался), тем не менее, уведомления на почту не очень удобны. Тогда я задался вопросом оповещений в Telegram, что позволит оперативно реагировать на события в пайплайнах.

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

Но на чём его писать? Можно бы было на Python, но я и так всё пишу на нём, хотелось "чего-то нового" и я стал выбирать между GoLang и Rust. Оба языка набирают популярность и имеют свои сильные и слабые стороны. Уж не знаю почему именно, но я выбрал для решения этой задачи Rust.

Начал "как водится", с чтения официальной книги по Rust. Она хорошо написана, но просто так, читая книгу что-то выучить трудно и я решил параллельно начать писать. В процессе, количество открытых вкладок поисковиков, Stack Overflow и других сайтов росло в геометрической прогрессии, это не считая вопросов, которые я задавал чату GPT, прося его объяснить мне в максимальных подробностях.

Результатом стала программа для выполнения в среде GitHub (и не только) Actions под названием Telegram Notify Action. Программа, при срабатывании триггера (они могут быть разные, например always, как понятно из названия, срабатывает всегда, а failure, только при сбое) получает данные из окружения текущего workflow и формирует текст сообщения, а затем отправляет его в Telegram-бота по API.

Если вам интересно, хотите опробовать или просто поддержать поставив "звёздочку", прошу в репозиторий: https://github.com/proDreams/actions-telegram-notifier

Буду рад вашим комментариям и отзывам!

А я пойду дальше читать учебник, наверняка придётся ещё не раз рефакторить написанный код, а возможно и добавлять новый функционал.

2 weeks ago

Вчера мы задали задачу, похожую на Задачу №46, но с небольшим отличием. Задачу решило 5 человек из 15-ти проголосовавших. Давайте резберём правильный ответ.

Задача:
Вы пишете функцию, которая выполняет фильтрацию и модификацию словаря на основе вложенных условий. Чтобы упростить логику, вы решили использовать итерацию по ключам словаря и изменять его "на лету". Что получится в результате выполнения написанного кода?

Код задачи

```
def filter_dict(data: dict[int, int]) -> dict[int, int]:
for key in list(data.keys()):
if key % 2 == 0:
data[key + 1] = data.pop(key) * 2
return data

data = {1: 10, 2: 20, 3: 30, 4: 40}
result = filter_dict(data)
print(result)
```

Разбор кода:
1. Функция filter_dict принимает словарь data с ключами и значениями типа int.

  1. Цикл for key in list(data.keys()) проходит по всем ключам словаря.

- Здесь используется list(data.keys()), чтобы создать список ключей, так как мы будем изменять сам словарь data в процессе итерации. Если бы мы проходили по data.keys() напрямую, это могло бы вызвать ошибки.
3. Внутри цикла для каждого ключа проверяется, делится ли он на 2 без остатка (key % 2 == 0). Это условие выделяет чётные ключи.

  1. Если ключ чётный, выполняется модификация:

- Значение по этому ключу удваивается (data.pop(key) * 2) и присваивается новому ключу, который равен key + 1.
- Метод pop удаляет старый ключ из словаря и возвращает его значение.
5. По завершении цикла функция возвращает модифицированный словарь.

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

Правильный ответ: {1: 10, 3: 40, 5: 80}

Как это работает?
Разберём пошагово, что происходит с данным словарём {1: 10, 2: 20, 3: 30, 4: 40} при прохождении через функцию:

  1. Итерация 1:
    Ключ 1 (нечётный). Условие key % 2 == 0 не выполняется, пропускаем этот ключ.
  2. Итерация 2:
    Ключ 2 (чётный).

- Выполняется data.pop(2) → удаляем ключ 2, возвращаем его значение 20.
- Новый ключ 2 + 1 = 3. Присваиваем значение 20 * 2 = 40 новому ключу 3.
Теперь словарь выглядит так: {1: 10, 3: 40, 4: 40}.
3. Итерация 3:
Ключ 3 (нечётный). Условие key % 2 == 0 не выполняется, пропускаем.
4. Итерация 4:
Ключ 4 (чётный).

- Выполняется data.pop(4) → удаляем ключ 4, возвращаем его значение 40.
- Новый ключ 4 + 1 = 5. Присваиваем значение 40 * 2 = 80 новому ключу 5.
Теперь словарь выглядит так: {1: 10, 3: 40, 5: 80}.

Цикл завершён, функция возвращает финальный словарь {1: 10, 3: 40, 5: 80}.

Почему результат именно такой?
1. Итерация по списку ключей, а не по словарю:
Мы создаём копию ключей (list(data.keys())), чтобы изменения в словаре data не влияли на процесс итерации. Без этого подхода могли возникнуть ошибки или пропуск ключей.

  1. Метод pop и добавление нового ключа:
    Метод pop удаляет чётные ключи и их значения из словаря. Удвоенное значение присваивается новому ключу (key + 1). Это приводит к замене чётных ключей на нечётные с модифицированным значением.

  2. Последовательность операций:
    Изменения в словаре происходят строго по порядку, так как мы проходим по изначальному списку ключей. Это исключает влияние на порядок обработки данных.

2 weeks, 1 day ago
3 weeks ago

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

Задача:
Вы экспериментируете с оптимизацией обработки данных. В представленном коде для фильтрации списка чисел используется вложенная функция и модификация самого списка во время его обработки. Цель задачи — понять, как работает данный код, и выяснить, какой результат будет выведен на экран.

Код задачи:

```
def process_data(data: list[int]) -> list[int]:
def modify_and_filter():
for i in range(len(data)):
if data[i] % 2 == 0:
data.pop(i)
yield i

indices = list(modify\_and\_filter()) return indices + data

data_lst = [1, 2, 3, 4, 5, 6]
result = process_data(data_lst)
print(result)
```

Разбор кода
Давайте разберём этот код построчно и посмотрим, что происходит.

Функция process_data
Это основная функция, принимающая список целых чисел data и возвращающая обработанный результат.

Вложенная функция modify_and_filter
Эта функция должна:

  1. Проходить по индексам списка data.
  2. Проверять, является ли элемент чётным.
  3. Если элемент чётный:
    - Удалять его из списка (data.pop(i)).
    - Возвращать индекс удалённого элемента (с помощью yield).

Ключевой момент: modify_and_filter — это генератор, так как она использует yield. Вызов этой функции не выполняет её код сразу, а создаёт генераторный объект, выполнение которого начинается только при итерации.

Цикл for i in range(len(data))
Цикл проходит по индексам от 0 до len(data) \- 1. Внутри цикла вызывается data[i] для проверки условия.

Проблема: Во время работы цикла список data модифицируется. Это влияет на длину списка и смещение элементов, что приводит к несогласованности индексов.

Удаление элемента data.pop(i)
Удаление элемента приводит к изменению длины списка и смещению индексов остальных элементов. Например, если удалить элемент с индексом 1, то элемент с индексом 2 станет на место элемента 1, а длина списка уменьшится.

Генератор возвращает индексы
Функция modify_and_filter возвращает индексы удалённых элементов в процессе итерации.

Возврат результата
Функция process_data создаёт список из всех возвращённых генератором индексов (indices) и объединяет его с текущим состоянием списка data.

Правильный ответ: IndexError

Почему возникает ошибка IndexError?
Рассмотрим, что происходит при выполнении программы:

  1. data_lst = [1, 2, 3, 4, 5, 6].
  2. Вызов process_data(data_lst) запускает modify_and_filter.
  3. Внутри генератора:
    - На первой итерации i = 0, проверяется data[0] (значение 1). Условие не выполнено, идёт следующая итерация.
    - На второй итерации i = 1, проверяется data[1] (значение 2). Условие выполнено:
    - Удаляется data[1] (pop(1)), список становится [1, 3, 4, 5, 6].
    - Возвращается i = 1.
    - Следующая итерация пытается проверить data[2], но из-за удаления индексы изменились: на месте data[2] сейчас стоит 4, а длина списка уменьшилась. Попытка доступа к несуществующему индексу приводит к IndexError.

Вывод
Ошибка в программе возникает из-за попытки изменить список во время его итерации. Это меняет длину списка и смещает индексы, что делает дальнейшие попытки доступа к элементам небезопасными. Для избежания подобных ошибок важно:

  1. Не модифицировать список внутри цикла, итерирующегося по нему.
  2. Использовать копию списка или собирать данные для изменения в отдельную структуру.

Модификация списка — распространённая ошибка новичков, но с пониманием устройства циклов и индексов её легко избежать.

3 months, 1 week ago

Привет, Друзья!

Хотим порекомендовать вам авторский канал про веб-разработку и сетевые технологии - "Давайте про IT".

Богдан специалист в Python-разработке и охотно делится со всеми гайдами, а также снимает видео! Сейчас на его канале активно рассказывается про OpenWRT и обходы сами знаете чего ?

Наверняка вы найдёте много полезного для себя.

3 months, 2 weeks ago

Сегодня разберём вчерашнюю задачу, где нам нужно найти пользователей сайта. Верно ответили 17% из 18-ти человек.

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

Условие:
- Первый список содержит идентификаторы пользователей, которые заходили на сайт в первый день.
- Второй список содержит идентификаторы пользователей, которые заходили на сайт во второй день.
- Третий список содержит идентификаторы пользователей, которые заходили на сайт между этими днями.

Код задачи:

```
day1 = {101, 102, 103, 104, 105, 106}
day2 = {104, 105, 106, 107, 108, 109}
midday = {105, 107, 110}

common = day1 & day2
inactive_in_between = common - midday

day2.add(102)
midday.add(103)

result = len(inactive_in_between |
midday -
day2)
print(result)
```

Разбор задачи
Перед нами три множества, представляющие пользователей, заходивших на сайт в разные дни. Всё, что нам нужно сделать, это найти пользователей, которые заходили в эти дни, но не были активны в промежуточный день.

  1. Шаг первый: пересекаем множества day1 и day2 с помощью оператора & (пересечение).

common = day1 & day2

Оператор & находит общие элементы между двумя множествами. В данном случае, мы находим пользователей, которые заходили на сайт в оба дня. Получаем:

common = {104, 105, 106}

  1. Шаг второй: вычитаем из этого множества тех, кто был активен в промежуточный день, используя оператор \- (разность).

inactive\_in\_between = common \- midday

Оператор \- убирает из множества все элементы, которые есть в другом множестве. Здесь мы убираем пользователей, заходивших в промежуток между днями. Остаётся:

inactive\_in\_between = {104, 106}

  1. Шаг третий: добавляем в day2 пользователя 102, а в midday — 103.

day2.add(102) midday.add(103)

Теперь:
- day2 = {102, 104, 105, 106, 107, 108, 109}
- midday = {103, 105, 107, 110}

  1. Шаг четвёртый: финальное выражение.

result = len(inactive\_in\_between | midday \- day2)

Внутри функции len(), мы выполняем две операции: | и \-, однако, выполнение идёт не по порядку. В Python приоритет операций с множествами такой, что сначала выполняется операция вычитания (\-), а затем объединение (|). Д

- Первым делом выполняется вычитание midday \- day2. Убираем всех пользователей, которые были во второй день, из тех, кто заходил между днями:

{103, 105, 107, 110} \- {102, 104, 105, 106, 107, 108, 109} = {103, 110}

- Затем выполняется объединение с множеством inactive_in_between. Объединяем множество пользователей, которые были неактивны в промежутке, с теми, кто заходил между днями и не зашёл во второй день:

{104, 106} | {103, 110} = {103, 104, 106, 110}

Теперь в результате остаются пользователи: {103, 104, 106, 110}.

Осталось посчитать количество элементов в этом множестве:

result = len({103, 104, 106, 110}) = 4

Правильный ответ: — 4.

3 months, 2 weeks ago
3 months, 2 weeks ago
We recommend to visit
HAYZON
HAYZON
6,053,581 @hayzonn

لا اله الا الله محمد رسول الله

👤 𝐅𝐨𝐮𝐧𝐝𝐞𝐫: @Tg_Syprion
🗓 ᴀᴅᴠᴇʀᴛɪsɪɴɢ: @SEO_Fam
Мои каналы: @mazzafam

Last updated 3 weeks, 1 day ago

Architec.Ton is a ecosystem on the TON chain with non-custodial wallet, swap, apps catalog and launchpad.

Main app: @architec_ton_bot
Our Chat: @architec_ton
EU Channel: @architecton_eu
Twitter: x.com/architec_ton
Support: @architecton_support

Last updated 2 weeks, 2 days ago

Канал для поиска исполнителей для разных задач и организации мини конкурсов

Last updated 1 month ago