Код на салфетке
2.22K subscribers
746 photos
14 videos
2 files
788 links
Канал для тех, кому интересно программирование на Python и не только.

Сайт: https://pressanybutton.ru/
Чат: https://t.iss.one/+Li2vbxfWo0Q4ZDk6
Заметки автора: @writeanynotes

Реклама и взаимопиар: @Murzyev1995
Сотрудничество и др.: @proDreams
Download Telegram
from aiogram.types import LabeledPrice, Message  

from botlogic.keyboards.payment_keyboard import payment_keyboard


async def send_invoice_handler(message: Message):
prices = [LabeledPrice(label="XTR", amount=20)]
await message.answer_invoice(
title="Поддержка канала",
description="Поддержать канал на 20 звёзд!",
prices=prices,
provider_token="",
payload="channel_support",
currency="XTR",
reply_markup=payment_keyboard(),
)


Предпродажная проверка.
Счёт выставлен, пользователь нажимает "Оплатить". Если у него не хватает звёзд, система предложит их приобрести. Если звёзд у него хватает, он произведёт оплату, и в этот момент Telegram пришлёт в бота запрос "точно ли всё хорошо?". На ответ у нас будет ровно 10 секунд. Если мы по каким-то причинам не хотим принимать оплаты у данного пользователя или логика бота настроена на отмену платежа, в таком случае необходимо дать ответ, сигнализирующий об отмене платежа, сопроводив его причиной отмены. В противном же случае, подтверждаем, что всё "Ок".

В этом же файле создадим асинхронную функцию pre_checkout_handler, принимающую аргумент pre_checkout_query — объект класса PreCheckoutQuery.

В теле функции у переменной pre_checkout_query вызываем метод .answer, передавая в него аргумент ok со значением True.


Код функции:

from aiogram.types import PreCheckoutQuery


async def pre_checkout_handler(pre_checkout_query: PreCheckoutQuery):
await pre_checkout_query.answer(ok=True)


Информирование о покупке.
Бюрократия позади, осталось только поздравить пользователя с покупкой!

В этом же файле создадим асинхронную функцию success_payment_handler, принимающую аргумент message — объект класса Message.

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

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


Код функции:

async def success_payment_handler(message: Message):  
await message.answer(text="🥳Спасибо за вашу поддержку!🤗")


Команда paysupport и немного про возврат средств.
Telegram также предъявляет условия к возврату средств пользователям. Не за все товары и услуги подразумевается возврат средств, однако у пользователя всё равно должна быть возможность запросить возврат средств, либо быть проинформированным касательно этого.

Для информирования пользователя обязательно должна быть команда /paysupport. В ней можно указать условия возврата, контактные данные и др. Давайте сделаем эту команду.

Создадим асинхронную функцию pay_support_handler, принимающую message — объект класса Message. В теле функции пропишем ответ на сообщение с текстом, описывающим условия для возврата средств.


Код функции:

async def pay_support_handler(message: Message):  
await message.answer(
text="Добровольные пожертвования не подразумевают возврат средств, "
"однако, если вы очень хотите вернуть средства - свяжитесь с нами." )

Непосредственно возврат средств можно сделать доступным пользователю. Для этого необходимо создать обработчик команды возврата, в котором, обращаясь к методу .refund_star_payment у объекта Bot, передать в него user_id и telegram_payment_charge_id.
🔥4
- user_id — Telegram-ID пользователя, запрашивающего возврат средств.
- telegram_payment_charge_id — Идентификатор платежа, совершённого пользователем.



Регистрация обработчиков.
Всё готово, осталось зарегистрировать обработчики в main.py.

Откроем файл main.py и в функции start добавим четыре регистрации:

- send_invoice_handler — Регистрируем как обычное сообщение, указав фильтр команды donate.
- pre_checkout_handler — Регистрируем как событие pre_checkout_query.
- success_payment_handler — Регистрируем как обычное сообщение. В качестве фильтра используем так называемый "Магический фильтр F", представляющий собой объект Message. В фильтре обращаемся к полю successful_payment. Если оно не пустое (успешная оплата), будет вызван обработчик.
- pay_support_handler — Регистрируем как обычное сообщение с фильтром на команду paysupport.



from aiogram import F


dp.message.register(payment.send_invoice_handler, Command(commands="donate"))
dp.pre_checkout_query.register(payment.pre_checkout_handler)
dp.message.register(payment.success_payment_handler, F.successful_payment)
dp.message.register(payment.pay_support_handler, Command(commands="paysupport"))


Тестирование.
Запустим бота и выполним команду /donate.

Получим сообщение с информацией о платеже и кнопкой-счётом. Нажмём на кнопку.

Откроется окно с подтверждением оплаты (если у вас нет звёзд — откроется окно приобретения, как на первом скриншоте в начале поста). Нажимаем "Подтвердить и заплатить".

В чате выстрелит конфетти, и мы увидим сообщение об успешном платеже.


Заключение.
Нововведение, конечно, всех удивило и немного застало врасплох. На переход дали мало времени, и наверняка не все даже узнали об этом. Интересно будет посмотреть, к чему всё это приведёт.



Файлы к посту, можно получить в боте по коду: 236204

Пост на сайте
Поддержать проект на Boosty
Поддержать проект в Telegram

#Python #AIOgram #Telegram_бот #Код_на_салфетке #Telegram_Stars #Оплата_в_Telegram
🔥6
Приветствуем.

В прошлую пятницу мы опубликовали пост, в котором попросили вас задавать нам вопросы.

Было всего три вопроса: Первый в комментариях к посту, второй в нашем чате, а третий прилетел в личные сообщения.

Чтож, давайте на них ответим!

Ревью бота.
Ссылка на сообщение: https://t.iss.one/press_any_button/685?comment=95471

Начнём с того, что сразу бросилось в глаза:
- README.md - Это же лицо проекта в репозитории, а такое скудненькое. Опиши, что делает, какие технологии используются, какие планы по реализации и оформи инструкцию по запуску.
- .env - Где он? Без примера .env не понятно какие переменные нужны.
- requirements.txt - По всей видимости собран используя pip freeze? Много лишнего в нём, что так и так установится с нужными пакетами + это может привести к проблемам, условно, обновишь ты версию AIOgram, а всё остальное оставишь как прежде, айограм установится, обновит зависимости, а они потом обратно откатятся, т.к. прописаны более старые версии. При этом в нём есть не всё, что нужно для работы бота.
- load_dotenv - Вместо получения сырых данных из .env, как по мне, лучше использовать pydantic для валидации, а именно pydantic-settings, но это больше вкусовщина.
- Миграции - Для управления БД удобнее использовать инструменты миграции, такие как Alembic. Можно контролировать изменения и откатываться при необходимости.

В целом интересный бот. Хотелось бы запустить и протестировать некоторые улучшения для него, но он не запустился😂. Отправил автору сообщения свои мысли по улучшению некоторых моментов.


Статистика.
Ты давно статистикой не делился. Не помню, где это было в последний раз и когда. Есть рост? Положительный ))

На канале 516 подписчиков и около 100 просмотров за сутки. Что, вполне себе неплохо (а хотелось бы больше!). По сайту тоже всё хорошо, дошли уже примерно до 100-120 ежедневных уникальных посетителей. Вот наверное всё, что можно ответить по этому поводу.


Где начинать разработку?
Лучше начать разработку на локальном компе или на реал серваке?

Не совсем понятно, что значит "начинать разработку сразу на сервере". Начинать её в любом случае проще локально, так как это позволит быстрее написать основу, продумать структуру и всё отладить, запуская проект. Потом, когда придёт пора деплоя, уже можно перебираться в разработку на сервере. Сделать это можно используя VS Code или, если у вас мощный сервер PyCharm, подключаясь по SSH и ведя удалённую разработку с доступом к консоли, докеру и прочему. Однако, лично мне удобнее всё ещё работу вести локально, затем просто по SFTP подкидывать изменённые файлы и в терминале перезапускать.
🔥3👍2
Приветствую, дорогие друзья!

Наконец-то пятница! Скажут те, у кого пятидневная рабочая неделя)). Настало время, когда мы можем позволить себе расслабиться, забыть о повседневных заботах и просто наслаждаться просмотром кино.

Фильм: Атлас

Год: 2024

События фильма разворачиваются в не столь отдалённом будущем, в котором искусственный интеллект захватил власть над людьми и развязал войну на уничтожение всего человечества. Женщина присоединяется к миссии по поимке робота-отступника, с которым её связывает загадочное прошлое. Но всё идёт не по плану, и чтобы не потерять единственный шанс спасти мир от искусственного интеллекта, Атлас должна довериться ему.

https://www.sspoisk.ru/film/4477073/

Приятного просмотра!
🔥3
Приветствуем!

Мы продолжаем попытки завоевать медиа-пространство. Сперва это были три стрима (к которым хорошо бы вернуться, но пока нет идей), а теперь это короткие видео YouTube Shorts.

Посмотреть первое видео можно по ссылке: https://www.youtube.com/shorts/AcBJriDXwQo

Будем очень благодарны, если вы поставите лайк и оставите комментарий. Это позволит алгоритмам ютуба понять, что видео интересно и будет предлагать его другим зрителям.

Оставляйте ваши отзывы, мы всё прочтём и учтём в следующем видео! Так может и до больших гайдов не далеко?😉
🔥5
Что выведет этот код? №26
🔥3
Что выведет код с изображения? №26
Anonymous Quiz
2%
b'2011'
43%
b'10011010'
32%
b'10011'
23%
Нет верного ответа
🔥3🤔2
Вчера мы опубликовали коротенькую, но интересную задачу. Верно ответили 43% из 37-ми человек.

Код задачи:
x = b'1001'
y = b'1010'

print(x + y)



Разбор задачи
Задача короткая и разбор будет таким же.

Создаём две переменные x и y, в которые помещаем две байтовые строки (byte string).

Далее в функции print() выводим результат конкатенации строк.

Думаю, на этом моменте уже стало понятно, почему правильный ответ b'10011010'.

Про строки байт.
Байтовые строки - это последовательность необработанных байт от 0 до 255, интерполируемая Python как строка, но со специальным литералом b"", в то время как обычные строки, это набор символов в определённой кодировке (обычно это UTF-8).

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

Превратить обычную строку в байтовую можно двумя способами:
1. Добавив перед кавычками литерал b - b"строка_текста".
2. Использовав метод строки .encode("кодировка") с указанием желаемой кодировки - "строка_текста".encode("utf8"). Преобразовать байтовую строку с текстом обратно можно использовав метод строки .decode("utf8").

Байтовые строки, практически ничем не отличаются от обычных. Им доступны всё те же методы и функции. Такие как: доступ к элементам по индексу, конкатенация, .split(), "".join() и другие.

Понимание работы байтовых строк особенно полезно при веб-разработке, поскольку все данные пересылаемые через интернет - являются набором байт. Данные кодируются в байты, пересылаются, затем декодируются, согласно требуемому формату данных.
🔥31
Приветствуем.

Сделали Shorts к задаче:
https://youtube.com/shorts/sSLH46uESzQ?feature=share

Будем благодарны за лайк и комментарий!
🔥3
Приветствую!

Быстро же летит время. Ровно год назад я создал этот канал и начал писать статьи про Django и AIOgram. В процессе появился сайт и чат. Я тогда и не подозревал, что вас будет больше 500 человек, а на сайте больше 100 посетителей ежедневно.
Практически сразу ко мне присоединились единомышленники. Без их помощи и поддержки всего этого бы не было. Мы, конечно, бывает, ворчим друг на друга (в основном я на всех или все на меня), но останавливаться не собираемся.
Мы постоянно учимся и не только программированию, о котором рассказываем, но и ведению канала, взаимодействию с вами, организации процессов - это всё сложно для непосвящённых вроде нас.

Благодарю команду за участие в этом авантюрном проекте. Авторов, пишущих для вас у нас. Вас - аудиторию, кто ставит реакции, пишет комментарии. Бустеров, а теперь ещё и тех, кто задонатил в боте - без вас, было бы нечем оплачивать сервер для сайта.


Передаю слово команде:

Большакова Кристина:
Год! Уже год! И правда быстро!

Данному каналу невероятно повезло! Здесь прекрасная команда администраторов, замечательные и интересные люди. Подписчики - удивительные и душевные люди!

Пусть канал продолжает расти и развиваться. А душевность остается навсегда!

С Днем Рождения, милый канал!


Лебедев Андрей:
Большое спасибо Ване и Кристине, которым этот канал обязан своим появлением. Первому - за целеустремленность и любопытство, а второй - за упорство и терпение.

То, что канал оказался востребованным, объясняется тем, что мы никак не отделяем себя от наших подписчиков: мы просто пытаемся разобраться в программировании и делимся с вами промежуточными результатами. Иногда получаем от вас замечания, дополнения и конструктивную критику. Обратная связь очень важна, потому что помогает нам становиться лучше.

Поздравляю всех нас с днём рождения канала!


Мурзыев Артур:
Не передать словами, каково это быть свидетелем того, как идея претворяется в жизнь. Как мысль материализуется упорством, бессонными ночами, трудом и потом. Видеть вживую, как общие интересы обьединяют людей со всей страны и не только.

Огромная благодарность всем подписчикам и подписчицам. Благодаря вам канал живёт, растёт и совершенствуется.
🎉18🔥32👍1
Найдите ошибку в коде ниже и исчерпывающим образом объясните ее в комментариях.

#python #код_на_салфетке #найди_ошибку
🤔4🔥1
Третья задача была довольно простой, если проявить внимательность.

Код задачи:
distance = {"home_school": 3, "school_shop": 2, "shop_home": 1}  

speed = {"runing": 15, "jogging": 10, "walking": 5, "crawling": 3}

time = (
distance.get("home_school", 0) / speed.get("jogging", 0)
+ distance.get("school_shop", 0) / speed.get("running", 0)
+ distance.get("shop_home", 0) / speed.get("walking", 0)
)

print(time)


Разбор задачи.
Вся суть задачи сводится к пониманию работы метода .get() у словарей.
Дело в том, что метод принимает один обязательный элемент - ключ, по которому ищет значение в словаре, и стандартное значение, которое возвращает, если ключ не был найден. Если стандартное значение не указано, возвращается None.

Первым на ошибку указал в комментариях - MAG.

Если внимательно пройтись по операторам в переменной time и ключам словаря, станет очевидно, что в словаре speed нет ключа running, а есть runing. Поэтому метод .get() вернёт установленное стандартное значение - 0.

Получается, что в одной из частей выражения мы делим на ноль, в связи с чем получаем ошибку DivisionByZero.
🔥41
Обновление библиотеки - AIOgram 3.8.0
Автор: Иван Ашихмин

Вышла новая версия библиотеки AIOgram 3.8.0.

Установить новую версию можно выполнив команду:

pip install -U aiogram


Главное.
- Добавлена утилита для безопасной десериализации любого объекта или метода Telegram в JSON-совместимый объект (dict). (Читать подробнее).
🔥1
- Добавлена полная поддержка Bot API 7.5:
- Добавлены классы aiogram.types.star_transactions.StarTransactions, aiogram.types.star_transaction.StarTransaction, aiogram.types.transaction_partner.TransactionPartner и aiogram.types.revenue_withdrawal_state.RevenueWithdrawalState, содержащие информацию о транзакциях Telegram Stars в боте.
- Добавлен метод aiogram.methods.get_star_transactions.GetStarTransactions для получения списка всех транзакций Telegram Stars в боте.
- Добавлена поддержка колбэк (callback) кнопок в aiogram.types.inline_keyboard_markup.InlineKeyboardMarkup для сообщений отправленных с использованием бизнес-аккаунта.
- Добавлена поддержка колбэк запросов (callback queries) для сообщений, отправленных с использованием бизнес-аккаунта.
- Добавлен аргумент business_connection_id в методы aiogram.methods.edit_message_text.EditMessageText, aiogram.methods.edit_message_media.EditMessageMedia, aiogram.methods.edit_message_caption.EditMessageCaption, aiogram.methods.edit_message_live_location.EditMessageLiveLocation, aiogram.methods.stop_message_live_location.StopMessageLiveLocation и aiogram.methods.edit_message_reply_markup.EditMessageReplyMarkup, позволяющий редактировать сообщения, отправленные с использованием бизнес-аккаунта.
- Добавлен аргумент business_connection_id в метод aiogram.methods.stop_poll.StopPoll, позволяет остановить опросы которые он делает от имени бизнес-аккаунта.


Исправления.
- Увеличено время жизни кэша DNS в сессии aiohttp как обходной путь для проблем с разрешением DNS в aiohttp.


Улучшение документации:
- Исправлен раздел MongoStorage в документации путем добавления дополнительной зависимости в конфигурацию ReadTheDocs.
- Добавлена информация об изменениях зависимостей в руководство по миграции с версии 2.x на 3.x.


Пост на сайте
Поддержать проект на Boosty
Поддержать проект в Telegram

#перевод #список_изменений #aiogram #telegram #новая_версия #telegram_бот #bot_api #changelog
🔥4
Сравнение array C и list Python
Автор: Arduinum628

Всем доброго дня! У меня был небольшой перерыв в написании статей, так как навалилось много дел. Заканчивал стажировку, параллельно занимаясь поиском работы и дописывая свой сайт-блог, весна и хорошая погода - всё это сделало своё дело. Сейчас я возобновляю свою работу над статьями и хочу выпускать их примерно раз в две недели. Также в ближайшем будущем я хочу запустить свой сайт-блог и дублировать свои статьи там.

Итак, продолжим. В предыдущей статье "Сравнение интерпретатора Python и компилятора C" я затрагивал вскользь темы array и list, а также циклов while. Поэтому в данной статье я сравню array (массив) из языка C и list (список) из языка Python, обход которых я сделаю на цикле while. Давненько я не писал статьи и даже очень соскучился по этому процессу. Так что приступаю к продолжению этой интересной и захватывающей рубрики.
🔥2
Сравнение array и list
Для начала начнём со знакомого многим питонистам list (список) из языка Python. Список - это неограниченная по размеру упорядоченная коллекция произвольных объектов. Для начала давайте создадим список в Python.


list_example = [1, 2, 3, 4, 5]
print(list_example)

Я создал список и назвал его list_example так как он не будет привязан к конкретным данным или назначению. Давайте запустим в IDE и посмотрим что он выдаст в эмуляторе terminal на моём Debian. Я перешёл с Kubuntu на Debian 12, но различий между двумя этими системами для демонстрации кода не будет. При нажатии на кнопку run python file в IDE VS Code видим следующий вывод.

В terminal


[1, 2, 3, 4, 5]

Функция print из строки print(list_example) печатает нам содержимое списка [1, 2, 3, 4, 5], в котором находятся числа. Прежде чем перейти к написанию кода с аналогичным функционалом на C давайте разберёмся что такое array.

Массив, или array, в языке C - это структура данных, которая позволяет хранить последовательности элементов одного типа. Это определение уже намекает нам на то, что в массиве на языке C не может быть разных типов данных. Чуть позже я объясню почему, а сейчас создадим массив, похожий на список, что я писал выше на Python.


#include <stdio.h>
#include <string.h>
int main(){
int array_example[] = {1, 2, 3, 4, 5};
char buffer[100];
sprintf(
buffer,
"[%d, %d, %d, %d, %d]",
array_example[0],
array_example[1],
array_example[2],
array_example[3],
array_example[4]
);
printf("%s\n", buffer);
return 0;
}

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

В terminal


$ gcc ./array_c.c -o array_c
$ ./array_c
[1, 2, 3, 4, 5]

После компиляции и запуска данного кода мы видим тот же результат, что и в коде на Python в эмуляторе terminal [1, 2, 3, 4, 5]. Давайте разберёмся, что мы вообще такое написали на С. Строка #include <string.h> включает заголовочный файл для компилятора, который нужен для работы со строками. В нашем случае заголовочный файл нужен, чтобы использовать функцию sprintf для формирования строки. Из предыдущей статьи вы помните, что строка int array_example[] = {1, 2, 3, 4, 5}; создаст массив целых чисел. Прошу обратить внимание, что вы не можете класть туда любые типы данных как это делается в языке Python! Компилятору явно указывается, что в массиве у нас тип данных int - целое число. Давайте взглянем на примере, что будет если положить в массив тип данных char или символ строки. При форматировании укажем %s спецификатор формата для char. Для этого давайте слегка поправим код.


#include <stdio.h>
#include <string.h>
int main(){
int array_example[] = {1, 2, 3, 4, "r"};
char buffer[100];
sprintf(
buffer,
"[%d, %d, %d, %d, %s]",
array_example[0],
array_example[1],
array_example[2],
array_example[3],
array_example[4]
);
printf("%s\n", buffer);
return 0;
}

Ещё раз компилируем и запустим код в terminal.


$ gcc ./array_c.c -o array_c
array_c.c: In function ‘main’:
array_c.c:5:40: warning: initialization of ‘int’ from ‘char *’ makes integer from pointer without a cast [-Wint-conversion]
5 | int array_example[] = {1, 2, 3, 4, "r"};
| ^~~
array_c.c:5:40: note: (near initialization for ‘array_example[4]’)
🔥2
Предупреждение нам говорит о том, что мы пытаемся добавить char символ к int массиву что сделать невозможно. Это сломает вашу программу так как компилятор ожидает только int тип в массиве. Перепишем код обратно на тот что был и снова перекомпилируем. Просто повторите предыдущий рабочий код, что был до изменений, и заново запустите команду компиляции. Всё должно работать как раньше.

Давайте разберём оставшиеся строки кода. Строка char buffer[100]; создаёт массив char из 99 символов и 1 символ конца строки \0. Это нужно для хранения символов строки char. Цифра 100 на самом деле не количество символов, а размер массива в байтах. Если вы введёте printf("%d\n", sizeof(char)); в свой код, то увидите что 1 char символ занимает 1 байт. Для сравнения 1 int число занимает 4 байта. Поэтому можно легко рассчитать какой размер буфера вам нужен для хранения массива char. Размер 100 байт в нашем случае очень избыточен, поэтому рассчитаем точный размер 5 * 1 + 1 = 6. Количество символов умножаем на вес одного в байтах и прибавляем 1 байт для символа конца строки. Квадратные скобки и запятые в нашем буфере не хранятся. Таким образом мы экономим 94 байта на компьютере. Программы на C требуют, чтобы вы следили за размером, который занимают ваши данные. Немного непривычно после языка Python, не так ли? На самом деле в Python тоже нужно думать о размере данных, но из-за того что он динамический и много прощает, следить за этим гораздо сложнее. Далее в функцию sprintf мы кладём наш буфер для хранения char, форматируем строку "[%d, %d, %d, %d, %d]" и для каждого спецификатора формата %d берём каждое число по индексу из массива. Далее функция sprintf заполнила наш buffer данными char в результате чего получился массив символов, последовательность которых образует строку. Ну и в конце выводим нашу строку в terminal (эмулятор терминала). В Python функция print сама выводила нам содержимое списка, а в C нам пришлось для этого форматировать строку. Возможности языка C и возможности Python разные и иногда в C просто нет простого решения. Давайте попробуем на Python написать близкий внешне вариант. Для этого перепишем наш Python код. Напишу два варианта: более старый и более новый и быстрый.


from typing import List
list_example: List[int] = [1, 2, 3, 4, 5]
str_list = '[%d, %d, %d, %d, %d]' % (list_example[0], list_example[1], \
list_example[2], list_example[3], list_example[4])
print(str_list)

Первый вариант использует оператор %, который более родственный языку C. Обратите внимание: я использую аннотацию типов List[int], показывая, что у нас должен быть тип данных list с числами int типа внутри. Это работает на уровне соглашения между разработчиками и не влияет на саму работу кода. И если туда добавить другой тип данных естественно ничего не сломается. Результатом в переменной str_list будет отформатированная оператором % строка [1, 2, 3, 4, 5], которую мы потом выводим в terminal с помощью функции print.


from typing import List
list_example: List[int] = [1, 2, 3, 4, 5]
str_list = f'[{list_example[0]}, {list_example[1]}, {list_example[2]}, '\
f'{list_example[3]}, {list_example[4]}]'
print(str_list)

Второй вариант использует f строки, которые работают быстрее оператора % и использование которых имеют более короткий и удобный синтаксис. Результат будет тот же самый что и в примере с оператором %. Если ваша Python версия поддерживает f строки, рекомендую использовать именно их.
🔥2
Далее я хочу пройти по списку и массиву с помощью цикла while и вывести каждое из чисел в списке. Довольно просто и банально, но моя цель - показать отличия Python от C, а не усложнять сам код. После того как я покажу вам основы, буду ставить задачи посложнее и писать более сложный код. Для начала напишем код на более простом языке Python.


from typing import List
list_example: List[int] = [1, 2, 3, 4, 5]
i = 0
while i <= list_example.index(list_example[-1]):
print(list_example[i])
i += 1

У меня получился довольно простой и элегантный вариант в версии Python. Когда я пишу на Python, я не пытаюсь усложнить задачу, а наоборот - стараюсь пользоваться его средствами для упрощения себе работы. В данном случае я использую функцию index для удобства. У нас есть переменная i для индекса, по которому нужно брать элементы из списка list_example. Строка while i <= list_example.index(list_example[-1]): говорит нам о том, что мы не выйдем из цикла while пока значение переменной i не будет равно последнему индексу списка. Далее выводим данные на экран в строке print(list_example[i]). После чего прибавляем на единицу переменную индекса i . Давайте запустим наш код в VS Code и взглянем на результат.


1
2
3
4
5

Видим, что наш код отработал как нужно - вывел все числа списка. После чего цикл while завершился. Пришло время написать код с похожим функционалом на C.


#include <stdio.h>
int main(){
int array_example[] = {1, 2, 3, 4, 5};
int i = 0;
int i_end = sizeof(array_example) / sizeof(array_example[0]) - 1;
while (i <= i_end){
printf("%d\n", array_example[i]);
++i;
}
return 0;
}

Давайте взглянем на наш C код и на отличия в работе его логики. У нас имеется переменная для индекса int i = 0;. Строка получения длины списка вам уже известна из предыдущей главы и единственное здесь отличие - мы отнимаем единицу. Это нужно для того, чтобы получить последний индекс списка. Строка int i_end = sizeof(array_example) / sizeof(array_example[0]) - 1; успешно получит число 4. Далее идёт условие работы цикла: while i <= i_end работает аналогично примеру из Python. Строка printf("%d\n", array_example[i]); выведет число из списка в terminal. В конце ++i; мы прибавляем единицу к переменной индекса i. Вот тут хочу остановиться поподробнее. Дело в том, что есть два варианта: ++i и i++. Первый вариант ++i это префиксная форма и она сначала увеличивает значение, а потом возвращает его. Второй вид i++ это суффиксная форма, которая сначала вернёт текущее значение, а потом увеличит его. Будьте внимательны при использовании, у них будут разные результаты и может быть ошибка в логике программы.
Теперь давайте скомпилируем и запустим программу.


$ gcc array_c.c -o array_c
$ ./array_c
1
2
3
4
5

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


Бонус
Как известно, в Python, увы, нет встроенного в язык типа данных array, но зато есть встроенный модуль array, который обеспечивает схожую функциональность. Давайте посмотрим как он работает на примере.


arr = array('i', [0]*5)
arr[0] = 1
arr[1] = 2
arr[2] = 3
arr[3] = 4
arr[4] = 5
print(arr)
print(arr[0])

Первая строка arr = array('i', [0]*5) создаёт аналог массива (по функциональности) и заполняет его пятью элементами нулями, i указывает, что это массив с данными int типа. Далее, как и в обычном list, мы присваиваем значение по индексу arr[0] = 1 и т.д. Давайте запустим код и убедимся, что всё работает.
🔥21