Ответы пользователя по тегу Python
  • Как запусить две функции асинхронно?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Всё так и должно быть, ведь await означает ожидание завершения функции и получения её результата, вторая не будет запущена до этого.

    Можно например так:

    send_result = send()
    polling_result = dp.start_polling(bot)
    await send_result
    await polling_result


    Или так:

    send_result = send()
    polling_result = dp.start_polling(bot)
    await asyncio.gather(send_result, polling_result)


    Или даже так:

    await asyncio.gather(
         send(),
         dp.start_polling(bot)
    )
    Ответ написан
    Комментировать
  • Python какой хостинг подойдет, и в чем проблема?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    В pythonanywhere в бесплатном тарифе ограничен список адресов, на которые можно ходить https://www.pythonanywhere.com/whitelist/ . Кроме того, браузер сам по себе очень тяжёлый, в бесплатных хостингах даже если и удастся его поставить, он упрётся в лимиты по памяти.

    Правильно арендовать VPS. Можно найти весьма недорогие, есть целый ряд сайтов с рейтингами и ценами хостеров. На пиво и сигареты в месяц больше уходит (кроме тех, кто не курит и не пьёт).
    Ответ написан
  • Как сделать так, что бы бот на disnake увидел мемберов?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Необходимо добавить member intents. А также включить privileged intents в настройках бота в developer portal. Документация. Вообще, примеров на эту тему в интернете море.
    Ответ написан
    Комментировать
  • Есть ли универсальный модуль Python для работы с разными базами данных (mysql, postgresql, ...)?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    sqlalchemy вполне можно использовать как абстрактный интерфейс к базам данных, просто передавая в него строковые запросы без ORM.
    Ответ написан
    1 комментарий
  • Как запретить давать атрибуты функции без ключей?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    def func(param1, param2, *, param3, param4, ...):

    * означает, что дальше будут только keyword-аргументы. До звёздочки будут обычные позиционные аргументы.
    Ответ написан
    Комментировать
  • Как работает asyncio.sleep?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Есть такой системный вызов select (а также подобные ему poll, epoll итд), суть которого - передать массив файловых дескрипторов (частный случай - сетевых соединений) и затем при получении событий ввода-вывода получить список тех дескрипторов, в которых произошёл ввод-вывод. Важно понимать, что при это программа "засыпает", передаёт управление ОС и не тратит ресурсов. ОС сама разбудит программу при наступлении нужных событий (записался файл, пришли новые сетевые байтики итд). Высокопроизводительные сетевые приложения (типа nginx, haproxy итд) используют подобный подход для того, чтобы эффективно обрабатывать большое количество сетевого трафика одновременно.

    asyncio работает как раз примерно по тому же принципу. Когда случается ввод-вывод, нужная функция "засыпает", а управление передаётся потоку событий. Соответственно, он либо находит задачу, которая ожидает выполнения и передаёт ей управление, либо видит, что все задачи уже одидают какого-нибудь ввода-вывода и запускает select на все ожидающие дескрипторы (возможно, в реальности используется не select, а какой-то из его аналогов, но это для нас сейчас непринципиально). Как только приходит событие, программа просыпается, поток событий находит нужное событие и передаёт управление соответствующей задаче, которая его ожидала. Это позволяет очень эффективно в один поток работать с задачами, которые много ожидают ввода-вывода, но мало выполняют реальной процессорной работы.

    Обычный ввод/вывод является блокирующим: пока не будет выполнена операция (чтение/запись/передача/приём), программа приостанавливает свою работу в ожидании. В asyncio весь ввод-вывод является неблокирующим: операции ввода-вывода не приостанавливают работу программы, а позволяют перейти к другим ожидающим задачам.

    Обычный вызов sleep приводит к приостановке и засыпанию программы на указанное время (с передачей управления ОС), и в ней в это время ничего не выполняется. Как только время истечёт, ОС вернёт управление программе. Всё это время программа не работает, события ввода-вывода не обрабатывает.

    В то же время asyncio.sleep возвращает управление потоку событий, а не ОС, что позволяет переключиться на выполнение других задач, обработать новые события итд итп. Программа не останавливается и управление ОС не передаёт (ну, кроме сна в процессе исполнения select), поэтому asyncio.sleep приводит к неблокирующему засыпанию, не мешающему выполнять задачи, которым ждать окончания сна одной конкретной задачи не нужно. Когда истечёт не менее чем указанное в asyncio.sleep время, поток событий вернёт управление приостановленной задаче.

    Важно отметить, что и sleep, и asyncio.sleep не гарантируют, что функция возобновит работу через указанное число секунд, а не позже, но при этом sleep делает это значительно точнее. Потому что возврат в вызвавшую asyncio.sleep функцию может произойти только из потока событий и только при условии, что поток событий не вернёт управление какой-то другой задаче.

    Например, пусть есть функция, которая делает asyncio.sleep(1), затем три секунды работает числомолотилка без ввода-вывода. Тогда если у нас выполняются подряд с интервалами 0.1 с три таких функции, то первая задержит на 2.9 секунд возврат управления второй, а вторая - на 5.8 с третьей.

    Это общий принцип, разумеется, там много нюансов и особенностей реализации.
    Ответ написан
    Комментировать
  • Почему декоратор не работает с функциями которые принимаю переменные?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    *args в приведённом коде это аргументы самого декоратора. А аргументы функции надо описывать в wrapper.

    Сама суть декоратора в том, что вместо исходной функции получается другая функция wrapper.
    Ответ написан
    Комментировать
  • Как отправить сообщение по его id, aiogram?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Прислать повторно - нет. Bot API не позволяет получить историческую информацию по ранее отправленным сообщениям. Но можно переслать его в тот же чат с помощью метода forward_message, правда, будет выглядеть не очень красиво. Лучше хранить в базе не просто id сообщения, а исходные данные, на которых оно основано (фотографию и подпись).
    Ответ написан
    Комментировать
  • Как исправить неправильное сложение десятичных дробей при помощи sympify в Python?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Скорее всего, дело в том, что десятичный разделитель - это точка, а не запятая. А запятая тут превращает строку в кортеж двух чисел. Получается, что 5+5,1 это число 10 и число 1, а 5,1+5 - число 5 и число 6.
    Ответ написан
    Комментировать
  • Как узнать User_id в inline mode?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    У объекта query, который передаётся в inline query handler, есть поле from_user, содержащее объект пользователя. Там есть и его id. Например:

    @bot.inline_handler(lambda query: len(query.query) > 0)
    def query_text(inline_query):
        print (inline_query.from_user.id)


    (это для телебота, другие библиотеки могут иметь некоторые отличия)

    Надо понимать, что inline mode - это лишь средство помощи в написании сообщения от имени пользователя, а не полноценное средство взаимодействия с пользователем. Результат ответа от бота может кэшироваться на серверах Телеграма и не перезапрашиваться при каждом запросе пользователя. А самое главное, что бот не может узнать, в какой чат отправляется сообщение, да и оно может не отправиться вообще. Единственный вариант - это если бот присутствует в нужном чате и имеет доступ к сообщениям, тогда он может ссылку via_bot с информацией о боте.

    В целом да, можно по user_id генерить реферальный хеш, а в качестве результата отдавать реферальную ссылку. Но нужно учитывать все ограничения режима и не ожидать от него слишком многого.
    Ответ написан
  • Телеграм бот не корректно отправляет результаты парсинга страницы, как исправить?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    А как иначе? На каждой итерации цикла содержимое n2 перезатирается очередной строкой, в итоге в конце цикла остаётся последняя. Вероятно, предполагалось, что в n2 нужно добавлять очередную строку.

    Ну и скрипт, вероятно, парсит страницу один раз, при своём запуске, а затем показывает одинаковый неизменный результат (но так как начала скрипта не видно, непонятно, когда запускается этот парсинг).
    Ответ написан
  • Бот не реагирует на команды ранее все работало поменял токен не помогло Поможете?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Лучше увеличить интервал, 1 секунда это мало, и при любой ошибке ты скорее всего очень быстро сделаешь второй запрос, который и вызовет подобное поведение. Дефолтные 30 секунд это норма, не надо их менять без очень веских причин.

    Long polling так и работает: запрос длится 30 секунд, если приходит событие - запрос завершается досрочно. Это позволяет и события получать быстро, и сервер слишком часто не дёргать.
    Ответ написан
    Комментировать
  • Как сделать проверку базы данных, на наличие новых записей?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Заводим в базе поле навроде created_at, в которое вставляем NOW() для всех новых записей (или задаём значение по умолчанию CURRENT_TIMESTAMP, чтобы оно заполнялось автоматически). В ежеминутном запросе выбираем записи с created_at больше максимального created_at при прошлой проверке. Либо можно использовать монотонный идентификатор (auto_increment), помнить последний известный и выбирать новые записи больше последнего. Ещё иногда добавляют поле статуса события, в котором отмечают процесс обработки. Например, 0 - ещё не обработано, 1 - обрабатывается, 2 - обработано.

    Идея из соседнего ответа использовать брокер очереди тоже неплоха, но ради такой простой задачи без высоких требований по скорости, надёжности, высоким объёмам, отказоустойчивости и масштабируемости это для простого бота будет чересчур. Можно иметь в виду и в какой-нибудь другой раз (когда это будет более осмысленно) воспользоваться советом.
    Ответ написан
  • Как называется специальная ячейка памяти в pytelegrambotapi?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Думаю, речь не про "ячейку памяти", а про register_next_step_handler.
    Ответ написан
  • Как исправить ошибку No module?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Разумеется, если в sys.path добавить каталог flaskr/live, то это не поможет найти в нём web. Надо добавлять flaskr.

    Проще запускать скрипт из вышестоящего каталога (python live/LiveScanner.py).

    upd: Посмотрел внимательнее, flaskr/web вообще не содержит подкаталогов, а live/apiLiveData.py находится в flaskr/, а не в flaskr/web. Думаю, надо начать с наведения порядка в этом хозяйстве.
    Ответ написан
    5 комментариев
  • Как сделать так, чтобы бот игнорировал ошибку, связанную с лс, и продолжал выполнять команду?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Как и всегда, исключение можно поймать и обработать, например, проигнорировать или выполнить какие-то альтернативные действия.

    try:
        await member.send("Привет!")
    except disnake.ext.commands.errors.CommandInvokeError:
        print(f"Написать {member} не удалось")


    Но вообще спамить в ЛС - это ненормальный сценарий использования Discord API, и за это бота могут заблокировать. Правильнее писать в каналы, для чего имело смысл с самого начала заложить в бота понятие "канал для уведомлений", чтобы все пользователи бота его заранее настроили на своих серверах.
    Ответ написан
    1 комментарий
  • Почему не работает aiogram, когда создаёшь виртуальное окружения?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Потому что в виртуальном окружении по умолчанию ничего (почти) нет. Надо доустановить с помощью pip всё необходимое.
    Ответ написан
  • Почему падает бот aiogram?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Так он пишет в чём проблема: одновременно делаются несколько вызовов getUpdates. Обычно это означает, что с одним токеном запущено больше одного бота.

    Хотя если судить по предыдущим ошибкам, возможно проблема сетевого доступа до Telegram.
    Ответ написан
  • На 25 строчке при 2-ом повторении выдаёт NonType, почему и как поменять на int?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Не надо так делать. Метод append изменяет список (добавляет в него элемент) и не возвращает никакого значения (или, что то же самое, возвращает None). То есть в результате такой записи мы добавляем элемент в список, а дальше этот список моментально выкидываем на помойку.

    week[g] = week[g].append(subj[gm])
    Ответ написан
    Комментировать
  • Почему тг бот обрезает сообщение?

    shurshur
    @shurshur
    Сисадмин, просто сисадмин...
    Ответ, который уже помечен галочкой, конечно же поможет решить данную конкретную проблему, но его яркий недостаток в том, что автор вопроса так и не поймёт, в чём же именно проблема состояла. А это очень важно понимать, так как с такой же проблемой можно столкнуться и в других ситуациях.

    Проблема заключается в том, что & является разделителем аргументов GET-запроса. На первом же & в тексте будет считаться, что значение параметра text закончилось, а дальше идёт следующий параметр.

    Чтобы этого не происходило, надо заменять & на %26. Пробел надо менять на +, + менять на %2B, и это далеко не всё, с чем можно столкнуться. В частности, символ # в некоторых применениях является ссылкой на якорь на странице, и http-клиент (например, браузер) не будет передавать в запросе ничего, начиная с этого символа, если его не заменить на %23.

    Чтобы это решить в данном случае, наиболее удобный способ - это передать параметры отдельным аргументом params метода requests.get, чтобы библиотека requests сама грамотно разрулила все необходимые замены. Но если это недоступно для решения какой-то другой задачи - искать как выполнить соответствующее преобразование надо по ключевым словам urlencode/urldecode.
    Ответ написан
    Комментировать