Ответы пользователя по тегу Python
  • Как получить содержимое сообщения до его редактирования в 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, которая будет показывать прогресс распаковки.

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

    Vindicar
    @Vindicar
    RTFM!
    Можно, открыв несколько сокетов и проверяя их все.
    Но начиная с определенного числа команд проще будет использовать SSH или иную форму удалённого управления.
    Ответ написан
    Комментировать
  • Как отсортировать элементы с определенным id в mongodb (pymongo) и записать их в список?

    Vindicar
    @Vindicar
    RTFM!
    В первом случае ты ищешь все элементы, у которых server_id НЕ совпадает (!=) с message.guild.id.
    Во втором случае ты ищешь все элементы, у которых server_id совпадает с message.guild.id.

    Исходя из твоего результата, я бы сказал, что у тебя в базе нет элемента с таким id. Ты уверен, что он там есть? Что насчёт типов данных - нет ли тут косяка, вроде "храню id как строку, а передаю при поиске как целое число"?

    И да, говори правильно. То, что ты делаешь - поиск/фильтрация, а не сортировка.
    Ответ написан
  • Как обрабатывать ошибки в асинхронном коде?

    Vindicar
    @Vindicar
    RTFM!
    try: 
        loop.create_task(exc())
    except ZeroDivisionError as ex:
        print(f"Ошибка {ex} обработана")

    1. Ты создаёшь задачу на базе корутины exc(). Созданная задача не выполнится немедленно, а только встанет в очередь исполнения (хотя в питоне 3.12 это поведение можно изменить, но по умолчанию это так). При этом с корутиной ассоциируется future-объект, который находится в состоянии "ожидание", так как корутина ещё не завершила работу.
    2. Ты проверяешь, не возникло ли исключение в процессе создания задачи. Это может произойти, только если exc() - не корутина. В остальных случаях операция будет успешна независимо от содержания exc(), так как см. пункт 1.
    3. Ты вызываешь loop.run_forever(). Рабочий цикл (loop) смотрит в очередь исполнения, и видит в нём только корутину exc(). Она получает управление.
    4. Корутина exc() выбрасывает исключение, но не ловит его. Ассоциированный с корутиной future-объект переходит из состояния "ожидание" в состояние "отказ", и сохраняет информацию об исключении. exc() завершает работу.
    5. Рабочий цикл проверяет, кто хранит ссылку на task - и понимает, что никто. Как следствие, даже в будущем никто не сможет узнать, что корутина выкинула исключение. Поскольку рабочий цикл - штука типовая, он понятия не имеет, что делала наша корутина и как надо реагировать на исключение в ней. А потому единственный вариант для него - написать в журнал работы о непойманном исключении и надеяться, что программист это увидит и поправит.
    task = asyncio.create_task(exc())
    try:
        # await asyncio.gather(task)  # <- gather() не нужно, если у тебя одна задача
        await task
    except ZeroDivisionError as ex:
        print(f"Ошибка {ex} обработана")

    1. Ты создаёшь задачу (успешно), а потом с помощью await-вызова просишь дождаться её завершения и получить результат.
    2. Корутина main() приостанавливает своё выполнение и сохраняет свой контекст, а также встаёт в очередь, ожидая, когда сработает future-объект, связанный с task.
    3. Рабочий цикл (loop) asyncio смотрит в очередь выполнения и видит, что корутина exc() готова выполняться (она не находится в await вызове, а только начала работу).
    4. Корутина exc() получает управление, выполняется, и генерирует исключение, которое не поймано внутри этой корутины. Future-объект, связанный с этой корутиной, переходит из состояния "ожидание" в состояние "отказ", и сохраняет информацию об исключении. Корутина exc() завершает выполнение. При этом о её future-объекте знает корутина main(), поэтому рабочий цикл не дёргается по этому поводу - у main() будет возможность отреагировать на происходящее.
    5. Рабочий цикл (loop) смотрит в очередь выполнения и видит, что там только корутина main(), причём она готова выполняться - future-объект, который она ждёт, более не находится в состоянии ожидания.
    6. Корутина main() получает управление и восстанавливает свой контекст, продолжая с того места, где она остановилась. Так как future-объект находится в состоянии "отказ", оператор await читает из него информацию об исключении и перевыбрасывает это исключение внутри main().
    7. Это исключение обрабатывается блоком try-except в main() как обычно.
    Ответ написан
    Комментировать
  • Как отправлять данные пользователю из бота telegram?

    Vindicar
    @Vindicar
    RTFM!
    У тебя, походу, button() прописан как обработчик для всех кнопок. А вот внутри него не прописана ветка для data == 'send_purchase'. На текущем шаге добавь во ВСЕ цепочки if ... elif ... elif ... ветку else, которая выводит отладочное сообщение - тогда хоть будет понятно, какой обработчик вызвался и с каким значением.
    Ответ написан
    1 комментарий
  • Как сделать свять вежду python игрой и сайтом на html?

    Vindicar
    @Vindicar
    RTFM!
    1. Ты должен выбрать себе схему URL, по аналогии с тем, как это делает телеграм с его схемой tg:// или стим (steam://).
    2. Научись упаковывать свою игру в exe-файл с помощью любого упаковщика - например, auto-py-to-exe.
    3. Подразумевается, что игра уже установлена на компьютере пользователя. При установке она регистрирует себя как обработчик для данной схемы. Это делается по-разному для винды и для линукса.
    Для винды нужно будет залезть в реестр через стандартный модуль registry

    Тебе нужно создать ключ реестра HKEY_CLASSES_ROOT/ИмяТвоейСхемы. Убедись, что такого ключа нет, перед тем как его создавать!
    В ключе создаёшь строковое значение с именем URL Protocol и пустым значением.
    Создаёшь вложенный ключ: HKEY_CLASSES_ROOT/ИмяТвоейСхемы/shell
    Внутри вложенного ключа создаёшь строковое значение с именем command и значением такого вида: "C:\путь\к\твоей\игре.exe" "%1"

    После этого при попытке ввести в браузере ссылку, начинающуюся с твоей схемы, должна запуститься твоя игра.
    3. Твоя игра должна проверять параметры командной строки (читай про sys.argv). Если игра запущена без параметров - её запустили просто ярлыком. Если игра запущена с одним параметром, и он начинается с твоей схемы - её запустил клик по ссылке. Разбирай текст ссылки в параметре и решай, что игра должна сделать.

    Технически, ты не обязан сам лезть в реестр в python-скрипте - ты можешь сделать это ручками через regedit или поручить это установщику, типа NullSoft. Он же позаботится о том, чтобы снести созданные ключи при удалении игры.
    Я бы сначала попробовал зарегистрировать URL вручную, убедился что это работает, а потом уже игрался бы с установщиком.
    Ответ написан
    Комментировать
  • SyntaxError: 'await' outside function. Как исправить ошибку кода, который должен пересылать удаленные сообщения в телеграмме в избранное?

    Vindicar
    @Vindicar
    RTFM!
    await client.run_until_disconnected()
    Эта строка где находится? Вне функции? А почему?
    Выглядит как будто ей место в main().
    Ответ написан
    Комментировать
  • Как обойти ошибку Tcl_AsyncDelete: async handler deleted by the wrong thread?

    Vindicar
    @Vindicar
    RTFM!
    Поясню ответ выше: насколько я знаю, графические интерфейсы строго однопоточны. Как минимум под Windows это так, а потому ни один графический фреймворк не поддерживает обращение к окнам и их элементам из других потоков.
    Как следствие, если ты хочешь организовать фоновый поток с "обратной связью" в GUI, обычно требуется использовать очередь, например, queue.Queue. В эту очередь фоновый поток должен класть сообщения, объясняющие, что надо сделать - например, сведения о прогрессе операции, или команды на смену состояния, или ещё что. Это зависит от твоей задачи.
    Тогда основной поток программы, который и отвечает за GUI, должен использовать средства фреймворка для периодической проверки очереди на предмет сообщений. Например, в обычном tkinter это будет реализовано через метод after().
    Если в очереди есть сообщения, основной поток читает их и выполняет соответствующие действия - например, меняет положение прогресс-бара, включает/выключает кнопки, и т.д.
    Если фоновый (рабочий) поток живёт долго, то может иметь смысл организовать вторую очередь для передачи команд из GUI-потока в рабочий. Идея та же самая: рабочий поток ждёт появления команды в своей входной очереди, и выполняет её, а потом сбрасывает уведомления в исходящую очередь.
    Ответ написан
    Комментировать
  • Как вывести роли discord сервера, кроме заблокированных?

    Vindicar
    @Vindicar
    RTFM!
    В discord.py ты можешь просто сравнивать роли. Но ты пытаешься сделать это вручную...
    Если заглянуть в исходники либы, то можно увидеть, что там проверяется свойство position. Причем вроде как меньший position означает меньшие привилегии, с поправкой на то что роль @everyone меньше всех.
    Тогда решением твоей задачи будет:
    1. Определить список ролей твоего токена на рассматриваемом сервере.
    2. Определить наибольший position среди этих ролей.
    3. Получить список всех ролей на рассматриваемом сервере.
    4. Отсеять роли, у которых position больше твоего наибольшего.

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

    Vindicar
    @Vindicar
    RTFM!
    Полноценную картинку в консоли не покажешь, тут тебе не линукс. Но ASCII-арт можно - вопрос только как разделить вывод текста игры и вывод ascii-арта. Например, сделать два логических "окна" в одном терминале.

    Ставишь пакет windows-curses, после этого можно будет и на винде использовать стандартный модуль curses. Он и это умеет, и цветной вывод.
    Ответ написан
    Комментировать
  • Как добавить несколько изображений к locateOnScreen?

    Vindicar
    @Vindicar
    RTFM!
    Никак, функция ищёт одно изображение.
    Если тебе нужно несколько, ищи их последовательно, пока не найдётся хотя бы одно из них.
    Ответ написан
    2 комментария
  • Стоит ли использовать ООП для бота на Telebot?

    Vindicar
    @Vindicar
    RTFM!
    Ну почему бы и нет?
    Вон, discord.py вообще реализует механизм когов (cogs), который позволяет заключать отдельные наборы поведений в класс, и подгружать/выгружать этот класс по ходу работы.
    Нечто подобное можно построить на базе почти любой библиотеки чат-ботов, особенно если с выгрузкой заморачиваться не требуется.
    Просто если у тебя только один набор связанных поведений, то и класс с обработчиками будет один - и смысл тогда?
    Ответ написан
    Комментировать
  • Как работает запуск корутин в asyncio?

    Vindicar
    @Vindicar
    RTFM!
    3FANG,
    насчёт твоего второго вопроса: всё предельно просто. Ты запустил 10 копий корутины, они все выполнили print('start') и ушли в спячку на две секунды - практически одновременно!
    Точнее, первая корутина встала в очередь, create_task() закончила свою работу и вернула управление в твой цикл запуска корутин. И так 10 раз. Все корутины стоят в очереди плотно друг за другом.
    Затем ты входишь в цикл ожидания корутин, пишешь в консоль "старт", дожидаешься первой корутины, при этом main() встаёт в очередь на вызов. Первая корутина запустилась, написала start, и ушла в ожидание. Следующая в очереди готова вторая корутина. Она запустилась, написала start, ушла в ожидание. И так далее. В конце main() снова оказывается в начале очереди - но она ждёт первую корутину, она ещё не готова выполняться. Она отправляется в конец очереди. Поэтому программа ждёт первую корутину, но ожидание-то тикает у всех!
    Тогда первая корутина отработала - но прежде чем ты вернёшься из await-вызова в main(), сначала успеют отработать всё стоящие в очереди корутины, потому что их время тоже подошло, и они стоят в очереди раньше! И ты видишь последовательность start-finish внутри корутин.
    Затем очередь вызова доходит до main() и ты видишь "финиш" ожидания первой корутины. Ты начинаешь ждать вторую (старт) - но она уже отработала, поэтому main() единственная в очереди, и она тут же получает управление обратно (финиш). И так с оставшимися корутинами.

    Если ты сделаешь так, чтобы каждая следующая копия корутины ждала дольше предыдущей, то ситуация будет интереснее:
    код
    import asyncio 
    from time import time, sleep
    
    
    async def waste_time(i, delay):
        print(f"Start work {i}...")
        await asyncio.sleep(delay)
        print(f"End work {i}!")
    
    
    async def main():
        tasks = []
    
        for i in range(10):
            task = asyncio.create_task(waste_time(i+1, (i+1)*1.0))
            tasks.append(task)
    
        for i, task in enumerate(tasks, 1):
            print(f'start wait {i}')
            await task
            print(f'end wait{i}')
    
    if __name__ == '__main__':
        start = time()
        asyncio.run(main())
        print(time() - start)

    вывод
    start wait 1
    Start work 1...
    Start work 2...
    Start work 3...
    Start work 4...
    Start work 5...
    Start work 6...
    Start work 7...
    Start work 8...
    Start work 9...
    Start work 10...
    End work 1!
    end wait1
    start wait 2
    End work 2!
    end wait2
    start wait 3
    End work 3!
    end wait3
    start wait 4
    End work 4!
    end wait4
    start wait 5
    End work 5!
    end wait5
    start wait 6
    End work 6!
    end wait6
    start wait 7
    End work 7!
    end wait7
    start wait 8
    End work 8!
    end wait8
    start wait 9
    End work 9!
    end wait9
    start wait 10
    End work 10!
    end wait10
    10.012470483779907
    Ответ написан
    5 комментариев
  • Имитация веб-камеры - как автоматизировать на python (linux)?

    Vindicar
    @Vindicar
    RTFM!
    Извини, а у тебя ничего не ёкнуло вот тут?
    sudo apt install v4l2loopback
    pip install v4l2loopback
    Ты понимаешь разницу между этими двумя командами?
    Первая - задействует системный менеджер пакетов для дистрибутивов на базе debian (deb-пакетов).
    Вторая - задействует встроенный менеджер пакетов питона.
    Это совершенно разные вещи, и они работают с совершенно разными репозиториями.
    Установить deb-пакет в систему, на которой будешь тестить, достаточно будет один раз.
    Прописать мод можно в /etc/modules, но можно и тупо делать modprobe при загрузке системы.
    И то и то, я полагаю, можно сделать хоть на живой системе, хоть внутри докера.

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

    Vindicar
    @Vindicar
    RTFM!
    Насчёт фреймворка не подскажу, а подскажу вот что: не нужно пытаться запихнуть всю безразмерную таблицу в GUI. Прокрутка - определение позиции - выборка данных, видимых на экране - рендеринг. Как-то так.
    Ответ написан
    2 комментария
  • Хочу написать python Бота который играет в сапер за меня, и наверное мне нужно наставление более опытного?

    Vindicar
    @Vindicar
    RTFM!
    1. Ввод данных
    Окей, гугл, как сделать скриншот в питоне

    2. Предобработка данных
    Используя что-то типа opencv matchTemplate(), превращаешь скриншот в двухмерный массив, описывающий игровое поле.

    3. Принятие решения
    Имея двухмерный массив, описывающий поле, определи, где надо ставить мину. Если решение принять не удаётся - определи, какую клетку надо открывать.

    4. Реализация решения
    Зная номер клетки, выполнить щелчок по ней. См. pyautogui.
    Ответ написан
    Комментировать
  • Возможно ли реализовать очередь из отложенных новостей в Discord?

    Vindicar
    @Vindicar
    RTFM!
    так не синхронный schedule используй, а aioschedule.
    Есть пример для телеграм-бота, адаптируй его под discord.py (или клон который ты используешь).

    А последняя часть вопроса намекает на необходимость в Finite State Machine (FSM).
    Ответ написан
    7 комментариев
  • Python ввод текста в неактивное окно как сделать?

    Vindicar
    @Vindicar
    RTFM!
    Нужно для администрирования сервера Bukkit

    А что, rcon уже отменили? Это даже ванильный майнкрафт умеет.
    А так, pywinauto пробуй.
    Ответ написан