Ответы пользователя по тегу Python
  • Unittest в Python?

    Vindicar
    @Vindicar
    RTFM!
    Приведенный код - это и есть юнит-тест.
    Юнит-тест проверяет, что отдельный модуль (класс, функция и т.п.) реализует ожидаемое поведение, как наблюдаемое снаружи, так и реализуемое внутри. Иными словами, он проверяет соответствие модуля ожидаемому интерфейсу.
    Интеграционный тест проверяет способность разных модулей взаимодействовать в предполагаемых рамках, т.е. проверяет правильность проектирования самого интерфейса взаимодействия. Достаточно ли возможностей для взаимодействия? Не забыли ли мы какой-то метод?
    Ответ написан
  • Ошибка: mute_role = discord.utils.get(ctx.message.guild.roles, name = 'mute') AttributeError: 'NoneType' object has no attribute 'guild', что зделать?

    Vindicar
    @Vindicar
    RTFM!
    Наверно, слэш команды не связаны с сообщением, а потому ctx.message - это None.
    Но ты можешь получить ссылку на гильдию и через member.
    Ответ написан
    1 комментарий
  • Почему в методе класса TypeError: takes 1 positional argument but 2 were given?

    Vindicar
    @Vindicar
    RTFM!
    Потому что self.get_x().
    В питоне доступ к полям/методам self ВСЕГДА явный, в отличие от других языков (типа C++ или C#), где this можно опустить.
    Собственно, ошибка тебе и говорит, что питон не может именно НАЙТИ get_x().
    Ответ написан
    7 комментариев
  • Обязательно ли использовать класс в Python?

    Vindicar
    @Vindicar
    RTFM!
    Классы удобны, когда у тебя есть некая сущность, наделённая состоянием и поведением. Иными словами, если есть поведение (т.е. функции) и оно требует сохранения каких-то данных между вызовами. Да, можно хранить эти данные через возврат значений и передачу параметров. По-сути, так реализуется ООП в языках вроде C (не путать с C++). Если эта сущность соответствует какому-то предмету, с которым ты работаешь, так еще лучше.
    Ответ написан
  • Win32api | python | Как создать окно приложения, где взять wndProc?

    Vindicar
    @Vindicar
    RTFM!
    Тебе повезло, я недавно такое делал.
    Нельзя просто взять и передать питоновскую функцию в WinAPI, так как у них совершенно разные способы вызова. Тебе сначалу нужно описать тип данных - указатель на функцию. Примерно так.
    import ctypes
    import ctypes.wintypes as w
    LRESULT = w.LPARAM
    WNDPROC = ctypes.WINFUNCTYPE(LRESULT, w.HWND, w.UINT, w.WPARAM, w.LPARAM)

    Вот после этого ты можешь предоставить свою оконную функцию вида
    def wnd_proc(hwnd: w.HWND, message: w.UINT, wParam: w.WPARAM, lParam: w.LPARAM) -> LRESULT:


    А потом уже указываешь это в классе окна:
    wndСlass.lpfnWndProc = WNDPROC(wnd_proc)

    Но тут есть еще один подвох - оконных сообщений много, и их набор отличается для разных версий винды. Есть базовый, более-менее статичный набор, но помимо них может прийти много чего.
    Тут на помощь приходит DefWindowProc().
    def wnd_proc(hwnd, message, wParam, lParam):
        if message == SOME_MESSAGE_YOU_WANT:  # отлавливаешь интересующие тебя сообщения
            DoStuff()  # и обрабатываешь их
            return 0  # не забудь вернуть 0 как признак успеха!
        # а все остальное отдаёшь в DefWindowProc()
        return user32.DefWindowProcW(hwnd, message, wParam, lParam)

    Обрати внимание, что как многие функции WinAPI, DefWindowProc() существует в двух видах - с сууфиксом A (однобайтовая кодировка ANSI) и с суффиком W (wide char, двухбайтовый вариант юникода). Смешивать не рекомендую, выбери один суффикс и придерживайся его во всей программе.

    И ещё подвох, который меня чуть с ума не свёл - переменная с классом окна ДОЛЖНА существовать, пока существует окно. Иными словами, её не стоит делать локальной в методе - иначе сборщик мусора питона её потом соберёт, что будет неприятным сюрпризом для WinAPI. Поймаешь крэш приложения.
    Ответ написан
    7 комментариев
  • Что такое executor в aiogram?

    Vindicar
    @Vindicar
    RTFM!
    Аиограм умеет работать в двух режимах - polling и webhooks. Как я понял, executor позволяет остальным механизмам бота абстрагироваться от используемого режима.
    Например, start_polling() просто создаёт реактор (loop) asyncio и запускает в нём задачу self.dispatcher.start_polling(), а потом ждёт сигнала завершения. Ну и еще дергает обработчики on_startup и on_shutdown. Это можно сделать и вручную, при необходимости.
    webhooks использует aiohttp для реализации веб-сервера, который будет получать запросы от telegram.
    Ответ написан
    Комментировать
  • Как сменить пути поиска импорта?

    Vindicar
    @Vindicar
    RTFM!
    файлы с одинаковым именем

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

    Vindicar
    @Vindicar
    RTFM!
    Если принимает любое количество именно чисел (т.е. типы данных int или float), то есть стандартная функция max().
    Если нужно её имитировать, то
    # функцию можно будет вызвать так: max(1,2,3,4) 
    # или так 
    # l = [1,2,3,4]
    # max(*l)
    
    # если нужно, чтобы функция принимала список чисел, а не числа по отдельности, исправь так
    # def my_max(args):
    # и вызывай так: max([1,2,3,4]) или max(l)
    
    def my_max(*args):   
      if not args:  # не передали ни одного числа?
        raise TypeError("Нет ни одного числа")  # ну или можно вернуть 0, если это требуется
      val = args[0]  # запоминаем первое переданное число
      for v in args[1:]:  # перебираем остальные
        if val < v:
          val = v
      return v

    А вот что касается ввода чисел с клавиатуры, то тут уже подумай сам.
    input() даст тебе одну введённую строку.
    Почитай про метод .split() у строк, он позволит разбить строку по пробелам в список строк.
    Затем сделай новый пустой список, пройдись по списку строк, каждый элемент обработай int() или float(), и добавь результат в этот новый список.
    Тогда у тебя будет список чисел, который можно скормить my_max().
    Ответ написан
    Комментировать
  • Почему этот код выкидывает ошибку "NameError: name 'BarCode' is not defined"?

    Vindicar
    @Vindicar
    RTFM!
    BarCode еще не определен на момент его упоминания в аннотации.
    Либо поставь BarCode выше чем Product, либо замени List[BarCode] на List['BarCode'] (опережающая ссылка), либо добавь в начало from __future__ import annotations (делает ссылки опережающими автоматически).
    Ответ написан
    1 комментарий
  • Как написать скрипт, который будет удалять сам себя, если в директории будут сторонние файлы?

    Vindicar
    @Vindicar
    RTFM!
    Храни в скрипте список не-сторонних файлов, а затем pathlib в помощь. Там тебе и перечисление файлов в каталоге, и извлечение путей, и манипуляции с файлами.
    Вот только зачем?
    Ответ написан
  • Зачем могут понадобиться else и finally в конструкции try-except?

    Vindicar
    @Vindicar
    RTFM!
    Рассмотрим два сценария:
    try:
      foo()
      bar()
    except:
      baz()

    try:
      foo()
    except:
      baz()
    else:
      bar()

    В первом случае baz() вызовется, если было выброшено исключение в foo() или в bar().
    Во втором случае baz() вызовется, если было выброшено исключение в foo(), а исключения в bar() останутся необработанными.
    В обоих случаях bar() вызовется только если foo() отработало без исключений.
    Какой из двух способов применять, зависит от нужного тебе поведения.

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

    Vindicar
    @Vindicar
    RTFM!
    Ответ написан
    Комментировать
  • Как сделать удаленный доступ к консоли сервера "Minecraft"?

    Vindicar
    @Vindicar
    RTFM!
    Наиболее простой способ - держать и сервер, и бота на одной машине, и запускать процесс сервера как дочерний к процессу бота. Сервер стартуешь с опцией --nogui, тогда он будет читать команды со стандартного входа, а лог консоли писать или на стандартный вывод или на stderr, нужно смотреть куда именно.
    Так как тебе нужно, чтобы дочерний процесс работал параллельно с основным, то вместо обычных функций из модуля subprocess нужно использовать subprocess.Popen.
    После этого периодически вызываешь Popen.communicate(), чтобы подсунуть серверу новую команду на стандартный ввод, и прочитать его лог со стандартного вывода. Например, храни список команд, которые надо отправить, а в цикле проверяй его. Тогда достаточно будет подложить команду в список, чтобы она потом отправилась. Выхлоп сервера можно перенаправлять по мере поступления в какой-нибудь приватный канал дискорда, для мониторинга и отладки.
    Как сделать этот цикл параллельно с работой бота, думай сам - ты не указал библиотеку для дискорда. Если это дискорд.пи, то там есть механизм для периодического вызова функций. Читай документацию.
    Ответ написан
    Комментировать
  • Работа с датами?

    Vindicar
    @Vindicar
    RTFM!
    datetime в помощь.
    Ответ написан
    Комментировать
  • Что еще можно добавить?

    Vindicar
    @Vindicar
    RTFM!
    Мой совет: сделай каждую команду отдельной функцей вида:
    # ': str' - это type hint. На выполнение не влияет, оно в первую очередь для читаемости. Можешь пока пропустить.
    def command_plus(args: str):  # функция получает аргумент как строку, вместо вызова input().
            "Складывает указанные числа."  # doc-string содержит человекочитаемое описание функции
            print("Калькулятор на сложение")
            parts = [int(part) for part in args.split()]  # операции со строками, list comprehensions
            if not parts:  # какие значения в питоне истинные (truey), какие ложные (falsy)?
                    parts.append(int(input("1-е число: ")))
                    parts.append(int(input("2-е число: ")))
            res = sum(parts)
            print(f"Результат: {res}")  # f-строки

    Далее, научись работать со словарями:
    # словарь, содержащий имя команды и её функцию
    commands = {
            'calc +': command_plus,
            # тут будут другие команды
    }

    Тогда рабочий цикл будет примерно таким:
    while True:
            cmd = input('Введите команду: ')  # например, "calc + 2 3 5"
            for cmd_name, cmd_func in commands.items():  # цикл for, операции со словарями
                    if cmd.startswith(cmd_name):  # операции со строками
                            cmd = cmd[len(cmd_name):]  # срезы (slice)
                            try:  # обработка исключений
                                    cmd_func(cmd)
                            except Exception as err:
                                    print(f"Произошла ошибка: {err}")
                            break  # операторы передачи управления
            else:  # Как работает оператор else: совместно с циклами?
                    if cmd == 'exit':
                            print('До свиданья')
                            break # прерываем while
                    else:
                            print(f"Неизвестная команда: {cmd}")

    Будет куда проще читать код и расширять функциональность.
    Ну и почитай по темам, которые я упомянул в комментариях.
    Ответ написан
    Комментировать
  • Как указывать пути к файлу в Kivy?

    Vindicar
    @Vindicar
    RTFM!
    file = open('Файл.txt', 'r', encoding = 'utf-8'), то есть работаю с файлом, который находится в папке с main.py,

    Неправильно. Ты работаешь с файлом, который находится в текущем рабочем каталоге, так как ты указал относительный путь (т.е. не от корня диска).
    Текущий рабочий каталог может совпадать или не совпадать с каталогом, в котором находится скрипт. Это зависит от поведения программы, которая скрипт запускает, будь то проводник винды, командная строка или ещё что. Кроме того, программа может менять свой текущий рабочий каталог при желании.
    Иными словами, ты не контролируешь, какой будет рабочий каталог на момент запуска программы - разве что поменяешь его самостоятельно.
    Так что лучше указывать абсолютный путь. Самый простой способ - получить из sys.argv[0] путь к скрипту и подняться на уровень выше. Вот тогда получишь путь к папке где лежит твой скрипт. И от этого пути уже отталкивайся.
    Операции с путями удобнее всего делать с помощью pathlib, или по старинке с помощью os.path.
    Ответ написан
    Комментировать
  • Как спарсить динамический текст python?

    Vindicar
    @Vindicar
    RTFM!
    Они обновляются скриптом наверняка. А скрипт наверняка делает фоновый запрос к бэкэнду сайта.
    Отсюда:
    а) Выяснить, что это за запрос, и научиться его выполнять самостоятельно с помощью requests. Бонус - наверняка там что-то удобочитаемое, типа JSON, а не HTML.
    б) Использовать полноценный браузер, умеющий выполнять скрипты, типа selenium. Громоздко и медленно, но зато позволяет успешнее косить под обычного пользователя.
    Ответ написан
    Комментировать
  • Как взаимодействовать с mp3 файлами через код? (python)?

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

    Правильно, никак. Просто прекрати воспроизведение и начни его снова.
    Ответ написан
    2 комментария