Задать вопрос
  • Как остановить выполнение функции в тг боте?

    Vindicar
    @Vindicar
    RTFM!
    cards = trees() #ФУНКЦИЯ ПАРСИНГА
    Ну вот тут уже проблема. Ты в асинхронном боте делаешь длительный синхронный вызов.
    Перепиши свой парсер на асинхронный код, запусти его через asyncio.create_task() и сохрани полученный объект задачи в глобальную переменную (если у тебя может быть не более одного активного парсера).
    Для отмены проверь, что в глобальной переменной лежит не None, а искомый объект. Если так, то вызови у него метод cancel().
    Это спровоцирует исключение CancelledError в функции парсера, что позволит прервать её выполнение, но в то же время аккуратно отработать освобождению ресурсов и т.п.
    Ответ написан
    Комментировать
  • Как заменить/обновить данные в sqlite (Python)?

    Vindicar
    @Vindicar
    RTFM!
    Во-первых, следует различать сценарий "я знаю, что строка есть, её надо обновить" (UPDATE) и "строки может не быть, если так, её надо создать" (INSERT OR REPLACE или INSERT ON CONFLICT UPDATE). Уточни, какой у тебя.

    Во-вторых, приведи код создания таблицы. У тебя link - первичный ключ?
    Ответ написан
  • Как запустить асинхронную функцию внутри синхронной flask?

    Vindicar
    @Vindicar
    RTFM!
    Ну для начала, проверка на вменяемость. Асинхронному боту для работы нужен рабочий цикл-реактор (event loop). Где и как ты его запускаешь, с учётом того, что Flask тоже требует рабочий цикл, а у тебя, вроде как, один поток?

    Я бы посоветовал использовать асинхронный веб-фреймворк. Например, доки на Flask упоминают Quart как максимально похожий, но изначально асинхронный фреймворк. Тебе всё ещё придётся разобраться, как параллельно запустить две длительные корутины (рабочий цикл Quart и рабочий цикл бота), но это уже решаемо. Вместо Quart можно использовать любой другой асинхронный веб-фреймворк.

    Альтернативно, можно запустить фласк и бота в разных потоках. Мешать асинхронность с многопоточностью - тоже та ещё идея, но если очень неохота уходить от Flask, то можно попробовать. Однако в этом случае нужно будет очень осторожно выполнять вызовы методов бота. В документации есть пример, как вызвать корутину в другом потоке ОС и дождаться ответа от неё.
    Ответ написан
    1 комментарий
  • Как создать новый словарь, не меняя старый?

    Vindicar
    @Vindicar
    RTFM!
    rows = self.rows
    НО! В тоже время изменяется из self.rows, который является другим списком.

    Не является. Твой оператор просто присвоил переменной rows ссылку на тот же самый список, что и self.rows.
    Это легко проверить оператором is или сравнением id():
    print(rows is self.rows, id(rows) == id(self.rows))  # True True

    Более того, если ты только скопируешь сам список:
    rows = self.rows.copy()
    То всё ещё поймаешь проблемы, так как скопируются ссылки на элементы, а не их значения:
    print(rows is self.rows, id(rows) == id(self.rows))  # False False
    print(rows[0] is self.rows[0], id(rows[0]) == id(self.rows[0]))  # True True

    Тебе нужно сделать глубокую копию (deepcopy). Это можно сделать вручную, так как у тебя всего два уровня вложенности (список-словарь):
    rows = [rowdict.copy() for rowdict in self.rows]
    Для более глубоких уровней есть функция copy.deepcopy(), но у неё есть свои подводные камни. Цитата:
    Two problems often exist with deep copy operations that don’t exist with shallow copy operations:
    Recursive objects (compound objects that, directly or indirectly, contain a reference to themselves) may cause a recursive loop.
    Because deep copy copies everything it may copy too much, such as data which is intended to be shared between copies.
    Ответ написан
    Комментировать
  • Зачем нужен декоратор @dp и все в этом духе, типо @dp.message_handler() в aiogram?

    Vindicar
    @Vindicar
    RTFM!
    На пальцах: чтобы бот работал, его функции должны вызываться при наступлении определённых событий (например, входящего сообщения). Проблема в том, что aiogram знает о возможных событиях, но ему нужно сказать, какие функции когда вызывать. Обычно это называется "зарегистрировать обработчик".
    В питоне функции - объекты первого рода, т.е. их можно сохранять в переменные, передавать как параметры, возвращать как результат и вообще поступать с ними как с любым другим значением.
    Т.е. по идее можно было бы сделать так:
    async def echo(message: Message):
        text = f"Привет, ты написал {message.text}"
        await bot.send_message(chat_id=message.from_user.id, text=text)
    
    dp.register_function_for_message(echo)  # это не настоящий метод aiogram, только пример

    Тогда каждому объявленному обработчику событий соответствовал бы вызов метода, ответственного за регистрацию этого обработчика.

    Но то же самое можно сделать через декораторы. Декоратор - это сокращённый вызов функции, которая принимает в качестве параметра другую функцию.
    Т.е. вот это
    @dp.message_handler()
    async def echo(message: Message):
        text = f"Привет, ты написал {message.text}"
        await bot.send_message(chat_id=message.from_user.id, text=text)

    абсолютно эквивалентно вот этому
    _decorator = dp.message_handler()
    
    async def echo(message: Message):
        text = f"Привет, ты написал {message.text}"
        await bot.send_message(chat_id=message.from_user.id, text=text)
    
    echo = _decorator(echo)

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

    Vindicar
    @Vindicar
    RTFM!
    split() разбивает по пробельным символам. У тебя в списке list_of_words будет 'Москва.', а не 'Москва' и '.'
    Ответ написан
    2 комментария
  • Почему в приведенном примере есть разница в расположении raise StopAsyncIteration?

    Vindicar
    @Vindicar
    RTFM!
    Я подозреваю, что по исчерпанию self.r (а range() - это не список, это одноразовая последовательность!) попытка вхождения в async for x in self.r приведёт к тому, что self.r просигнализирует об исчерпании последовательности. Как следствие, тело async for не выполнится ни разу, и управление выйдет за цикл. А за циклом - ничего, конец корутины. Поэтому, так как явного return не было, будет неявный return None. Что ты и наблюдаешь.
    Соответственно, ты никогда не получишь выброс StopIteration - его будет выкидывать self.r.__anext__(), но исключение будет перехватываться async for.
    Так что нужно добавить raise StopIteration() после async for, чтобы по опустошению self.r оно гарантировано выбрасывалось.
    Ответ написан
    1 комментарий
  • Aiogram как перейти на другой @dp message_handler()?

    Vindicar
    @Vindicar
    RTFM!
    Что у тебя за каша с вложенными обработчиками? Нет никаких гарантий, что это вообще будет работать.
    Научись пользоваться finite state machine.
    Ответ написан
    Комментировать
  • Как определять количества целых чисел на отрезке, интервале, полуинтервале?

    Vindicar
    @Vindicar
    RTFM!
    Разбей задачу на меньшие.
    1. Научиться разбирать входную строку. Можно регулярными выражениями, можно вручную с помощью split().
    В итоге у тебя должно быть 4 значения: начало интервала, входит ли начало (открытый/закрытый левый край), конец интервала, входит ли конец (открытый/закрытый правый край).
    2. Найти количество чисел в интервале.
    2.1. Округли левый край вверх (math.ceil()) чтобы найти первое целое число, входящее в интервал. Если результат округления равен левому краю И интервал открыт слева, прибавь к числу 1.
    2.2. Округли правый край вниз (math.floor()) чтобы найти последнее целое число. Если результат округления равен правому краю И интервал открыт справа, вычти из числа 1.
    2.3. Зная первое и последнее целое число, входящее в интервал, нужно вычесть первое из последнего и прибавить 1. Т.е. если первое число 2 а последнее 4, то в интервале 4 - 2 + 1 = 3 числа (2, 3, 4).
    Вот и всё. На питон переведёшь самостоятельно.
    Ответ написан
    1 комментарий
  • Как навсегда изменить цвет кнопки при нажатии в Python?

    Vindicar
    @Vindicar
    RTFM!
    Свяжи обработчик событий с кнопкой.
    Заведи глобальную переменную, которая считает, сколько раз была нажата кнопка.
    В обработчике событий читай эту переменную, увеличь её на 1, в зависимости от значения вызывай self.pushButton.setStyleSheet() с разными стилями.
    Ответ написан
    1 комментарий
  • Как правильно использовать run_in_executor?

    Vindicar
    @Vindicar
    RTFM!
    Ну для начала посмотри пакет arsenic, это селениум с асинхронной обёрткой. Можно будет переписать твой парсер на асинхронный подход, и не париться по поводу блокировки бота.
    Ответ написан
    Комментировать
  • Почему response.json( ) после fetch асинхронен?

    Vindicar
    @Vindicar
    RTFM!
    Потому что получение ответа от сервера - не то же самое, что получение контента. Скорее всего, мы получили только заголовки ответа, а в рамках соответствующих методов типа json() мы получаем тело ответа и парсим его.
    Ответ написан
    Комментировать
  • Как работает перенаправление вывода скрипта python?

    Vindicar
    @Vindicar
    RTFM!
    Скорее всего, проблема в работе с одним файлом через два дескриптора (один - stdout твоего скрипта, второй - stdout вызываемого). Попробуй принудительно сбрасывать данные в файл:
    print('Пытаемся запустить файл 1:', flush=True)
    Ответ написан
    1 комментарий
  • Фундаментальное отличие async await в python и javascript?

    Vindicar
    @Vindicar
    RTFM!
    Разницы нет, в том числе в твоём описании.
    Текущая корутина при await-вызове приостанавливается, её состояние сохраняется.
    При этом реактор может заниматься другими вещами (в частности, выполнением await-вызова).
    Когда await-вызов завершиться, состояние корутины будет восстановлено, и она продолжит выполнение.
    Ответ написан
    4 комментария
  • Что делать, если команда работает только если каждый раз перезапускать бота?

    Vindicar
    @Vindicar
    RTFM!
    Подозреваю, что async with p2p закрывает соединение с сервисом, с которым ты пытаешься работать. Собственно, with обычно для этого и предназначен - для высвобождения ресурсов.
    Либо переоткрывай клиента перед with, либо не используй with.
    Ответ написан
    Комментировать
  • В Pycharm код выполняется, из винды нет, почему?

    Vindicar
    @Vindicar
    RTFM!
    Открой окно терминала (cmd.exe), перейди в каталог скрипта, запусти его командой python myscript.py.
    Тогда окно терминала останется по завершению скрипта, и ты сможешь увидеть, что скрипт написал.
    Ответ написан
    Комментировать
  • Как получить результат выполнения задачи в Asyncio?

    Vindicar
    @Vindicar
    RTFM!
    await tay
    Угадай с трёх раз, что возвращает это выражение?
    Правильно. Значение, которое вернёт корутина, запущенная в рамках задачи. Просто присвой его переменной.
    А вообще в твоём случае и задачи-то не требуются.
    Освой asyncio.gather().
    Она позволит выполнить переданные корутины одновременно, и вернёт массив их результатов.
    results = await asyncio.gather(coro1(x,y), coro2(a,b), ...)
    res1, res2, ... = results
    Ответ написан
    Комментировать
  • Как в Python присвоить объекту класс, если имена классов хранятся в списке?

    Vindicar
    @Vindicar
    RTFM!
    Например, так.
    class KnownClasses:
        # используем статическое поле класса, 
        # так как к нему проще получить доступ из разных модулей
        collection: typing.Dict[str, typing.Type] = {}
    
    class SomeKnownClass:
        ...  # тут тело класса
    
    # регистрируем класс
    KnownClasses.collection[SomeKnownClass.__name__] = SomeKnownClass

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

    Vindicar
    @Vindicar
    RTFM!
    Запустить и пусть работает.

    Не, кроме шуток. Каков вопрос - таков ответ.
    Нужна машина, которая включена и подключена к сети 24/7. Например, арендованная VPS.
    Также нужно предусмотреть наиболее вероятные исключения в боте, отловить и обработать их.
    Также стоит предусмотреть средства аварийного перезапуска. Например, если на VPS установлен Debian-подобный дистрибутив, то можно оформить запуск бота через systemd. Это гарантирует перезапуск программы при перезагрузке, а также при его аварийном завершении.
    Ответ написан
    Комментировать