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

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

    Я думаю, схема будет такая:
    1. При входе на целевую страницу, JS генерирует AJAX запрос с помощью fetch() или XMLHttpRequest, на твой выбор. Форму запроса (GET/POST) и передаваемые данные определяешь ты сам, но их должно быть достаточно для идентификации пользователя. В простейшем случае URL целевой страницы должен быть уникальным для каждого пользователя, и тогда можно будет передать этот уникальный идентификатор.
    2. Есть небольшой HTTP-сервер, который принимает эти запросы, записывает их в локальную базу данных и даёт отклик вида "успех/неудача". На чем он написан - неважно, но для простоты можно использовать Flask. Там будет строк 100 от силы. В качестве базы можно использовать sqlite.
    3. Есть Python бот, использующий одну из библиотек под телегу, который периодически смотрит в эту базу и проверяет наличие необслуженных запросов. Если таковые находятся, бот их перебирает, определяет для каждого запроса соответствующего пользователя, отправляет файл, и помечает запрос как обслуженный (ну или просто удаляет).
    61ceec5390670627570751.png

    Есть соблазн совместить пункты 2 и 3 в одном процессе, но это может оказаться нетривиально - тебе придётся крутить работу веб-сервера в главном потоке, а работу бота - в дополнительном. Тогда вместо базы данных можно будет использовать очередь (threading.Queue) - главный поток (Flask) кладёт задания в очередь, а поток бота - выбирает и обслуживает.
    61ceedcee35a5542427561.png
    Плюсы - один Python-скрипт вместо двух, отсутствие промежуточной БД.
    Минусы - повышенная сложность скрипта, при внезапной остановке скрипта текущие задания в очереди будут потеряны, труднее вести статистику обслуживания ботом пользователей.
    Решай сам, стоит ли оно того.
    Ответ написан
    7 комментариев
  • Сортировка словаря по нескольким значениям с условием по time.time()?

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

    Я бы вообще посоветовал временно представить словарь как список кортежей (ключ, значение), и фильтровать/сортировать этот список.
    Ответ написан
  • Подскажете аналог set(), но для словаря?

    Vindicar
    @Vindicar
    RTFM!
    Даже не знаю с чего начать.
    Во-первых, массивы в питоне - это array, и они используются нечасто. Я сильно подозреваю, что ты имел ввиду списки (list).
    Во-вторых, set() к спискам отношения не имеет, это абсолютно самостоятельная структура данных - множество. От того, что есть идиома без_повторов = list(set(с_повторами)) set() не становится методом списка или чем-то подобным. Эта идиома прекрасно работает с любым коллекциями - списками, кортежами (tuple), да с чем угодно.
    В-третьих, повторы чего ты хочешь устранить? Ключей? Значений?
    Если ключей, то в словарях ключи и так не повторяются, как уже написали выше. Повторяющийся ключ просто заменит собой старый.
    Если значений, то тебе сначала придётся решить, какой из ключей с одинаковым значением сохранить.
    Ответ написан
    Комментировать
  • Как узнать индекс динамического виджета tkinter?

    Vindicar
    @Vindicar
    RTFM!
    Есть два подхода. Один основан на лямбдах:
    for i in range(2):
        buttonFrame_update=Button(frame,text="Добавить", command= lambda arg=i: update_main_db(arg))

    Приём с аргументом лямбды необходим, чтобы сохранить текущее значение i - иначе в момент вызова лямбды она прочитает последнее значение i, а оно будет указывать на последнюю строку.

    Второй способ, которя я бы выбрал - написать свой виджет - строку таблицы. Тогда обработчик нажатия на кнопку сможет брать данные из экземплярной переменной.
    class MyTableRow(Frame):
        def __init__(self, master, *args, **kwargs):
            super().__init__(master, *args, **kwargs)
            self.widgets = []
            for i in range(3):
                widget = Entry(frame)
                widget.pack(side="left")
                self.widgets.append(widget)
            self.update_btn = Button(self, text = "Добавить", command = self.update_clicked)
            self.update_btn.pack(side="right")
            self.delete_btn = Button(self, text = "Удалить", command = self.delete_clicked)
            self.delete_btn.pack(side="right")
      
        def update_clicked(self):
            print(self.widgets[0].get())
        
        def delete_clicked(self):
            print("whatever")
    
    
    for i in range(2):
        item = MyTableRow(doth, borderwidth=2, relief="groove")
        frames.append(item)
        item.pack(side="top", fill="x")
    Ответ написан
    5 комментариев
  • Не свосем юзербот на discord.py?

    Vindicar
    @Vindicar
    RTFM!
    Нельзя. И хорошо что нельзя.

    Можно подставить имя пользователя в начало текста, но всё равно будет видно, кто писал на самом деле.
    Ответ написан
    Комментировать
  • Защита софта на Python?

    Vindicar
    @Vindicar
    RTFM!
    Вопрос вообще "как идентифицировать компьютер". И это нетривиально.
    1. Получить MAC адрес сетевой карты и проверить его на вхождение в список. Простейший способ его получить - примерно такой:
    import uuid
    print(hex(uuid.getnode()))

    * неясно, как поведет себя функция, если на компе несколько сетевых адаптеров.
    * смена сетевой карты сломает программу
    * MAC адрес сетевой карты часто можно сменить
    2. Можно попробовать использовать CPUID, например, так.
    Но я без понятия, какие процессоры это поддерживают!
    3. Можно разместить секретное значение в реестре целевых машин, и проверять его наличие.

    Самая большая проблема - эту проверку может отломать любой, более-менее знакомый с языком.

    Можешь использовать пакет типа pyarmor, он вроде предоставляет механизм создания "лицензий" и обфусцирует исходный код, чтобы его труднее было анализировать и изменить. Но и pyarmor тоже отламывается при желании.

    Так что главный вопрос: а нафига?
    Ответ написан
    2 комментария
  • Как вывести все данные из БД?

    Vindicar
    @Vindicar
    RTFM!
    value, create = Choose.objects.get_or_create(voter=request.user)


    Может, поэтому?
    Ответ написан
    Комментировать