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

    Vindicar
    @Vindicar
    RTFM!
    Вот трудно вбить в гугл "API tiktok gift"?
    Вторая же ссылка ведёт на гитхаб подходящей под описание библиотеки. А там и примеры есть...
    Вторая ссылка, Карл!
    Ответ написан
    1 комментарий
  • Не могу решить задание ЕГЭ. Почему мой код не работает?

    Vindicar
    @Vindicar
    RTFM!
    Тебе выше правильно намекнули.
    Во-первых, нужно увидеть простую вещь: дописывание нуля в конец двоичного представления - это то же, что умножение на 2. Назовём это операция А. А дописывание единицы - то же, что умножение на 2 и прибавление 1. Назовём это операция Б. Таким образом, можно избавиться от двоичной системы в задании.

    Второе: операция А будет давать в результате только чётные числа, независимо от аргумента. Аналогично, операция Б будет давать только нечётные числа, независимо от аргумента.

    Третье: результат как операции А, так и операции Б всегда больше аргумента. Более того, больший аргумент даёт больший результат. Это легко показать.
    Пусть у нас есть число x. Результат операции A меньше, чем операции Б над тем же числом, поэтому мы должны проверить только один сценарий: когда к x применяется операция А, а к x - 1 - операция Б. Значит, x станет 2 * x, а x - 1 станет 2 * (x - 1) + 1 = 2 * x - 1. Т.е. для x - 1 результат меньше. Т.е. даже в таком, самом спорном случае, меньшее число даёт меньший результат

    Четвёртое: задачу можно решать задом наперёд. У нас есть целевые числа - значит, мы должны применить к ним алгоритм наоборот, чтобы получить исходные. Это и даст нам диапазон для поиска исходных чисел.

    Дальше уже проще. Смотрим на начало целевого диапазона, число 876 544. Оно чётное, значит, оно могло быть создано только операцией А. Значит, чтобы получить исходное число, нужно поделить его на 2. 876 544 / 2 = 438 272. Это число тоже чётное, оно тоже могло быть создано только операцией А. 438 272/ 2 = 219 136. Оно тоже чётное. Значит, третий раз применяем операцию А наоборот: 219 136 / 2 = 109 568. Исходя из пункта 3, можем сказать, что числа, меньше 109 568, не могут дать результат, больший или равный 876 544.

    Аналогично анализируем верхнюю границу целевого диапазона.
    1 234 567 899 = 2 * 617 283 949 + 1 (операция Б)
    617 283 949 = 2 * 308 641 974 + 1 (операция Б)
    308 641 974 = 2 * 154 320 987 (операция А)
    Значит, исходное число должно быть не более 154 320 987. Вот тебе и диапазон для поиска.
    А поскольку большие аргументы дают большие результаты, то это означает, что ни одно число меньше 154 320 987 не даст результат, который выйдет за верхнюю границу диапазона (1 234 567 899). Т.е. искомые числа - это весь диапазон от 109 568 до 154 320 987. Посчитать, сколько чисел в диапазоне, тривиально.
    Ответ написан
    Комментировать
  • Как организовать клиент-клиент соединение на python через socket?

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

    Vindicar
    @Vindicar
    RTFM!
    Ну для начала твоя лесенка из if-elif-elif-... - плохое решение.
    Сделай нормальную структуру данных вместо пачки переменных. Используй словарь, или ещё что. Например, такого вида:
    # словарь, где ключ - строка с названием пунка отправления, а значение - ещё словарь,
    #   где ключ - строка с названием пункта назначения, а значение - список,
    #     где элементы - пары строк ("время отправления", "время прибытия")
    # Тогда с таким словарём можно будет работать так:
    bus_timetable: dict[str, dict[str, list[tuple[str, str]]]] = {
        # ты словарь заполняешь по результатам парсинга, ну и то хорошо
        # я для примера запишу прямо так
        'Владимир' : {
            'Муром': [
                ('8:00', '11:00'),
                ('9:00', '12:00'),
                ('10:00', '13:00'),
            ],
        },
    }
    point_from = 'Владимир'
    point_to = 'Муром'
    # для примера вывожу в консоль, для бота перепишешь сам
    print(f'Автобус из {point_from} в {point_to}')  
    for departure, arrival in bus_timetable[point_from][point_to]:
        print(f'Отходит в {departure}, прибывает в {arrival}')

    Тогда тебе не потребуется делать кучу веток для разных городов, достаточно лишь определить значения point_from и point_to. Более того, ты можешь просто перечислить ключи внешнего словаря при создании кнопок:
    kbd_from = types.ReplyKeyboardMarkup(resize_keyboard=True)
    buttons = [types.KeyboardButton(point_from) for point_from in bus_timetable]  # список кнопок
    kbd_from.add(*buttons)  # если надо добавить все кнопки сразу

    Похожий приём возможен и для определения кнопок для городов назначения.

    А теперь по тому, как сделать выбор. Тут есть два варианта, но давай пока поговорим о ReplyKeyboardMarkup, которую ты используешь.
    Если ты хочешь использовать ReplyKeyboardMarkup, то стоит помнить - её кнопки дают тот же эффект, как если бы пользователь просто ввёл текст кнопки сам. Поэтому тебе потребуется использовать register_next_step_handler(). Ты не привёл код своей попытки, но в целом идея несложная. В основном обработчике события ты проверяешь, что текст сообщения содержится в bus_timetable (оператор in в помощь) - это значит, что текст сообщения содержит название известного боту города.
    Тогда ты делаешь вызов register_next_step_handler() и ставишь обработчик второго сообщения. Единственное "но": тебе нужно будет обработчику передать первый выбранный город. Это будет выглядеть как-то так:
    @bot.message_handler(content_types=['text'])
    def first_message_handler(message):
        if message.text in bus_timetable:  # назвали известный город? Это пункт отправления
            kbd = ...  # тут определяешь клавиатуру, опираясь на города в bus_timetable[message.text]
            response = bot.reply_to(message, "А теперь назовите пункт назначения", reply_markup=kbd)
            # обрати внимание: все параметры после указания функции second_message_handler будут
            # переданы в эту функцию при её вызове. А вызвана она будет, когда пользователь ответит.
            bot.register_next_step_handler(response, second_message_handler, message.text)
        elif ...  # нам назвали не город - тут можно проверить другие команды
    
    def second_message_handler(message, point_from):
        # а эта функция будет вызвана только когда пользователь уже назвал пункт отправления
        # point_from будет содержать название города, отправленное пользователем.
        if message.text in bus_timetable[point_from]:  # нам назвали допустимый пункт назначения
            bus_rides = bus_timetable[point_from][message.text]  # список рейсов
            ...  # дальше перебираем список bus_rides и выводим его пользователю
        else:  # пользователь назвал что-то другое
            ...  # говорим пользователю, что он дурак
    Ответ написан
    1 комментарий
  • Как определить область в потоке видео и среагировать на обнаружение?

    Vindicar
    @Vindicar
    RTFM!
    Ну так и скажи, "я хочу написать чит для Dead By Daylight, помогите!"
    Сделай полярное преобразование нужного куска экрана. Тогда нужная полоса превратится в вертикальную, и её легко можно будет выбрать обрезкой, а индикатор будет двигаться не по кругу, а по вертикали, и его движение будет проще анализировать.
    Впрочем, приколюхи вроде докторского безумия, которые меняет положение и направление движения индикатора, собьют твой алгоритм. А ещё есть скилл-чеки, у которых просто нет идеальной зоны, только хорошая.
    Ответ написан
    2 комментария
  • Как правильно проксировать запрос при коннекте к aiosmtplib?

    Vindicar
    @Vindicar
    RTFM!
    Погоди-ка, а параметр sock на что? Он есть и у функции send(), и у конструктора SMTP(). Подготовь запроксированный экземпляр socket.socket и отдай туда.
    Судя по упомянутому в комментах issue, нужно будет самому закрыть этот сокет, когда закончишь работу с SMTP.

    Нет, конечно, есть варианты жёстче. Например, отнаследоваться от SMTP, переопределить _create_connection(), и заменить/пропатчить self.loop так, чтобы вместо self.loop.create_connection() вызывалась твоя корутина. В ней уже формировать сокет как тебе надо.
    Но мне кажется, проще поработать с sock.
    Ответ написан
    Комментировать
  • Возможно ли создать асинхронную функцию чтобы отправлять в неё данные постепенно без await?

    Vindicar
    @Vindicar
    RTFM!
    asyncio.Queue в помощь. Чтобы синхронно помещать туда элементы, или используй put_nowait(), или выкручивайся с вызовом put() через create_task().

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

    Vindicar
    @Vindicar
    RTFM!
    Ну тебе же английским по белому написано:
    RuntimeError: This Application was not initialized via `Application.initialize`!

    Нужно перед вызовом application.start() добавить аналогичный вызов initialize().

    И да, ты пытаешься трогать элементы управления своего окна из другого потока. Так нельзя.
    Ответ написан
    Комментировать
  • Как в numpy максимально быстро изменить структуру данных в массиве?

    Vindicar
    @Vindicar
    RTFM!
    CUDA тут не нужна, просто не следует перебирать массив numpy питоновскими циклами.
    Если есть возможность - выражай желаемое через операции над массивом в целом. Тогда цикл организует numpy, и он это делает через нативный код, ЕМНИП - работает в разы быстрее.
    Подход ниже сожрёт больше памяти, но зато короткий, выразительный и использует только средства numpy.
    image = cv2.imread("image.png")
    image = image.astype(numpy.uint32)  # смена типа нужна, иначе при сдвиге потеряются разряды
    image_clone = (image[..., 0] << 16) | (image[..., 1] << 8) | image[..., 2]

    Если хочется заморочиться по памяти:
    image = cv2.imread("image.png")
    image_clone = numpy.zeros(image.shape[:2], numpy.uint32)
    # краткие формы операций не создают новый массив, а изменяют существующий по месту
    image_clone |= image[..., 0]
    image_clone <<= 8
    image_clone |= image[..., 1]
    image_clone <<= 8
    image_clone |= image[..., 2]


    P.S.: как там, у imread() починили уже неумение работать с юникодными путями?
    Ответ написан
    Комментировать
  • Бот для уведомлений с ютуба не работает больше 3х дней, где я мог ошибиться?

    Vindicar
    @Vindicar
    RTFM!
    Во-первых, научись регистрировать проблемы. Почитай про logging, как его настраивать. Расставь в боте и в парсере try-except и записывай в лог возникающие ошибки. Тогда у тебя будет текст ошибки, с которым уже можно как-то работать.

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

    Тут вопрос такой: а нужна ли вообще тут БД? Если да, то для чего она нужна?
    yt-dlp, к сожалению, синхронный - но ты ведь можешь выполнять этот код через run_in_executor(). Тогда получится интегрировать парсер прямо в бот, и отправлять сообщения немедленно.

    Альтернативно, можно схитрить так: сделать боту учётку на ютубе, подписать его на нужные каналы и настроить уведомления о новых видео по почте, а в боте мониторить почтовый ящик через email-monitor или подобное.
    Ответ написан
    Комментировать
  • Почему не добавляются данные в mysql?

    Vindicar
    @Vindicar
    RTFM!
    Коммит не забыл сделать?
    Ответ написан
    Комментировать
  • Зачем вообще нужна библиотека python turtle в реальной практике?

    Vindicar
    @Vindicar
    RTFM!
    Обучение. Многие языки для школьников основаны на принципе "черепашки". Сам начинал с LogoWriter и L-Graph, но есть и другие.
    А тут сразу можно привыкнуть к синтаксису питона, заодно.
    Ответ написан
    Комментировать
  • Почему не получается закрыть окно в PyQt5?

    Vindicar
    @Vindicar
    RTFM!
    Ну у твоего класса действительно есть только метод setupUi(), и нет метода close(). Неудивительно, что Питон этот метод тоже не находит.
    Я с Qt не знаком, поэтому поинтересуюсь: а MyMindow точно должно наследоваться от object? Может, от какого другого класса?

    А вообще выглядит всё так, словно этому коду место в MainWindow.
    Ответ написан
    Комментировать
  • Как получить данные с сайта росреестра?

    Vindicar
    @Vindicar
    RTFM!
    Правило номер ноль при парсинге: при любых проблемах сохраняй на диск то, что тебе пришло в ответе от сервера.
    То, что ты видишь в браузере - это не обязательно то же самое, что браузер получил от сайта.
    То, что браузер получил от сайта - это не обязательно то же самое, что requests получит от сайта.

    В данном случае, и requests и браузер получают в ответе вот это:
    <body style="height: 100%; width:100%;">
    <div id=app style="height: 100%; width:100%;"></div>
    <script src=js/chunk-vendors.c1d200da.js></script>
    <script src=js/chunk-common.adcda62e.js></script>
    <script src=js/chunk-esri.caf28189.js></script>
    <script src=js/index.ca134891.js></script>
    </body>

    Как видишь, нужного элемента тут просто нет, потому что он создаётся динамически, через JavaScript. А BS не выполняет скрипты.

    Варианта только два:
    1. Выяснять, каким запросом сайт подтягивает данные для этого, научиться этот запрос делать самостоятельно и вытаскивать искомые данные из полученного. Медленно и трудно на подготовительном этапе, зато потом работает сравнительно быстро... если, конечно, сайт защиту от парсинга не поставит.
    2. Запускать управляемый браузер, дать ему загрузить страницу и выполнить скрипты, а потом уже искать нужные данные. Быстрое решение в плане разработки, но более медленное и ресурсоёмкое в дальнейшем использовании.
    Ответ написан
    Комментировать
  • Как отрыть ссылку с помощью flet с регистром?

    Vindicar
    @Vindicar
    RTFM!
    Твоя ссылка парсится так:
    1. nullsbrawl - схема
    2. createAndJoinRoom - адрес узла, точнее, доменное имя. Доменные имена не имеют регистра, насколько я знаю, т.е. habr.com и HABR.COM - одно и то же имя. Вероятно, поэтому оно и преобразуется в нижний регистр.
    3. пустой путь к ресурсу - подразумевается корневой ресурс
    4. всё, что после ? - параметры запроса

    Ты можешь попробовать изменить ссылку так: nullsbrawl:///createAndJoinRoom?....
    Обрати внимание на дополнительный слэш. Эта ссылка парсится так:
    1. nullsbrawl - схема
    2. адрес узла пустой
    3. createAndJoinRoom - путь к ресурсу на указанном узле. Пути регистрозависимы в URL, а потому его трогать не будут.
    4. всё, что после ? - параметры запроса
    Ответ написан
  • Почему питоновский скрипт сам по себе рабочий, а в виде службы - нет?

    Vindicar
    @Vindicar
    RTFM!
    Виртуальное окружение в проекте есть? Если да, то запускать скрипт надо не системным питоном, а питоном из этого окружения.
    EDIT1:
    Если из командной строки дать pyhon3 /home/lxm213/script.py, то скрипт работает штатно и без ошибок

    Т.е. скрипт запускаешь в системном окружении, а не в виртуальном. ОК, тогда по идее он должен работать...
    Но встаёт вопрос: как ты ставил schedule? Просто pip install schedule? Из-под рута ставил или с правами просто пользователя?
    Если ставил из-под рута, то библиотека будет установлена в системный интерпретатор и будет доступна всем пользователям.
    Если ставил не из-под рута, то, возможно, pip поставил её куда-то в твой домашний каталог - я знаю, что под виндой он так делает. Тогда библиотека доступна только если запускать скрипт из-под твоего пользователя.

    Отсюда три возможных решения:
    1. Создать виртуальное окружение для проекта, поставить библиотеку в это виртуальное окружение (используя местный pip), запускать скрипт через python3 из этого окружения.
    2. Если библиотека была поставлена без рут-прав, указать в .service-файле, что скрипт надо запускать от имени твоего пользователя, а не от имени root.
    3. Убедиться, что библиотека поставлена в системный интерпретатор. При необходимости поставить её с рут-правами. Тогда скрипт будет работать из-под любого пользователя.
    Ответ написан
    9 комментариев
  • Обработка params ?fields в апи запросе для вывода в response?

    Vindicar
    @Vindicar
    RTFM!
    Рекурсивно делай. Опиши требуемую функцию:
    def filter_fields(obj: dict[str, ...], fields: list[str]) -> dict[str, ...]:
        """obj - фильтруемый словарь, fields - множество полей, которые надо оставить."""
        ...

    Проблема в том, что поля могут быть вложенным. Тогда первым делом составляешь набор нужных тебе полей верхнего уровня:
    top_level_fields = {}
    for f in fields:
        top, _, bottom = f.partition('.')
        top_level_fields.setdefault(top, [])
        if bottom is not None:
            top_level_fields[top].append(bottom)

    Для
    fields=['boardId', 'name', 'Data.Matches.t.id', 'Data.Matches.m']
    в top_level_fields получишь
    { 'boardId': [], 'name': [], 'Data': ['Matches.t.id', 'Matches.m']}

    Дальше перебираешь поля, собираешь их значения в один мешок и смотришь, есть ли для них нижележащие поля:
    output = {}
    for top, bottom in top_level_fields.items():
        if bottom:
            output[top] = filter_fields(obj[top], bottom)  # что делать, если ключа top нет?
        else:
            output[top] = obj[top]

    Таким образом наберёшь всё, что надо.
    Ответ написан
    Комментировать
  • Как получить содержимое сообщения до его редактирования в discord через requests?

    Vindicar
    @Vindicar
    RTFM!
    Насколько я знаю - никак. Ты можешь ловить событие редактирования сообщения - тогда ты получишь старую и новую версии. Но и только.
    Ответ написан
  • Взаимодействие методов внутри класса?

    Vindicar
    @Vindicar
    RTFM!
    # Ты заявляешь следущее:
    # "метод udar должен вызываться на экземпляре объекта (self) с двумя параметрами: hp и dmg"
    def udar(self,hp,dmg):
        print("Наносит урон с руки")
        # при этом метод не использует переданные параметры?
        rep = self.hp - self.dmg  # почему self.dmg? Боец бьёт себя?
        return "Осталось здоровья: " + rep
    
    
    # а ниже у тебя:
    # метод udar() фактически вызывается с одним параметром: другим бойцом
    boec.udar(boec2)


    Твоя проблема та же, что и всех новичков: ты не озаботился сформулировать обязанности метода, что должен делать это метод с точки зрения решаемой программой задачи.
    Например, сейчас у тебя путаница: метод имитирует нанесение удара бойцом self по бойцу, переданному как параметр? Или же наоборот, удар бойцом, переданным как параметр, по бойцу self? И уж точно не нужно прикручивать сюда ещё и вывод текста в консоль, это посторонняя обязанность, не относящаяся к классу бойца.

    Вот моя идея (может, несколько усложнённая, но, надеюсь, понятная):
    class Fighter:
        def __init__(self, name: str, hp: int, damage: int):  # указывай типы параметров - так проще понять, что нужно методу
            """Конструктор инициализирует экземпляр бойца заданными значениями."""
            self.name: str = name
            self.hp: int = hp
            self.damage: int = damage
        
        def is_defeated(self) -> bool:
            """Возвращает True, если боец не может более сражаться."""
            return self.hp <= 0  # в простейшем случае, если у бойца не осталось HP
    
        def calculate_attack_on(self, other: 'Fighter') -> int:
            """Метод определяет, сколько урона наш боец (self) нанесёт бойцу other. Возвращает число очков урона."""
            # сейчас урон всегда одинаков, но потом тут можно будет прикрутить что-то посложнее
            # например, рандомный урон в диапазоне, или бонусы/малусы против конкретных бойцов, или ещё что
            return self.damage  
    
        def receive_damage(self, damage: int) -> int:
            """Метод определяет, сколько HP наш боец (self) потеряет, получив урон damage, и уменьшает его здоровье. Возвращает число фактически потерянных очков здоровья."""
            # сейчас метод просто вычитает урон из очков здоровья. 
            # но потом при желании можно добавить, например, механику "последний шанс", 
            # когда первый "смертельный" удар оставляет бойца на 1 хп. Или сопротивление/уязвимость к урону, или ещё что.
            lost = min(self.hp, damage)  # если у нас 1 очко здоровья, мы не можем потерять 10
            self.hp -= lost
            return lost
    
        def attack_other(self, target: 'Fighter') -> int:
            """Проводит атаку нашего бойца (self) по другому бойцу (target). Возвращает нанесённый урон."""
            attack_damage = self.calculate_attack_on(target)
            actual_damage = target.receive_damage(attack_damage)
            return actual_damage

    Как видишь, у каждого метода есть свой достаточно чётко очерченный круг обязанностей. Хотя, конечно, можно придраться и сказать, что receive_damage() делает две вещи и его стоит разбить на два метода.
    Названия методов должны однозначно указывать, что они делают. Например, udar ничего не говорит о том, кто кого ударяет, тогда как attack_other намекает, что атаку производит тот, у кого вызвали метод, в адрес того, кого передали как параметр метода. То же самое касается параметров методов.
    Весь вывод вынесен из класса, это не его обязанность:
    boec = Fighter("вася",200,22)
    boec2 = Fighter("bob",100,19)
    print(f'{boec.name}: {boec.hp} HP;  {boec2.name}: {boec2.hp} HP')
    dmg = boec.attach_other(boec2)
    print(f'{boec.name} нанёс {dmg} урона {boec2.name}')
    print(f'{boec.name}: {boec.hp} HP;  {boec2.name}: {boec2.hp} HP')
    Ответ написан
    2 комментария
  • Как ускорить запуск .exe файла?

    Vindicar
    @Vindicar
    RTFM!
    Если проблема именно в "юзер сбит с толку", то её можно обойти, а не решить. Я, например, когда писал гуишную программу, завязанную на numpy, scipy и matplotlib, в итоге плюнул и сделал простой splash screen, который показывается при загрузке и пред-импортирует требуемые модули, показывая прогрессбар. А у pyinstaller есть опция --splash, которая будет показывать прогресс распаковки.

    А так - профилируй приложение, выясняй, на чём задержка. Добавь отладочный вывод в самое начало скрипта, до импортов, чтобы понять, идёт ли задержка на этапе запуска интерпретатора, или на этапе ипорта модулей.
    Ответ написан
    Комментировать