• Как взять из массива все значения ключа?

    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!
    По команде на выдачу мута заноси в таблицу БД ID пользователя и время, когда надо снять мут.
    Также периодически (скажем, раз в несколько минут), выбирай из этой таблицы все записи, у которых время снятия мута меньше, чем текущее время. Если такие записи нашлись, снимаешь мут для пользователей, к которым они относятся, и удаляешь эти записи.
    Перезапуск бота такая схема переживает без нужды в дополнительных телодвижениях.

    Как сделать периодическую задачу, зависит от используемого языка и библиотеки - ты их не указал, кстати. Но это реализуемо в любом языке.
    Ответ написан
  • Не могу понять в чем проблема?

    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)


    Может, поэтому?
    Ответ написан
    Комментировать
  • Как настроить ssh туннель для smb?

    Vindicar
    @Vindicar
    RTFM!
    В ssh есть три варианта проброски портов.
    -L lport:remote.host:rport задаёт проброску клиентского порта, т.е.
    1. клиент SSH слушает порт lport на своей машине. По умолчанию на всех сетевых интерфейсах, но можно указать желаемый адрес, который будет слушаться, так: bind.address:lport:remote.host:rport
    2. когда к этому порту кто-то коннектится, клиент сообщает серверу
    3. сервер коннектится на remote.host:rport
    4. В дальнейшем данные пробрасываются через этот туннель.

    -R rport:local.host:lport работает наоборот
    1. сервер SSH слушает порт rport на своей стороне. По умолчанию на всех сетевых интерфейсах, но можно указать желаемый адрес, который будет слушаться, так: bind.address:rport:local.host:lport
    2. когда к этому порту кто-то коннектится, сервер уведомляет клиента
    3. клиент коннектится на local.host:lport
    4. В дальнейшем данные пробрасываются через этот туннель

    И последний, самый практичный, но самый трудно контролируемый.
    -D lport или -D bind.address:lport
    1. клиент слушает порт lport на своей стороне
    2. когда к этому порту кто-то коннектится, клиент пробрасывает соединение на ssh сервер
    3. ssh сервер отвечает по протоколу прокси SOCKS4/SOCKS5, и выполняет дальнейшие соединения в зависимости от желаний подключившегося приложения.
    Т.е. чтобы это работало, нужно чтобы приложение умело работать с SOCKS-прокси.

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

    Vindicar
    @Vindicar
    RTFM!
    1. Читаешь из файла соль и хэш пароля.
    2. К введенному паролю добавляешь соль (так же, как она была добавлена к сохранённому) и хэшируешь.
    3. Сравниваешь два хэша - полученный и прочитанный. Если они совпали, пароль верен.
    Ответ написан
    2 комментария
  • Как переметить нулевые значения в конец списка?

    Vindicar
    @Vindicar
    RTFM!
    original_list = [0,1,8,3,0,4,5,0,0] #исходный список
    new_list = [x for x in original_list if x != 0] #только ненулевые элементы
    how_many_zeros =  len(original_list) - len(new_list) #сколько нулей потеряли?
    new_list.extend( [0] * how_many_zeros ) # добавляем нужное количество нулей в конец
    Ответ написан
    1 комментарий
  • Как еще чуть ускорить алгоритм?

    Vindicar
    @Vindicar
    RTFM!
    А не проще ли будет сделать в два прохода.
    Прямым проходом делаем так: если 0, то счетчик в ноль, иначе счетчик + 1 и элемент приравниваем счетчику.
    Потом то же самое делаем обратным проходом, но изменяем элемент только если он больше счетчика.
    Отсюда получаем:
    lst=[5, 3, 0, 2, 0, 3, 8, 2, 9, 7, 0, 0, 7, 1, 5, 3]
    L = len(lst)
    # если в начале списка не 0, то мы сможем задать корректные значения только на обратном ходе
    # так что ставим заведомо большее значение счетчика
    counter = len(lst) if lst[0] != 0 else 0
    for i in range(0, L):
      if lst[i] == 0:
        counter = 0
      else:
        counter += 1
        lst[i] = counter
    # обратный ход
    counter = lst[-1] - 1 #чтобы не запороть последние элементы
    for i in range(L-1, -1, -1):
      if lst[i] == 0:
        counter = 0
      else:
        counter += 1
        lst[i] = min(counter, lst[i])
    
    print(lst)
    # [2, 1, 0, 1, 0, 1, 2, 3, 2, 1, 0, 0, 1, 2, 3, 4]

    Правда, это даст некорректный результат, если список не содержит нулей. Но это можно обнаружить в ходе первого прохода.
    Ответ написан
    2 комментария