Задать вопрос
  • Правильное разбиение числа на группы, как реализовать?

    Vindicar
    @Vindicar
    RTFM!
    Делишь N на 40, округляешь вверх, получаешь число групп, на которые нужно разделить.
    Смотри math.ceil()
    Зная число групп, определить размер группы уже несложно.
    Ответ написан
    Комментировать
  • AttributeError: 'NoneType' object has no attribute 'text'?

    Vindicar
    @Vindicar
    RTFM!
    card_title = card_product.find("h3", class_ = "card_title").text

    На странице, URL которой ты привёл, вообще нет тега h3, похоже. h4 есть, в том числе с классом card_title.
    Ответ написан
  • Sqlachemy, менять параметры в зависимости от условий?

    Vindicar
    @Vindicar
    RTFM!
    **kwargs?
    kwargs = dict(  # общая часть
            name = importRow['nameLinkCompetitor'],
            link = importRow['linkCompetitor'],
            article = importRow['articleCompetitor'],
            price = importRow['priceCompetitor'],
            discount_price = importRow['discountPriceCompetitor'],
    )
    # условная часть
    if competitorId:
            kwargs['competitor'] = competitorId
    p = Product(**kwargs)  # и дальше используем p
    Ответ написан
    Комментировать
  • Как правильно получить Bot.fetch_user() в Disnake?

    Vindicar
    @Vindicar
    RTFM!
    Поясню ответ выше: ты вызываешь метод на классе Bot, а не на экземпляре этого класса в переменной bot. Будь внимательнее.
    Ответ написан
    Комментировать
  • Что означает это ошибка и как его исправить?

    Vindicar
    @Vindicar
    RTFM!
    Ты пытаешься запустить асинхронный код с рабочим циклом (reactor loop) в отдельном потоке.
    Прежде чем пытаться такое сделать, нужно очень хорошо понимать, как работает asyncio, и ознакомиться с соответствующим разделом документации. А также про другие особенности .

    Но если коротко: asyncio создаёт рабочий цикл автоматически только для главного потока. Для остальных потоков его надо создать и задать самому через вызовы new_event_loop() и set_event_loop(). И сделать это лучше сразу же при запуске потока.

    А вообще, я бы использовал FastAPI вместо Flask, он вроде бы честно поддерживает asyncio, а потому может получиться избежать всей возни с потоками.
    Ответ написан
  • При разбиении пути возникает ошибка. Как пофиксить?

    Vindicar
    @Vindicar
    RTFM!
    Читай документацию же.
    The return value is a tuple (type, encoding) where type is None if the type can’t be guessed (missing or unknown suffix) or a string of the form 'type/subtype', usable for a MIME content-type header.

    Т.е. для неизвестных типов у тебя в ftype попадёт None, а ты этого не проверяешь.

    EDIT: А вообще есть смысл делать guess_type()? Если у тебя тип файла известен заранее, то можно захардкодить и правильный mime-тип.
    Ответ написан
    Комментировать
  • Как изменить по имени сортировку списка?

    Vindicar
    @Vindicar
    RTFM!
    Потому что сортировка строк (например, имён файлов) - это лексикографическое сравнение. В этом сравнении "б" > "аааааааааа", просто потому что "б" > "а". Другое дело, что у человеков очень странные представления о порядке, и компьютеру трудно к ним адаптироваться.

    Если тебе нужен т.н. естественный порядок (natural sorting), тебе нужно как-то выцепить из имени тот кусок, по которому нужно делать сравнение. Например, так:
    import re
    PARTS = re.compile(r'^(.+?)(?:(\d+)\D+)?$')
    
    def natural_sort_key(fname: str):
        "Функция извлекает из имени файла описание, по которому его надо сортировать."
        prefix, index = PARTS.match(fname).groups()
        return (prefix, int(index) if index else 0)
    
    
    lst.sort(key=natural_sort_key)
    Ответ написан
  • Что я делаю не так с register_message_handler в aiogram?

    Vindicar
    @Vindicar
    RTFM!

    dp.register_message_handler(answer3, state=get_answer.answer3)
    db.register_message_handler(answer4, state=get_answer.answer4)

    У тебя в паре месте перепутано dp и db.
    Короткие названия они такие... коварные.
    Ответ написан
  • Для чего нужен lock в python? Как работает данный пример кода?

    Vindicar
    @Vindicar
    RTFM!
    Это объясняется тем, что в базовом питоне потоки не вполне честные - они конкурируют за global interpreter lock, так что код выполняется всё равно поочерёдно. Так что многопоточность в питоне полезна с точки зрения распараллеливания, но не ускорения. ЕМНИП, есть реализации питона, в которых нет этой GIL problem.
    Но нужно иметь ввиду, что этот GIL блокирует только элементарные операции (как в твоём примере), тогда как явное использование lock может накрывать целые блоки кода, состоящие из нескольких операций с защищаемым ресурсом.

    Вот тебе пример:
    import threading
    import time
    
    class Data:
        def __init__(self):
            self.x: int = 0
            self.y: int = 0
    
    
    do_sleep = False
    run = True
    
    
    def reader(d: Data):
        while run:
            x, y = d.x, d.y
            # по идее это условие не должно выполниться никогда
            if (x != 0) != (y != 0):  
                print(f'Got x={x} and y={y}')
            else:
                print(f'OK {x}', end='\x08\x08\x08\x08')
    
    
    def writer(d: Data):
        while run:
            if d.x == 0:
                d.x = 1
                if do_sleep: pass
                d.y = 1
            else:
                d.x = 0
                if do_sleep: pass
                d.y = 0
    
    
    do_sleep = False
    instance = Data()
    reader_thread = threading.Thread(target=reader, args=(instance,), daemon=True)
    writer_thread = threading.Thread(target=writer, args=(instance,), daemon=True)
    reader_thread.start()
    writer_thread.start()
    try:
        input()
    finally:
        run = False
        reader_thread.join()
        writer_thread.join()


    На моей машине, если if do_sleep: pass закомментировать, то в консоли высвечивается только OK - иными словами, присваивание двух полей выполняется достаточно быстро, чтобы поток не успел переключиться в промежутке. Как следствие, reader() всегда видит либо x=0 y=0, либо x=1 y=1.
    Но если if do_sleep: pass оставить, то выполнение тела цикла замедляется достаточно, чтобы поток успел переключиться - и, как следствие, reader() начинает видеть структуру данных Data в неконсистентном состоянии, когда x=0 y=1 или когда x=1 y=0.
    И вот чтобы не гадать "успеет - не успеет", нужно в таких случаях защищать связные серии обращений к структуре с помощью мьютекса, ну или в питоновских терминах - Lock.
    Ответ написан
    Комментировать
  • Почеум при использывании функции click() библиотеки pyautogui курсор не кликает?

    Vindicar
    @Vindicar
    RTFM!
    А ты уверен, что на момент выполнения click() окно браузера уже существует? Сколько времени он открывается?
    И вообще, открывать URL кликом по закреплённой закладке - ну такое себе. Чем тебе webbrowser.open() не угодил?
    Ответ написан
    1 комментарий
  • Атрибуты дочернего класса в родительском?

    Vindicar
    @Vindicar
    RTFM!
    Нет, так как код CacheManager вообще ничего не знает про свои дочерние классы.
    С другой стороны, почему у тебя все методы декорированы staticmethod? Если бы это был classmethod, то тогда при вызове Info.extract метод extract() хотя бы смог бы понять, что его вызывает на классе Info, а не CacheManager.
    Ответ написан
  • Как с Python получить текст из DOCX с сохранением форматирования?

    Vindicar
    @Vindicar
    RTFM!
    Ну смотри. В DOCX текст хранится в виде интервалов (runs), где интервал - это последовательность символов с одинаковым форматированием. Можно получить список интервалов в абзаце через свойство docparagraph.runs.
    А дальше для каждого интервала определяешь интересующие тебя свойства форматирования, достаёшь текст, и имитируешь это форматирование с помощью markdown (ну или какие там ещё языки разметки поддерживает нужный тебе мессенджер). Результаты склеиваешь в одну строку и отправляешь.

    Кое-что есть в документации, но она явно неполная, так что остальное придётся искать в исходниках классов Paragraph и Run.
    Ответ написан
    3 комментария
  • Как удалить пакеты которые не используются в проекте из виртуального окружения?

    Vindicar
    @Vindicar
    RTFM!
    Потому что надёжного метода анализа зависимостей нет.
    Импорты в питоне могут быть условными, выполняться в разное время, или вообще выполняться динамически через importlib.
    Я бы сказал, вспомнить, какие пакеты тебе требуются, очистить окружение, поставить их, погонять приложение и пособирать недостающее.

    А на будущее - когда тестируешь пакет, делай отдельную ветку в системе управления версиями, и отдельное окружение. Только когда пакет устоялся, делаешь merge.
    Ответ написан
    Комментировать
  • Как исправить ошибку взаемодействия Дискорд бота и окна?

    Vindicar
    @Vindicar
    RTFM!
    #
        loop = asyncio.get_event_loop()
        loop.create_task(process_bot_queue())
        loop.run_forever()

    Что вообще вот этот код делает в теле программы, если у тебя вызов create_window() не вернёт управление, пока окно GUI не будет закрыто?
    Ответ написан
    Комментировать
  • Можно ли поставить паузу и продолжить?

    Vindicar
    @Vindicar
    RTFM!
    цикл for, функция range(), функция time.sleep()
    Ответ написан
    Комментировать
  • Не меняется параметр call.data в тг-боте, почему и где я допустил ошибку?

    Vindicar
    @Vindicar
    RTFM!
    @dp.callback_query_handler()
    async def callback(call):
      await call.message.answer(f'Понял Принял! Теперь напиши пожалуйста, в каком городе будем смотреть {call.data}')
      print(call.data)
      @dp.message_handler(content_types=['text'])  # обработчик событий объявлен внутри другого?
      async def city(message: types.Message):

    Это НЕ будет работать так, как ты ожидаешь. При каждом выполнении callback() будет попытка добавить ещё один обработчик, но предыдущие обработчики так и останутся. А поскольку вызывается обычно только самый первый обработчик, то только самый первый вариант и будет обрабатываться.

    Открой для себя Finite State Machine, ну и в целом получи хоть какое-то представление как работает используемая тобой библиотека, что в ней можно делать, а что нельзя.
    Ответ написан
  • Как исправить ошибку взаимодействия окна и дискорд бота?

    Vindicar
    @Vindicar
    RTFM!
    В коде нет работы с потоками, ты даже не импортируешь threading.
    Нужно понимать три вещи:
    1. Рабочий цикл бота займёт весь поток, равно как и рабочий цикл tkinter. Совместить их практически невозможно (технически можно, но это очень нетривиально).
    2. Элементы GUI должны создаваться и использоваться строго в одном и том же потоке.
    3. Нельзя делать await вызовы из одного потока в другой.

    Поэтому я бы посоветовал такое грубое, но простое решение:
    В одном потоке потоке создавай event loop (сам! это важно!) и запускай бота. В другом потоке создавай и запускай GUI.
    Какой поток должен быть главным - скорее всего не принципиально. Попробуй оба варианта.
    Используй пару очередей (queue.Queue) для синхронизации между потоками.

    Одна очередь будет периодически проверяться в потоке GUI с помощью root.after(). Почитай документацию на этот метод, но если коротко - он позволяет запланировать вызов функции в потоке GUI через время. Эта очередь будет содержать сведения о том, что нужно обновить в GUI.
    Формат и смысл сведений определи сам. Это может быть что-то высокоуровневое в духе "есть сообщение от пользователя такого-то с таким-то текстом", и пусть поток gui сам разбирается, что с этим делать. Это может быть и что-то более низкоуровневое, типа "задай такому-то свойству у такого-то элемента управления такое-то значение". Я бы посоветовал первый вариант - он позволит разделить логику программы чётко на две части.
    Код проверки будет примерно вида
    def check_gui_queue():
        try:
            while True:
                command = gui_queue.get_nowait()  # проверяем, есть ли команда для GUI
                gui_queue.task_done()  # на каждый успешный вызов get() - один вызов task_done()
                pass  # как-то обрабатываем команду
        except queue.Empty:  # команды нет
            root.after(100, check_gui_queue)  # даём GUI поработать спокойно 100 мс

    Разумеется, если ты завернёшь GUI в класс (что имеет смысл) код немного изменится. Но суть останется прежней.

    Другая очередь будет содержать команды для бота. Периодически проверяй её в потоке asyncio с помощью простого кода вида
    async def check_bot_queue():
        while True:
            try:
                command = bot_queue.get_nowait()  # проверяем, есть ли новая команда для бота
            except queue.Empty:
                await asyncio.sleep(0.1)  # нет - даём другим корутинам поработать 100 мс
            else:
                bot_queue.task_done()  # на каждый успешный вызов get() - один вызов task_done()
                pass  # есть - как-то её обрабатываем

    Эту корутину запустишь через create_task(), и она позволит коду GUI организовывать вызовы в коде бота.

    Разумеется, придётся подумать, как аккуратно сделать, чтобы эти две функции не разрослись в дикую простыню из if-elif-else. Но общий принцип примерно такой.
    Время ожидания команды можно увеличить - это замедлит время реакции пре передаче данных между потоками, но уменьшит холостую нагрузку на систему.
    Ответ написан
    Комментировать