Задать вопрос
Ответы пользователя по тегу Python
  • Как исправить "RuntimeError: There is no current event loop in thread"?

    Vindicar
    @Vindicar
    RTFM!
    Очевидно, webdriver использует под капотом asyncio, который требует дополнительных телодвижений при работе с потоками.
    В частности, нужно в начале потока сначала вызвать asyncio.new_event_loop(), потом её результат скинуть в asyncio.set_event_loop(). Доки.
    Ответ написан
  • Почему генератор yield начинает работу с последней страницы сайта?

    Vindicar
    @Vindicar
    RTFM!
    data = soup.find_all('div', class_= 'col-lg-4 col-md-6 mb-4')

    Ты перезаписываешь data на каждой итерации цикла, конечно там остаётся только последнее записанное значение. Совмести оба цикла внутри get_url() в один, иначе нет особого смысла в yield.
    Ответ написан
    Комментировать
  • Как парсить текст при помощи python-docx?

    Vindicar
    @Vindicar
    RTFM!
    1. Оформленный код в студию.
    2. Формат разбираемого текста фиксирован, т.е. он всегда выглядит одинаково? Если да, регулярные выражения в помощь.
    Если нет... ну можешь попробовать задействовать пакет Natasha, но это из пушки по воробьям.
    Ответ написан
  • Как записать данные в столбик в csv формате?

    Vindicar
    @Vindicar
    RTFM!
    file_writer.writerow([name, subscribers, type, price])

    Ну так ты просишь записать в одну строку, он и записывает в одну строку.
    file_writer.writerows(zip(name, subscribers, type, price))


    zip() превратит отдельные списки ([имя, имя, ...], [подписчики, подписчики, ...], [тип, тип, ...], [цена, цена, ...]) в последовательность значений ([имя, подписчики, тип, цена], [имя, подписчики, тип, цена], ...)
    Ответ написан
    1 комментарий
  • Как сделать так, чтобы бот телеграмм пересылал данные, которые ввел пользователь в другой аккаунт?

    Vindicar
    @Vindicar
    RTFM!
    Смотри в сторону Finite State Machine.
    Если коротко, твой бот должен для каждого пользователя помнить, на каком этапе он находится, и обрабатывать события соответственно.
    "Я получил сообщение от Васи. Вася сейчас на этапе ввода имени. Значит, нужно записать текст сообщения как имя, попросить ввести номер, и перевести Васю на этап ввода номера."
    Многие библиотеки для чатботов уже имеют ту или иную реализацию FSM, как раз для реализации таких вот сценариев. Читай документацию на ту библиотеку, которую ты собираешься использовать.
    Если у неё этого нет, или эта реализация тебе почему-то не подходит, то можно попробовать наколхозить её самому. Как я уже говорил, всё, что реально нужно - для каждого пользователя помнить, на каком этапе он находится.
    Ответ написан
    Комментировать
  • Как правильно одновременно запустить двух Telegram ботов одной программой на Python?

    Vindicar
    @Vindicar
    RTFM!
    Ну потому что ты фигню написал.
    th_bot = Thread(target=pyrobot(), args=())
    th_userbot = Thread(target=aiobot(), args=())

    Ты пытаешься запустить в качестве потока значение, возвращаемое функцией pyrobot(). А так как она уходит в цикл и значения не возвращает, то далее ничего не происходит. До вызова конструктора Thread() дело не доходит. С aiobot() аналогично.

    Еще раз:
    pyrobot() - вызов функции
    pyrobot - ссылка на функцию

    EDIT:
    Оба бота - асинхронные на базе asyncio, им для работы нужен цикл-реактор (event loop). Вообще не факт, что хорошая идея запускать их в потоках.
    Тут есть два варианта, сразу даже не скажу, что проще.
    Вариант А, лобовой: каждый бот создаёт своё собственные реактор через asyncio.new_event_loop(), потом задаёт его как текущий для своего потока через asyncio.set_event_loop(loop). Если ботам не требуется взаимодействовать, то это может быть проще. Если требуется... будут проблемы. Два реактора в одной программе - это не хорошо.

    Вариант Б, адекватный:
    И вызов app.run(), и вызов executor.start_polling(dp, skip_updates=True) скорее всего под капотом создают асинхронную функцию (корутину), и запускают её в реакторе. Тогда ты можешь обойтись без потоков, заставив обоих ботов работать на одном реакторе. Нужно будет зарыться в доки, или даже глянуть исходники.

    Например, для пирограмма написано такое:
    When calling this method (app.run()) without any argument it acts as a convenience method that calls start(), idle() and stop() in sequence. It makes running a single client less verbose.

    Т.е. вместо вызова app.run() ты можешь изменить код так:
    async def pyrobot():  # обрати внимание, теперь функция асинхронная!
        print("pyro started")
        @app.on_message(filters.chat("some_chat"))
        async def print_pyrogram():
            print("Pyrogram")
        # это вместо вызова app.run(), как написано в доках.
        await app.start()
        try:
            await app.idle()
        finally:
            await app.end()

    Затем делаешь аналогичный трюк с aiobot(). Нужно посмотреть в доках на аиограм, как именно.

    И потом запускаешь обоих ботов кодом вида...
    asyncio.run(asyncio.gather(pyrobot(), aiobot()))
    Ответ написан
    3 комментария
  • Как составить число n из элементов списка?

    Vindicar
    @Vindicar
    RTFM!
    Я бы решал задачу рекурсивно.
    Найди в списке все числа x, меньшие или равные n, определи их позиции в списке, отсортируй по убыванию числа.
    Если в списке есть x, равное n, ответ найден.
    Иначе перебирай числа по порядку, от больших к меньшим, и для каждого числа x пробуй убрать его из списка, а потом рекурсивно решить задачу для суммы n-x.
    Т.е. что-то типа:
    def compose_sum(numbers: list[int], total: int) -> list[int] | None:
        # ищем индексы потенциальных слагаемых
        indices = [i for i in range(len(numbers)) if numbers[i] <= total] 
        # сортируем по убыванию слагаемых, потом по порядку в списке
        indices.sort(key = lambda i: (numbers[i], i), reverse=True)
        # если нулевой элемент совпадает - мы нашли точную сумму. Прерываем рекурсию.
        if numbers[indices[0]] == total: 
            return [indices[0]]
        for index in indices: # иначе перебираем слагаемые
            numcopy = numbers.copy()
            # копия списка без рассматриваемого слагаемого
            current = numpcopy.pop(index)
            next_indices = compose_sum(numcopy, total - current)
            if next_indices:  # нашли решение, корректируем индексы (так как мы удалили один элемент)
                for i in range(len(next_indices)):
                    if next_indices[i] >= index:
                        next_indices[i] += 1
                return [index] + next_indices # отдаём наше решение "наверх"
            # next_indices пуст/None - решения не нашли, пробуем другой index
        return None # не нашли решения ни для одного index
    Ответ написан
    Комментировать
  • Почему выводит не совсем правильно?

    Vindicar
    @Vindicar
    RTFM!
    Ты забыл последнюю сторону многоугольника.
    p += len_seg(x[-1],y[-1],x[0],y[0])
    Ответ написан
    Комментировать
  • Как реализовать код диаграммы uml с стрелками зависимости и ассоциации?

    Vindicar
    @Vindicar
    RTFM!
    линия и пунктир с треугольной стрелкой самые понятные, они просто наследуют классы

    Неверно. Сплошная стрелка - да, наследует классы. Пунктир - это реализация интерфейса (в терминах Питона это скорее typing.Protocol). Т.е. при реализации один участник (с меткой interface) описывает методы без их реализации, а второй - их реализует.

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

    Это скорее коллекция и элементы. Разница между агрегацией (пустой ромб) и композицией (закрашенный ромб) простая. В случае композиции элемент не имеет смысла вне содержащей его коллекции. Например, чат и сообщения - если сообщение не может быть вне чата, это композиция. А вот, скажем, контакт и группа контактов - агрегация, так как контакт может рассматриваться и иметь смысл вне группы, в которую он входит.
    И агрегация, и композиция - это частные случаи ассоциации. В случае ассоциации одному или нескольким экземплярам одного класса сопоставляется один или несколько экземпляров другого класса. Например, у сообщений в любом чате есть автор - это ассоциация один-ко-многим.

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

    Vindicar
    @Vindicar
    RTFM!
    Заверни тело файла (непосредственный вызов функций) в конструкцию
    if __name__ == '__main__':
    Этот if выполнится, только если файл запущен непосредственно, и не выполнится, если он импортирован.
    Ответ написан
    Комментировать
  • Почему выдает ошибку Cannot choose from an empty sequence?

    Vindicar
    @Vindicar
    RTFM!
    visit = random.choice(urls)
    У тебя в urls пусто на момент вызова функции.

    urls = []  # в urls пусто
    
    # тут ты только определяешь функцию, но не вызываешь её
    def createlist(ids):
        global urls
        for id in ids:
            urls.append("https://scrap.tf/raffles/" + id)
    # так что тут urls всё ещё пуст
    # внутри login() вызывается rufflejoin(). А urls всё ещё пуст.
    login()
    Ответ написан
    Комментировать
  • Как отправлять текст соответствующий картинке в телеграм боте на Python?

    Vindicar
    @Vindicar
    RTFM!
    1. вынеси random.choice(os.listdir('test')) в переменную, например, img
    2. используй os.path.splitext(os.path.basename(img))[0], чтобы получить имя файла картинки без расширения
    3. Не забудь отправить файл через photo = open('test/' + img, 'rb')
    4. PROFIT
    Ответ написан
    2 комментария
  • Как сделать актуализацию данных?

    Vindicar
    @Vindicar
    RTFM!
    Используй on_conflict. Он позволяет как молча проигнорировать втавляемые данные, так и частично обновить существующую строку.
    Причем достаточно конфликта по ключу (id пользователя).

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

    Vindicar
    @Vindicar
    RTFM!
    AttributeError: Can't pickle local object 'start.<locals>.f1'

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

    Vindicar
    @Vindicar
    RTFM!
    Ну вот тут ты столкнулся с проблемой изоляции изменений.
    Обозначим код, который предоставляет какую-то услугу, сервисом, а код, который эту услугу использует - клиентом.
    Тогда есть два типа изменений: изменение реализации сервиса и изменение интерфейса сервиса.

    Первое изменение затрагивает сервис, но необязательно затрагивает клиента. Если клиент обращается к сервису таким же образом, получает результат в таком же виде, получает сведения об ошибках таким же способом, то с точки зрения клиента изменения не было. Пусть даже в реальности сервис переписали с нуля.
    Пример: пусть у нас есть функция сортировки списка "на месте", т.е. изменяя этот список.
    def sort_list(original: list):
    Если раньше она сортировала список пузырьком, а потом мы её переписали на quicksort - с точки зрения кода, который эту функцию использует, ничего не изменится, кроме времени работы функции. Клиент все равно будет использовать функцию так:
    some_list = [ ... ]
    sort_list(some_list)


    Второй тип изменений меняет интерфейс сервиса, т.е. то, как он взаимодействует с клиентом.
    Продолжая пример, если мы решили, что теперь функция будет возвращать отсортированную копию списка, не трогая исходный список:
    def sort_list(original: list) -> list:
    Это изменение сломает клиентский код, так как ему теперь придётся использовать функцию так:
    some_list = [ ... ]
    some_list = sort_list(some_list)

    Т.е. наше изменение сломало обратную совместимость: старый код не может работать с новыми версиями.

    Если быть осторожным, то можно внести изменение в интерфейс, не сломав обратную совместимость. Например, если мы решили научить нашу функцию сортировать не только по возрастанию, но и по убыванию:
    def sort_list(original: list, inverse: bool = False):

    Тогда изначальный способ вызова sort_list(some_list) по прежнему будет работать. Мы расширили старый интерфейс, а не заменили его.

    Так вот, к чему я всё это говорю: умные IDE, вроде PyCharm, могут находить случаи использования того или иного элемента в рамках одного проекта (!). Но эта возможность очень ограничена, так как всегда можно так запутать код, что никакая IDE не разберётся.
    Поэтому лучше заранее продумывать, как клиентский код будет обращаться к услугам твоих сервисов, чтобы не пришлось переписывать интерфейс, а только реализацию.
    Ответ написан
    Комментировать
  • Бот рандомно выбирает вопрос, но проверяет по ответам для 1 вопроса, как исправить?

    Vindicar
    @Vindicar
    RTFM!
    if x == 1:
        @bot.message_handler(content_types="text")
        def send(message):
            ...

    Так работать НЕ будет. Ты явно не очень понимаешь, что делаешь.

    1. Должна быть только одна функция, декорированная как @bot.message_handler(content_types="text"). Если их несколько, отработате только одна.

    2. Ты должен хранить сведения:
    - Какой вопрос был последним задан тому или иному пользователю
    - Какие вопросы были уже заданы тому или иному пользователю
    В рамках обучения их можно хранить в словаре, но в реальном боте потребуется постоянное хранилище (например, БД), в котором эти сведения пережили бы перезапуск бота

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

    Vindicar
    @Vindicar
    RTFM!
    Для начала скажи, какую задачу ты пытаешься решить.
    Для случая с одноразовым потоком-воркером, тебе не нужна глобальная переменная. Достаточно класса.
    import threading
    
    class MyWorkerThread(threading.Thread):
        def __init__(self, arg1: float, arg2: float): # передаём потоку входные данные 
            # поток не должен их менять!
            super().__init__()
            self.arg1 = arg1
            self.arg2 = arg2
            self.result: t.Optional[float] = None
        def run(self):
            time.sleep(10) # имитируем длительную работу
            self.result = self.arg1 + self.arg2

    И тогда ты можешь его использовать так:
    worker = MyWorkerThread(42, 69)
    worker.start()
    while True: 
        if worker.is_alive():  # проверяем, жив ли поток
            # делаешь ещё что-то, пока поток работает
            print('Still working...')
            time.sleep(0.5)
        else:
            # поток завершился, даём знать пользователю.
            print(f'Done! Result is {worker.result}!')
            break # выходим из цикла

    Если же тебе нужно просто дождаться конца потока, ничего не делая в процессе, можно сделать просто worker.join()

    Сложности начинаются, когда тебе нужно взаимодействовать с длительным потоком. Усложним пример:
    import threading, queue
    
    class MyWorkerThread(threading.Thread):
        def __init__(self, arg1: float, arg2: float): # передаём потоку входные данные 
            # поток не должен их менять!
            super().__init__()
            self.arg1 = arg1
            self.arg2 = arg2
            self.result: t.Optional[float] = None
            self.progress = queue.Queue()
        def run(self):
            for i in range(10):
                time.sleep(1) # имитируем длительную работу
                self.progress.put(i/10) # сообщаем о прогрессе
            self.result = self.arg1 + self.arg2
            self.progress.put(1.00)

    Тогда код использования изменится следующим образом:
    worker = MyWorkerThread(42, 69)
    worker.start()
    while True: 
        if worker.is_alive():  # проверяем, жив ли поток
            # делаешь ещё что-то, пока поток работает
            try:
                progress = worker.progress.get(block=True, timeout=0.5)
            except queue.Empty: # поток ничего не сообщил
                print('Still working...')
            else:
                print(f'Still working... {progress:.0%}')
                worker.progress.task_done() # один вызов task_done() на один успешный вызов get()!
        else:
            # поток завершился, даём знать пользователю.
            print(f'Done! Result is {worker.result}!')
            break # выходим из цикла

    Если тебе нужно передать потоку новые задания, то можешь использовать ещё одну queue.
    Ответ написан
    Комментировать
  • Multiprocessing.Process OSError: [WinError 87] Параметр задан неверно, что делать?

    Vindicar
    @Vindicar
    RTFM!
    Ну так тебе же говорят:
    _pickle.PicklingError: Can't pickle <function <lambda> at 0x00000122F23CEB00>: attribute lookup <lambda> on __main__ failed

    Для передачи данных в соседний процесс они сериализуются через модуль pickle. А сериализовываться так может далеко не всё.
    Если тебе нужно скинуть в соседний процесс код... это проблема. Может, получится скинуть словарь с локальными переменными, строку с кодом, и вычислить эту строку через eval() уже "на месте".
    Альтернативно, просто замени лямбду на нормальную функцию, и попробуй передать либо её, либо имя этой функции, чтобы дочерний процесс сам её взял из globals() или еще откуда.
    Ответ написан
    Комментировать
  • Не работает replace в голосовом ассистенте?

    Vindicar
    @Vindicar
    RTFM!
    Ну ты же явно какую-то глупость делаешь.
    if cmd == "sreachyoutube":
            search_term = cmd.replace("Кеша видео", " ")

    Если в переменной cmd лежит строка sreachyoutube(!), то там по определению не может содержаться подстроки "Кеша видео".
    Ответ написан
    8 комментариев
  • Как узнать находятся ли все элементы списка в другом списке?

    Vindicar
    @Vindicar
    RTFM!
    Преврати первый список и второй список в множества. Если первое множество является подмножеством (issubset()) второго, то условие выполнилось.
    Если есть возможность строить множество одновременнео с первым списком, это упростит задачу.
    Ответ написан
    1 комментарий