Задать вопрос
Ответы пользователя по тегу Python
  • Как использовать 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)


    Может, поэтому?
    Ответ написан
    Комментировать
  • Хэш и соль пароля в файл?

    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 комментария
  • Что то не то в скрипте?

    Vindicar
    @Vindicar
    RTFM!
    Перечитывать файл каждый раз при обработке сообщения - не лучшая идея.

    Вместо этого сделай отдельную команду, которая будет его перечитывать.
    blacklist = []
    def load_stoplist():
        global blacklist #чтобы можно было изменить глобальную переменную
        inputfile = '1.txt'
        # учись как правильно работать с файлами
        with open(inputfile, mode='r', encoding='utf-8') as f:
            blacklist = list(map(str.strip, f.readlines()))
    
    @bot.message_handler(commands=['reload'])
    def reload_blacklist(message):
        #тут имеет смысл вставить проверку, чтобы бот игнорировал эту команду от других юзеров
        load_stoplist()
    
    #ну и так далее. А в конце скрипта
    if __name__ == "__main__":
        load_stoplist()
        bot.infinity_polling()
    Ответ написан
  • Discord.py кортеж и split,в чем проблема?

    Vindicar
    @Vindicar
    RTFM!
    Ты пытаешься сделать рандомный выбор из введённых значений?
    А на кой пельмень ты вообще соединяешь args? Если они разделяются пробелом, то так
    # команда вызывается как !choice вариант1 вариант_2 "вариант 3"
    @commands.command(pass_context=True)
    async def choice(self, ctx, *args:str):
      chosen = random.choice(args)

    А если прямо нужно через запятую, то лучше так:
    # команда вызывается как !choice вариант1, вариант 2, вариант 3
    @commands.command(pass_context=True)
    # discord.py интерпретирует * как "всю остальную строку засунь в следующий параметр" 
    async def choice(self, ctx, *, args:str): 
      choices = [arg.strip() for arg in args.split(',')]
      chosen = random.choice(choices)
    Ответ написан
  • Снижается версия Python почему?

    Vindicar
    @Vindicar
    RTFM!
    Нужно немножко включить голову и почитать про то, как работает SSH и оболочка Unix системы. Гуглинг типа "SSH keep program running" быстро бы вывел тебя на то что нужно.
    1. Когда ты подключаешься по SSH, сервер запускает копию bash или sh (или какая там оболочка используется) с правами твоего пользователя.
    <br>
    sshd<br>
      - bash<br>

    При вводе команды в этой оболочке программа ищется в системном PATH, а в нём находится второй питон.

    2. Потом, когда ты делаешь activate, ты переходишь в виртуальное окружение. Оно отличается тем, что питон там ищется по умолчанию другой, так как там поменян PATH (и ещё кое что). И происходит этот переход за счёт запуска дочерней командной оболочки.
    <br>
    sshd<br>
      - bash<br>
          - activate <br>
              - bash<br>


    3. Ты запускаешь свой скрипт. Он запускается из под оболочки внутри activate.
    <br>
    sshd<br>
      - bash<br>
          - activate<br>
              - bash<br>
                  - python3 your_script.py<br>


    4. Ты закрываешь putty. SSH сервер регистрирует отключение клиента, и посылает дочернему bash сигнал HUP - обычно он интерпретируется как сигнал на завершение. Тот передаёт этот сигнал своему дочернему процессу, и так далее.
    <br>
    sshd "sshd: эй, bash, завершайся"<br>
      - bash "bash: эй, activate, завершайся. А теперь я сам завершусь."<br>
          - activate "activate: эй, bash, завершайся. А теперь я сам завершусь"<br>
              - bash "bash: эй, python3, завершайся. А теперь я сам завершусь"<br>
                  - python3 your_script.py "python3: хорошо, завершаюсь."<br>

    В итоге получаем только работающий ssh сервер
    sshd
    И когда ты переоткрываешь сессию, activate уже перестал существовать, и ты снова попадаешь в обычный bash, где в PATH прописан только второй питон.

    Теперь главное: как же это обойти? Нужно сделать так, чтобы python3 проигнорировал сигнал о завершении. Есть несколько способов.
    Самый простой - использовать такой синтаксис:
    nohup python3 your_script.py &
    Амперсанд в конце означает "запусти программу и вернись в оболочку, не дожидаясь когда программа закончит работать". А команда nohup запускает указанную программу с указанными аргументами, но при этом она проигнорирует сигнал HUP, т.е. "эй, завершайся". А потому когда ты закроешь putty, бот должен остаться работать.
    Минус - после переподключения ты не будешь видеть вывод бота в консоль. Так что пиши логи!
    Чтобы остановить бота, придётся использовать ps чтобы узнать ID его процесса, и kill чтобы этот процесс прибить. Ну или можешь предусмотреть команду выхода в самом боте, которая завершит работу скрипта изнутри. Это удобнее.

    Второй способ - использовать программу screen, если она установлена. Документацию по ней гугли. Если коротко, screen позволяет создать виртуальную рабочую сессию, к которой можно подключатсья и отключаться, не прерывая её. При этом весь вывод на экран сохраняется между переподключениями. Удобно если бот пишет много в консоль, но несколько муторно, и надо учить сочетания клавиш.

    Третий способ - сделать так, чтобы бот запускался при загрузке, через init.d скрипт или systemd модуль. Но так как у тебя минимальные права, скорее всего это не прокатит.
    Ответ написан
    1 комментарий
  • Пишет лишнюю букву?

    Vindicar
    @Vindicar
    RTFM!
    А зачем тебе вообще цикл for i in password:?
    Если тебе нужно в консоль и в файл вывести одно и то же, то выполни F.write(f'{n} {password}\n') и всё.
    Ну и приём с with, который я показал в твоём предыдущем вопрос, тоже стоит применить.
    Ответ написан
  • Текст накладывается сам на себя?

    Vindicar
    @Vindicar
    RTFM!
    Добавлю, что
    F.close
    Не делает ровным счётом ничего, так как вы не вызываете метод close.
    Должно быть
    F.close()
    А ещё лучше заменить вот это:
    F = open("txt","w")
      for i in password:
        F.write(str(n)+ password + '\n')
        F.close

    На вот это
    with open("txt","w") as F:
        for i in password:
          F.write(str(n)+ password + '\n')
    Ответ написан
    Комментировать
  • Как сделать чат для трех и более компьютеров в python socket?

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

    Я бы посоветовал разобраться с asyncio, оно может сильно упростить написание сервера.
    Самое сложное будет написать клиента, так как нужно будет подружить asyncio с пользовательским интерфейсом клиента. Даже элементарный input() будет нетривиально использовать.
    Так что можно сразу использовать qasync, чтобы подружить pyqt и asyncio.
    Ответ написан
    Комментировать