Ответы пользователя по тегу Python
  • Как перебрать объекты и найти максимальное значение свойства у одного из объектов?

    Vindicar
    @Vindicar
    RTFM!
    winner = max(player1, player2, key=lambda p: p.scores)

    Параметр key задаёт функцию-ключ. Эта функция должна для каждого сравниваемого объекта вернуть его "вес", и max() тогда вернёт целый объект с наивысшим "весом".
    Но вообще твое решение тоже норм.
    Ответ написан
    1 комментарий
  • Непонятная ошибка KeyError, как исправить?

    Vindicar
    @Vindicar
    RTFM!
    queue_len = len(self.song_queue[ctx.guild.id])
    KeyError: 902227097647468664

    Число выглядит как id в дискорде. KeyError обычно случается, когда пытаешься обратиться к несуществующему ключу в словаре. В указанной строке кода есть кусочек, который выглядит как обращение к словарю: self.song_queue[ctx.guild.id]
    Вывод: в словаре self.song_queue нет ключа для того сервера (ctx.guild) с которого пришла команда боту. А вот почему его там нет, и почему нет логики, предусматривающей этот сценарий - это уже вопрос к вам.
    Ответ написан
    Комментировать
  • Как остановить зацикленную функцию телеграм бота(telebot)?

    Vindicar
    @Vindicar
    RTFM!
    В указанном виде - никак, бот, насколько я могу судить, однопоточный, и этот один поток будет занят циклом while True.
    Ответ написан
    Комментировать
  • Чем отличается результат отображения переменной через функцию print() от обрадения к ней напрямую?

    Vindicar
    @Vindicar
    RTFM!
    Некоторые среды разработки позволяют вывести содержимое переменной. Например, Jupyter или интерактивный интерпретатор питон. Но это не фича питона, это фича среды разработки. Упрощая, для каждого выражения среда выполняет примерно такой код:
    result = введённое_тобой_выражение
    if result is not None:
        print(repr(result))

    А вот способов преобразовать объект в строку в питоне и впрямь 2.
    str(some_object) должно давать человеко-читаемое представление.
    repr(some_object) должно (если можно) давать такое представление, которое описывает этот объект в синтаксисе питона.
    Наглядный пример - строки.
    print(str("foo\nbar")) напечатает
    foo
    bar

    Тогда как print(repr("foo\nbar")) напечатает
    "foo\nbar"

    Но для многих объектов нет ни толкового str(), ни толкового repr(), так что оба представления совпадают.
    Ответ написан
  • Питон не видит таблицу Sqlite, что делать?

    Vindicar
    @Vindicar
    RTFM!
    по видеоуроку ХаудиХо

    Ну собственно проблема уже в этом. Эти видяшки почти ничего не объясняют, а просто "делай как я". Нужно как следует учить язык, боты - не самая тривиальная вещь.

    А вообще galaxy выше прав. Вы указываете базу данных вот так: sqlite3.connect("Database.db")
    Если не помните, это то, что называется "относительный путь", который отсчитывается относительно текущего рабочего каталога. Проблема в том, что текущий рабочий каталог при запуске скрипта может быть разным - это совершенно необязательно каталог, где лежит скрипт (хотя часто может им быть). Факторов, влияющих на текущий рабочий каталог, очень много, и лучше на него не полагаться.
    Надежнее узнать полный путь до каталога скрипта, и использовать его для построения пути до рабочих файлов скрипта. Например, так:
    import sys
    import pathlib
    script_path = pathlib.Path(sys.argv[0]).parent  # абсолютный путь до каталога, где лежит скрипт
    conn = sqlite3.connect(script_path / "Database.db")  # формируем абсолютный путь до файла базы

    Вот после этого можно быть уверенным, к какой базе обращается бот.
    Ответ написан
  • Как можно перенести команду на json?

    Vindicar
    @Vindicar
    RTFM!
    Zakkaru, чтобы бот сохранял состояние переменной afk_users в json файл? Ну так бы и сказал.
    Ну тогда у тебя много ерунды написано... ну вот хотя бы тут.
    with open('afk_users.json', 'w', encoding='utf-8') as file:
        file.write(json.dumps(afk_users, indent=4, ensure_ascii=False))
        file.close()

    Во-первых, оператор with сам вызовет file.close() по окончанию.
    Во-вторых, можно было сделать проще - json.dump(afk_users, file, indent=4, ensure_ascii=False). Обрати внимание, не dumps(), а dump().
    with open('afk_users.json', 'w', encoding='utf-8') as file:
        json.dump(afk_users, file, indent=4, ensure_ascii=False))

    В-третьих, почему ты сохраняешь состояние переменной afk_users, а потом тут же её изменяешь? Может, всё-таки в обратном порядке?
    В-четвёртых, где у тебя загрузка состояния afk_users из файла? Она должна производиться при запуске бота, например внутри on_ready.
    Ответ написан
    Комментировать
  • Python Telegram bot: Как убить поток при любом исключении в основной части?

    Vindicar
    @Vindicar
    RTFM!
    Просто сделай поток демоном через параметр в threading.Thread.
    If not None, daemon parameter explicitly sets whether the thread is daemonic. If None (the default), the daemonic property is inherited from the current thread.

    Это поможет вот почему:

    daemon
    A boolean value indicating whether this thread is a daemon thread (True) or not (False). This must be set before start() is called, otherwise RuntimeError is raised. Its initial value is inherited from the creating thread; the main thread is not a daemon thread and therefore all threads created in the main thread default to daemon = False.
    The entire Python program exits when no alive non-daemon threads are left.

    Выделение моё.

    Ну а если у тебя есть неподконтрольные тебе недемонические потоки, то тогда придётся заворачивать основного бота в try catch. И да, то что "бот разбит на файлы с классами и методами" абсолютно ничего не меняет. Если бот синхронный, у него есть точка входа, где ты запускаешь его работу, и любое непойманное исключение в этом потоке всплывёт только там. Если бот асинхронный, то нужно реагировать на непойманные исключения в корутинах - читай доки на asyncio как это сделать.
    Ну и оптимальное решение - разобраться уже, где всплывает исключение, понять его причину, и исправить.
    Ответ написан
    Комментировать
  • Библиотека telebot Python?

    Vindicar
    @Vindicar
    RTFM!
    Их две. Одна так и называется, telebot.
    Другая называется pyTelegramBotAPI, но подключается как import telebot, и она куда популярнее.
    Ответ написан
    Комментировать
  • Возможно ли вызвать функцию, если есть только ее наименование в строковом виде?

    Vindicar
    @Vindicar
    RTFM!
    Если эти функции объявлены в твоем коде, то может помочь функция globals(). Она возвращает словарь всех глобально доступных именованных объектов в твоем скрипте - функций, классов, глобальных переменных.

    Если же эти функции все входят в один модуль, или являются методами одного объекта (обозначим владельца функций как obj), то можно сделать и так:
    func = getattr(obj, 'funcname')
    func()

    Наконец, и я бы посоветовал именно так, тебе никто не запрещает сделать самому словарь вида:
    accepted_funcs = { 'func1': func1, 'func2': func2 }
    Тогда ты просто вызываешь accepted_funcs['funcname'](). Этот способ позволяет гарантировать, что неожиданный внешний ввод не приведет к вызову какой-то неожиданной посторонней функции. Любое имя функции, не входящей в словарь, спровоцирует исключение.
    Ответ написан
    1 комментарий
  • Какие инструменты можно использовать для сравнения животных на картинках?

    Vindicar
    @Vindicar
    RTFM!
    Лучшие классификаторы изображений могут вроде определить породу, но не более.
    Впрочем, возможность сузить диапазон для сравнения уже кое что...
    В общем, читай тему image classifiers. Может, есть какие-то готовые.
    Ответ написан
    Комментировать
  • Как передать на сервер Python данные?

    Vindicar
    @Vindicar
    RTFM!
    Почитай про AJAX запросы.
    Проще всего будет написать JavaScript, который будет по завершению ввода строки (ну или по другому событию) делать маленький фоновый HTTP-запрос на сервер. Фоновый в том смысле что страница не будет перезагружаться, и пользователь сможет продолжить работу.
    А на сервере отдельный маршрут примет данные, запишет их куда надо, а скрипту ответит только получилось или нет.
    Ответ написан
    Комментировать
  • Как взять из массива все значения ключа?

    Vindicar
    @Vindicar
    RTFM!
    У тебя всегда в верхнем уровне массива один элемент?
    Ну так просто перебирай элементы в mas[0]['d']['x'].
    Если не всегда, то используй тот же цикл по z.
    Ответ написан
    Комментировать
  • Как переносить текст input() при ограничении количества букв?

    Vindicar
    @Vindicar
    RTFM!
    input() не предназначен для таких вещей.
    Тебе придётся или имитировать ввод вручную, или использовать модули для продвинутого консольного интерфейса типа curses (под винду нужно будет поставить пакет windows-curses).
    Ответ написан
    Комментировать
  • Как удалить символ из словаря?

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


    Теперь скажи, в контексте вышесказанного - что значит "удалить символ подчеркивания"? Удалить откуда?
    Я предполагаю, что из значений в словарях внутри списка в ключе data для каждого словаря в твоем списке?
    Ну вот собственно эту фразу достаточно перевести на питон (от конца к началу), чтобы получить ответ.
    # этот код изменит твой массив "на месте", а не создаст изменённую копию!
    for mas_item in mas: # для каждого словаря в твоем списке
        for data_dict in mas_item['data']: # для каждого словаря в списке по ключу data 
            # словари не любят, когда их модифицируют и проходятся по ним for'ом одновременно
            data_dict_keys = list(data_dict.keys()) # так что заранее составляем список ключей словаря
            for key in data_dict_keys: # проходимся по этим ключам
                data_dict[key] = data_dict[key].replace('_', '') # и обрабатываем значения по этим ключам

    Как-то так. Чем тебе это подчеркивание помешало, без понятия.
    Ответ написан
    1 комментарий
  • Как отследить пользователей телеграм бота, написанного на python и где взять их Id?

    Vindicar
    @Vindicar
    RTFM!
    Выше уже ответили, что нужно регистрировать пользователей самостоятельно. Я опишу один из способов, как это сделать.
    Я предполагаю, что используется СУБД Sqlite, хотя это можно адаптировать и к другим.
    Нам потребуется таблица пользователей примерно такого вида:
    import time
    import sqlite
    
    connection = sqlite3.connect('bot.db')
    cursor = connection.cursor()
    cursor.execute("""CREATE TABLE IF NOT EXISTS users ( -- всё что после -- комментарий SQL
        id TEXT PRIMARY KEY, -- идентификатор пользователя, он же первичный ключ таблицы
        first_use REAL, -- метка времени, когда пользователь впервые обратился к боту
        last_use REAL -- метка времени, когда пользователь последний раз обратился к боту
    )""")
    cursor.close()

    То, что мы сделали id первичным ключом, гарантирует, что одному пользователю будет соответствовать только одна строка таблицы.
    Тогда перед выполнением каждой команды нужно обновить эту таблицу - добавить строку, если её нет, или обновить поле last_use, если она есть. К счастью, существует синтаксис, позволяющий сделать это за один запрос.
    def ensure_user_stats(user_id):
        "Эта функция обновляет таблицу users, и должна вызываться в начале обработки каждой команды."
        global connection
        cursor = connection.cursor()
        now = time.time()
        # пытаемся добавить строку с указанным id, и фиксируем текущее время в полях first_use и last_use 
        # если возникает конфликт в поле id (такое id уже есть),
        # то мы обновляем в этой записи поле last_use на текущее время, а остальное не трогаем
        cursor.execute("""INSERT INTO users (id, first_use, last_use) VALUES (?, ?, ?)
        ON CONFLICT (id) DO UPDATE SET last_use = excluded.last_use""", (user_id, now, now))
        cursor.close()
    Ответ написан
    Комментировать
  • Как использовать all/any с if?

    Vindicar
    @Vindicar
    RTFM!
    if any(x==item for item in ['fd', 'tf', 33]):
    Но это имеет смысл только если сравнение нетривиальное, и просто in не сработает.
    Ответ написан
    Комментировать
  • Как остановить поток при вводе команды?

    Vindicar
    @Vindicar
    RTFM!
    Единственный вменяемый способ - тело потока должно время от времени проверять какое-то условие (будь то объект threading.Event, или просто будевая переменная). Соответственно, если условие выполнилось, тело потока должно немедленно завершиться, не доделывая начатое.

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

    Vindicar
    @Vindicar
    RTFM!
    description = f"""У тебя , **{ctx.author}** вот столько балов!**{cursor.execute("SELECT cash FROM users WHERE id = {}".format(ctx.author.id)).fetchone()[0]} :polegar_para_cima:**"""

    Вот это - трижды говнокод.
    1. Не засовывай в шаблонные строки ничего сложнее одной арфиметической операции - результат абсолютно нечитаем и неконтролируем (в чем ты убедился).
    Неправильно:
    description = f"""У тебя , **{ctx.author}** вот столько балов!**{cursor.execute("SELECT cash FROM users WHERE id = {}".format(ctx.author.id)).fetchone()[0]} :polegar_para_cima:**"""

    Правильно:
    score = cursor.execute("SELECT cash FROM users WHERE id = {}".format(ctx.author.id)).fetchone()[0]
    description = f"""У тебя , **{ctx.author}** вот столько балов!**{score} :polegar_para_cima:**"""

    2. Никогда не формируй запросы через форматирование строк. Слишком легко словить ошибку, явную или неявную.
    Неправильно:
    score = cursor.execute("SELECT cash FROM users WHERE id = {}".format(ctx.author.id))

    Правильно:
    score = cursor.execute("SELECT cash FROM users WHERE id = ?", (ctx.author.id,) )

    3. Всегда проверяй, что ты получаешь из базы! Нет гарантий, что запись с указанным id и впрямь существует.
    Неправильно:
    score = cursor.execute("SELECT cash FROM users WHERE id = ?", (ctx.author.id,) ).fetchone()[0]
    description = f"""У тебя , **{ctx.author}** вот столько балов!**{score} :polegar_para_cima:**"""

    Правильно:
    score_row = cursor.execute("SELECT cash FROM users WHERE id = ?", (ctx.author.id,) ).fetchone()
    if score_row is not None:
        description = f"""У тебя , **{ctx.author}** вот столько балов!**{score_row[0]} :polegar_para_cima:**"""
    else:
        # что делать, если такого юзера еще нет в базе?
        cursor.execute("INSERT INTO users (id, cash) VALUES (?, 0)", (ctx.author.id,) ) # можно его добавить
        description = f"""У тебя , **{ctx.author}** пока нет ничего! Но скоро будет!"""

    4. БаЛЛов, блин.
    Ответ написан
    5 комментариев
  • Как создать объект который самостоятельно распакуется в нужное число имен?

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

    Собственно, главный вопрос тут опять "а зачем тебе такое?"

    EDIT: Ну что ж, не говори, что тебя не предупреждали...

    # оба модуля - встроенные, а не сторонние
    import inspect
    import dis
    
    def callee(x):
        our_frame = inspect.currentframe()
        our_caller_frame = our_frame.f_back
        our_caller = our_caller_frame.f_code
        print(f"We are called by {our_caller.co_name}(), at line {our_caller_frame.f_lineno}")
        print("Our caller's code goes as following (byte string):")
        print(our_caller.co_code)
        bytecode = dis.Bytecode(our_caller, first_line=our_caller.co_firstlineno)
        print("Or, in human readable form, its this:")
        print(bytecode.dis())
        return [x*x]
    
    
    def caller():
        print("Calling callee()")
        y = callee(2)
        print(y)
    
    def other_caller():
        print("Calling callee()")
        z, *_ = callee(3)
        print(z)
    
    caller()
    other_caller()
    Ответ написан
    7 комментариев