Задать вопрос
  • Как сделать подсчет скорости нажатий на пробел?

    Vindicar
    @Vindicar
    RTFM!
    Одним голым питоном - трудно, потому что консольный ввод буферизуется. Условно, я зажму пробел, а программа будет видеть как я ввожу один пробел за другим. Да и интервал между нажатиями теряется.
    Тебе нужно ловить пары событий нажатие-отпускание. Ты можешь попробовать использовать tkinter (он в питоне доступен сразу), создать окно, и привязать к нему обработчики соответствующих событий. Причём нужна именно пара событий <KeyPress> и <KeyPress>, а не просто <Key>.
    А реакция на эти события... зависит от того, что тебе нужно. Например, заводишь переменную-счётчик, при отпускании клавиши наращиваешь его на 1, а раз в секунду (в ткинтере есть метод .after(), он хорошо подходит для задач вида "сделай вот это через заданное время") выводишь этот счётчик пользователю, и тут же сбрасываешь его в ноль.
    Ответ написан
    Комментировать
  • Как решать такие задачи?

    Vindicar
    @Vindicar
    RTFM!
    Размер выхода слоя равен размеру входа следующего слоя.
    Вот как узнать размер выхода последнего слоя - я фз, тут недостаточно данных.

    EDIT: ой, блин, я невнимательный. Не увидел, что слои идут не 1->2->3->4, а 4->3->4.
    Тогда ещё проще, выход 4 должен совпадать по размеру со входом 3, а вход 4 - с выходом 3.
    Ответ написан
    2 комментария
  • Что использовать в качестве workerА для отложенных задач?

    Vindicar
    @Vindicar
    RTFM!
    Я бы вообще изобрёл велосипед, если честно.
    У тебя есть список или база активных (неслучившихся) событий. Пусть это будет пара ID-метка времени, остальная инфа нам без надобности.
    При запуске бота выбираем из списка ближайшее событие, и вычисляем время ожидания (с небольшим запасом) и спим в корутине. В случае, если ожидание прервано раньше - повторяем то же самое, чтобы либо "доспать", либо переключиться на ожидание более близкого события.
    Если же ожидание закончилось успешно, обрабатываем событие и снова повторяем поиск ближайшего события.
    Если список событий изменился, прерываем текущее ожидание, чтобы корутина ожидания могла адаптироваться к изменениям.

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

    Vindicar
    @Vindicar
    RTFM!
    Если Normalize может работать нормально с uint8 - то преобразования типа не нужны.
    Если не может - то никакой другой порядок и не заработает.
    Ответ написан
    Комментировать
  • Как склеить 2 и более изображения с помощью поиска локальных особенностей?

    Vindicar
    @Vindicar
    RTFM!
    Можно сделать так:
    1. Вычисляешь матрицу преобразования, которому нужно подвергнуть изображение 2, чтобы склеить его с изображением 1 (далее, 2->1).
    2. Вычисляешь матрицу преобразования 3->2.
    3. Склеиваешь 3 с 2, используя матрицу 3->2.
    4. Склеиваешь сумму 3 и 2 с 1, используя матрицу 2->1.
    Альтернативно, ты можешь подвергнуть 3 преобразованию 3->2, а потом 2->1 (либо последовательно, либо перемножив их матрицы), чтобы перевести его в систему отсчёта изображения 1, и склеить их непосредственно.

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

    Ещё я не вполне понял, что ты имеешь ввиду под "панорамное изображение".
    Но я подозреваю, это может быть вызвано тем, что на выбранном корневом (первом) изображении ракурс отличается от "нормального" - строго перпендикулярного целевой плоскости. Тогда тебе нужно выбрать такое изображение, на котором ты можешь более-менее точно определить целевую плоскость. ТУт может помочь какой-нибудь маркер типо QR-кода, aruco-маркера, да хоть банальный шахматный шаблон (с ним, кстати, проще всего). Главное, чтобы его размер был известен, и он был прямоугольный. Тогда можно будет рассчитать преобразование для этого изображения, которое исправит перспективу. Мы будем "смотреть прямо" на плоскость, где расположен этот шаблон. Это исправленное изображение и будет для нас корневым, к которому мы будем "пристёгивать" остальные.
    Ответ написан
    Комментировать
  • Как в openai обойти ошибку openai.PermissionDeniedError?

    Vindicar
    @Vindicar
    RTFM!
    Сделать так, чтобы openai не понял, что вы в России.
    Как хотите, но ваш туннель должен терминироваться на зарубежном хосте, и только потом идти к ним.
    Либо ставьте бота туда, либо поднимайте там прокси с авторизацией, либо городите VPN...
    Ответ написан
  • Как перезапустить бота через команду на Windows?

    Vindicar
    @Vindicar
    RTFM!
    Увы, под виндой достучаться до менеджера служб куда сложнее.
    Вариант А: оформить бота как службу через утилиту вроде NSSM.
    Тогда для перезапуска можно попробовать выполнить
    cmd.exe /C "net stop имя_твоей_службы && net start имя_твоей_службы"

    Ну или закинуть эту строку в cmd-файл и запускать уже его. Но поскольку подкоманды restart нет, то я не знаю, доживёт ли твой скрипт до выполнения net start.
    Вариант А2: то же самое, но использовать ctypes для обращения к Service Control Manager через WinAPI. Сразу скажу, это сложнее.

    Вариант Б: Очень примитивный, но корявый способ - завернуть запуск бота в батник(cmd-файл), где запускать бота в вечном цикле с ожиданием, и перезапускать его, если бот завершился с ненулевым кодом завершения.
    Что-то типа
    :restart
    python bot.py
    IF ERRORLEVEL 1 GOTO restart

    ERRORLEVEL проверяет, что код завершения больше или равен указанному.
    Тогда, если надо завершить работу бота, делаешь sys.exit(0), а для перезапуска sys.exit(1). Бонус: бот также перезапустится при непойманном исключении.

    Вариант В: Запустить скрипт бота напрямую, скажем, через os.startfile(sys.argv[0]), и сразу же выйти самому. Но приведённый вариант не дружит с виртуальным окружением, так что может потребоваться модификация вроде
    os.startfile('/path/to/venv/python3', 'open', sys.argv[0])
    . Если нужно ещё и параметры командной строки передать, дело усложняется.
    Ответ написан
    Комментировать
  • Как сделать чтоб функция принимала целый класс статусов в aiogram?

    Vindicar
    @Vindicar
    RTFM!
    Вроде ты можешь просто передать желаемый StatesGroup при регистрации команды - так же, как ты регистрируешь команду для конкретного состояния.
    Ответ написан
  • Как сжать и закодировать данные так, чтобы их можно было отправить в теле запроса на сервер?

    Vindicar
    @Vindicar
    RTFM!
    У тебя различие появляется в том, что gzip.compress() даёт не тот же результат, что был подан в gzip.decompress().
    Видимо, разные реализации алгоритма gzip. Но если данные успешно разжимаются, то не всё ли равно?

    EDIT: я посмотрел инфу о заголовке Gzip. Создать идентичный заголовок несложно, но проблема идёт дальше: сами данные непохожи. Я раскопал, как получить "голый" deflate-поток без заголовков, и попытался сравнить его с тем, что идёт после gzip-заголовка в твоих данных. В твоём случае заголовок минималистичный, поэтому занимает всего 10 байт, а дальше идёт deflate-поток. Он успешно разжимается в те же данные, которые даёт gzip, так что я вроде не ошибся.

    Но попытка перебора вариантов сжатия так, чтобы получить хоть что-то похожее, результатов не дала.
    Вот мой код, увы, он выводит Match not found.
    import binascii, gzip, zlib, sys
    
    def deflate(data, compresslevel=9, strategy=0, wbits=zlib.MAX_WBITS, memlevel=zlib.DEF_MEM_LEVEL):
        compress = zlib.compressobj(
                compresslevel,        # level: 0-9
                zlib.DEFLATED,        # method: must be DEFLATED
                -wbits,               # window size in bits:
                                      #   -15..-8: negate, suppress header
                                      #   8..15: normal
                                      #   16..30: subtract 16, gzip header
                memlevel,             # mem level: 1..8/9
                strategy              # strategy:
                                      #   0 = Z_DEFAULT_STRATEGY
                                      #   1 = Z_FILTERED
                                      #   2 = Z_HUFFMAN_ONLY
                                      #   3 = Z_RLE
                                      #   4 = Z_FIXED
        )
        deflated = compress.compress(data)
        deflated += compress.flush()
        return deflated
    
    def inflate(data):
        decompress = zlib.decompressobj(
                -zlib.MAX_WBITS  # see above
        )
        inflated = decompress.decompress(data)
        inflated += decompress.flush()
        return inflated
    
    
    input_data = b"H4sIAAAAAAAA_2SNvU7EMBAG32V7To7txMleB-JKWugsc-wllhI78k8iQLw7sgPVdauZHX0GFX5H7BHMumpnFoJzRIGw03u5muYwG4VovStIIaiT4OLE6gNDuE7GOZq1_SiEdwiZ2wf59Rjy8-vLdnm67Ref_e1t_BxrI2uTtMlp8qF2FlkxLcI1h0Au6RzpX_VStQ1X8li3iZY_IQbVDl3HWX-OOCBEmuf76ucXAAD__wEAAP__grfYVeYAAAA"
    gzipped_data = binascii.a2b_base64(input_data.replace(b"_", b"/").replace(b"-", b"+") + b"=")
    raw_data = gzip.decompress(gzipped_data)
    print('RAW', raw_data)
    
    deflate_stream = gzipped_data[10:]
    inflated = inflate(deflate_stream)
    print('DEFLATED DATA', deflate_stream)
    print('RESTORED DATA', inflated)
    print('Restored data matches original:', inflated == raw_data)
    
    for level in range(1, 10):
        for strategy in range(0, 5):
            for wbits in range(9, 16):
                for memlevel in range(1, 10):
                    test = deflate(raw_data, level, strategy, wbits, memlevel)
                    if deflate_stream.startswith(test) or test.startswith(deflate_stream):
                        print(level, strategy, wbits, memlevel)
                        sys.exit(0)
    else:
        print('No match found')
    Ответ написан
    1 комментарий
  • Проблема с парсингом сайта, кракозяблы и непонятные символы вместо HTML?

    Vindicar
    @Vindicar
    RTFM!
    Сайт утверждает, что отдаёт Content-Type: text/html;charset=utf-8.
    Попробуй сохранить в файл и открыть тем же Notepad++.
    Ответ написан
  • Как сделать чтобы извлекался user_id пользователя, а не бота?

    Vindicar
    @Vindicar
    RTFM!
    Читаем доки telebot.
    https://docs.python-telegram-bot.org/en/stable/tel...
    message (telegram.MaybeInaccessibleMessage, optional) - Message sent by the bot with the callback button that originated the query

    Выделение моё. Теперь понятно, почему ты получаешь id самого бота?
    А если чуть выше глянуть, там ещё интереснее.
    from_user (telegram.User) – Sender.


    Привыкай находить и читать документацию, там много интересного.
    Ответ написан
    1 комментарий
  • Как работает Jinja?

    Vindicar
    @Vindicar
    RTFM!
    В рамках веб-стэка питон код не может выполняться на клиенте. Учи основы.
    Вся работа Jinja выполняется на бэкэнде. Проверить легко - открой исходник страницы (Ctrl-U по умолчанию), и ты увидишь, что пришло в браузер от сайта.
    Ответ написан
    Комментировать
  • Задание из практикума, не могу сделать уже целую неделю. Какие есть ошибки?

    Vindicar
    @Vindicar
    RTFM!
    У тебя как минимум один косяк в expire().
    for title, batches in items.items():
        for batch in batches:
            if batch['expiration_date'] and batch['expiration_date'] < today:
                expiring_items.append({'title': title, 'expiration_date': batch['expiration_date']})
                break  # <--- ???

    Ты находишь первую "протухшую" партию для товара, и сразу же переходишь к следующему товару. А если у одного товара несколько "протухших" партий?
    Ответ написан
    Комментировать
  • Появилась проблема при запуске приложения Python в Termux?

    Vindicar
    @Vindicar
    RTFM!
    Если нужен красивый визуал в командной строке под никсами, может, стоит использовать модуль curses?
    Ответ написан
  • Где и как в Pycharm можно проанализировать код на вызовы или использование не объявленных методов\полей?

    Vindicar
    @Vindicar
    RTFM!
    Ide подсвечивает такие опечатки, но реально на них можно напороться только при исполнение кода

    Про линтеры выше написали, а я добавлю: PyCharm позволяет просмотреть список всех наденных проблем (errors, warnings) в проекте. Если он не пустой - значит, надо чинить.
    Ответ написан
  • Бот на python/telebot не приветствует новых пользователей, что не так?

    Vindicar
    @Vindicar
    RTFM!
    А почему ты вызываешь bot.polling()? Это для асинхронных ботов, а твой синхронный. Используй infinity_polling().
    Вообще, читай официальные примеры, вроде вот этого, и сравнивай со своим кодом.
    Ответ написан
  • Как исключить ввод пустой строки?

    Vindicar
    @Vindicar
    RTFM!
    Тебе нужно повторять ввод аргументов, пока пользователь не введёт их правильно? Ну вот и повод почитать про циклы.
    while True:  # бесконечный цикл
      x_str = input('Введите x:')  # вводим число
      try:  # внутри блока try мы будем отлавливать ошибки - исключения
        x = float(x_str)  # пробуем преобразовать строку в число
      except ValueError:  # в случае чего float() выкинет исключение ValueError
        print(x_str, 'это не число. Попробуйте ещё раз.')  # сообщаем пользователю
      else:  # если ошибки не было
        break  #  то прерываем цикл, у нас в x лежит нужное значение
      # мы делаем break только в ветке else - значит, пока отрабатывает ветка except, цикл продолжится

    В принципе, если тебе нужна только одна попытка, ты можешь вытащить блок try-except из цикла, убрать ветку else, и заменить ветку except на что-то типа:
    except ValueError:
      print(x_str, 'это не число. У вас есть ещё одна попытка')  # сообщаем пользователю
      x_str = input('Введите x: ')
      x = float(x_str)

    Тогда получится обойтись без циклов.

    Но без try-except обойтись сложнее. Да, ты можешь предварительно проверить строку на соответствие шаблону десятичного дробного числа, но честно? try-except куда проще, так что стоит его освоить. Главное - не "глотай" ошибки, реагируй на них.
    Ответ написан
    Комментировать
  • Как подсветить функцию как устаревшую?

    Vindicar
    @Vindicar
    RTFM!
    66a00bc093f98796053667.png
    У меня всё работает. Смотри настройки IDE, в частности, File->Settings->Editor->Inspections, ищешь "deprecate".
    Ответ написан
  • Питон,нейросеть, алгоритм выхода из лабиринта?

    Vindicar
    @Vindicar
    RTFM!
    Общая идея задачи. как я её понял: дрон с воздуха снимает лабиринт, затем алгоритм сшивает кадры в одно изображение, извлекает форму лабиринта и строит путь по нему. Так? Если так, это должно было быть в вопросе.

    У тебя три чётко видимых шага.
    1. Сборка карты лабиринта по видео с дрона. Я бы для начала использовал поиск локальных особенностей (SIFT, углы по Харрису, или что-то столь же простое).
    Вопрос 1
    Что использовать - сильно зависит от условий съёмки. Чем более контрастные элементы присутствуют на изображении, тем лучше.

    Они обычно не позволяют работать в реальном времени, но это для задачи и не требуется. Затем, зная позиции особенностей на каждом изображении, сравниваем их с "соседними" изображениями.
    Вопрос 2
    Тут будет большой вопрос, касающийся определения соседних изображений. Простой ответ: считаем соседними N последних кадров, но тут могут быть проблемы с длинной цепочкой кадров. Например, если дрон сделает круг, не факт, что на карте этот круг сомкнётся. Может потребоваться какая-то оценка позиции снимка.

    По итогам сравнения мы получим проективное преобразование, описывающее, как надо повернуть/наклонить/растянуть/etc один кадр, чтобы совпали общие с соседним кадром части. Подвергнув кадр такому преобразованию, мы сможем все кадры привести к одной плоскости.
    Вопрос 3
    Скорее всего, возможные преобразования будут на нескольких кадрах, так что придётся их как-то ранжировать, и "усреднять" несколько наилучших преобразований с ближайшими соседями

    Тогда постепенно построите одно изображение-карту, а уж дальше его можно будет обрабатывать обычными средствами. Там, пороговое преобразование или что для выделения "стен", определение границ лабиринта, и дальше уже тупой flood-fill для поиска пути.
    Ответ написан
    1 комментарий
  • Почему выводит ошибку Traceback (most recent call last) при сохранении json словаря в переменную?

    Vindicar
    @Vindicar
    RTFM!
    Читаем и осознаём текст ошибки. UnicodeDecodeError - ошибка декодирования строки байт в юникод-строку, т.е. косяк с кодировками. В списке traceback ищем последний элемент, который ссылается на твой код.
    File "C:\Users\Maks\PycharmProjects\pythonProject7\main.py", line 57, in check_news_update
        news_dict = json.load(file)

    Т.е. косяк при чтении json из файла. При вызове load() кодировку нельзя указать, так что проверяем, откуда приходит файл.
    with open('news_dict.json') as file:  # где encoding? где режим открытия?
            news_dict = json.load(file)

    Вот и ошибка - не указана кодировка (и я бы явно указал режим открытия 'rt'). Причём при сохранении не забыл ведь указать...
    with open("news_dict.json", "w",encoding="utf-8") as file:  # а тут всё правильно
                json.dump(news_dict, file, indent=4, ensure_ascii=False)
    Ответ написан
    Комментировать