Задать вопрос
  • Как получить колонку по ее значение?

    Vindicar
    @Vindicar
    RTFM!
    Короче.
    Основную идею я тебе дам, но всё равно почитай уже любой учебник!

    Аналогия очень простая.
    Строка таблицы = структура данных, типа класса. Таблица = коллекция однотипных структур данных.
    Столбец - поле в структуре данных. Схема таблицы - описание структуры данных, т.е. набора полей.
    Таким образом, изменение схемы таблицы - изменение состава структуры данных - это НЕ обычная операция.
    Её не нужно использовать для добавления новых данных в коллекцию! Если ты добавляешь новые данные в коллекцию - это добавление строки, т.е. INSERT.

    "А что делать, если у меня переменный набор данных? Например, есть чаты, и в них есть юзеры?"
    У тебя несколько сущностей - в таких случаях тебе нужно несколько таблиц. Ключевой момент - сколько сущностей связано с той или иной сущностью.
    Например, у нас есть чаты, и есть пользователи. Пользователь может быть в нескольких чатах, чат может иметь нескольких пользователей. Это называется "связь многие-ко-многим". Если сделать так, как ты делаешь сейчас, то будет таблица Чаты, и при добавлении пользователя в чат будет добавляться столбец в таблицу. Это неправильно!
    Правильно: есть таблица Чаты (каждый чат имеет свой id - "ключ", "primary key"), таблица Пользователи (каждый имеет свой ключ) и вспомогательная таблица (association table) ПользовательВЧате.
    В виде SQL это будет выглядить примерно так:
    CREATE TABLE Chats (id INTEGER PRIMARY KEY, name TEXT, topic TEXT);
    CREATE TABLE Users (id INTEGER PRIMARY KEY, name TEXT);
    CREATE TABLE UserInChat(
        chat_id INTEGER, 
        user_id INTEGER, 
        FOREIGN KEY (chat_id) REFERENCES Chats(id),
        FOREIGN KEY (user_id) REFERENCES Users(id),
        PRIMARY KEY (chat_id, user_id)
    );

    Что это нам даёт?
    - Наличие записи в UserInChat означает, что пользователь находится в чате.
    - Каждая запись в UserInChat ссылает на существующего пользователя и на существующий чат.
    - Сочетание пользователь-чат уникально, т.е. пользователь не может войти в один чат дважды (одновременно).
    - В то же время, могут быть записи с одним и тем же пользователем (один пользователь в нескольких чатах).
    - Могут быть записи с одним и тем же чатом (много пользователей в одном чате).

    Как узнать, какие пользователи находятся в чате? Используем запрос с JOIN.
    SELECT Users.id as userid, Users.name as username
    FROM Users INNER JOIN UserInChat ON Users.id = UserInChat.user_id
    WHERE UserInChat.chat_id = 123456;


    Для добавления пользователя в чат делаем INSERT INTO в таблицу UsersInChat. Для удаление - DELETE FROM. Тут всё как обычно.
    Ответ написан
  • Почему выдает ошибку Cannot choose from an empty sequence?

    Vindicar
    @Vindicar
    RTFM!
    visit = random.choice(urls)
    У тебя в urls пусто на момент вызова функции.

    urls = []  # в urls пусто
    
    # тут ты только определяешь функцию, но не вызываешь её
    def createlist(ids):
        global urls
        for id in ids:
            urls.append("https://scrap.tf/raffles/" + id)
    # так что тут urls всё ещё пуст
    # внутри login() вызывается rufflejoin(). А urls всё ещё пуст.
    login()
    Ответ написан
    Комментировать
  • Как отправлять текст соответствующий картинке в телеграм боте на Python?

    Vindicar
    @Vindicar
    RTFM!
    1. вынеси random.choice(os.listdir('test')) в переменную, например, img
    2. используй os.path.splitext(os.path.basename(img))[0], чтобы получить имя файла картинки без расширения
    3. Не забудь отправить файл через photo = open('test/' + img, 'rb')
    4. PROFIT
    Ответ написан
    2 комментария
  • Как сделать актуализацию данных?

    Vindicar
    @Vindicar
    RTFM!
    Используй on_conflict. Он позволяет как молча проигнорировать втавляемые данные, так и частично обновить существующую строку.
    Причем достаточно конфликта по ключу (id пользователя).

    Собственно, это хорошо работает, если тебе нужно просто хранить в базе всех, кто обращался к твоему боту.
    Если же тебе нужна именно своя регистрация (а тут надо дважды подумать - нужна ли? может, нафиг её?), то тогда сначала проверяй вручную, прошёл ли пользователь регистрацию.
    Ответ написан
    Комментировать
  • Как запускать Process в скриптах которые импорируются?

    Vindicar
    @Vindicar
    RTFM!
    AttributeError: Can't pickle local object 'start.<locals>.f1'

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

    Vindicar
    @Vindicar
    RTFM!
    File -> Close Project. Закроет проект и покажет меню выбора проекта.

    Также есть настройка, Settings > Appearance & Behaviour > System Settings > Reopen projects on startup
    Ответ написан
    5 комментариев
  • Как в Python проверять, в каких скриптах какие ресурсы, импортируемые из других скриптов, используются?

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

    Первое изменение затрагивает сервис, но необязательно затрагивает клиента. Если клиент обращается к сервису таким же образом, получает результат в таком же виде, получает сведения об ошибках таким же способом, то с точки зрения клиента изменения не было. Пусть даже в реальности сервис переписали с нуля.
    Пример: пусть у нас есть функция сортировки списка "на месте", т.е. изменяя этот список.
    def sort_list(original: list):
    Если раньше она сортировала список пузырьком, а потом мы её переписали на quicksort - с точки зрения кода, который эту функцию использует, ничего не изменится, кроме времени работы функции. Клиент все равно будет использовать функцию так:
    some_list = [ ... ]
    sort_list(some_list)


    Второй тип изменений меняет интерфейс сервиса, т.е. то, как он взаимодействует с клиентом.
    Продолжая пример, если мы решили, что теперь функция будет возвращать отсортированную копию списка, не трогая исходный список:
    def sort_list(original: list) -> list:
    Это изменение сломает клиентский код, так как ему теперь придётся использовать функцию так:
    some_list = [ ... ]
    some_list = sort_list(some_list)

    Т.е. наше изменение сломало обратную совместимость: старый код не может работать с новыми версиями.

    Если быть осторожным, то можно внести изменение в интерфейс, не сломав обратную совместимость. Например, если мы решили научить нашу функцию сортировать не только по возрастанию, но и по убыванию:
    def sort_list(original: list, inverse: bool = False):

    Тогда изначальный способ вызова sort_list(some_list) по прежнему будет работать. Мы расширили старый интерфейс, а не заменили его.

    Так вот, к чему я всё это говорю: умные IDE, вроде PyCharm, могут находить случаи использования того или иного элемента в рамках одного проекта (!). Но эта возможность очень ограничена, так как всегда можно так запутать код, что никакая IDE не разберётся.
    Поэтому лучше заранее продумывать, как клиентский код будет обращаться к услугам твоих сервисов, чтобы не пришлось переписывать интерфейс, а только реализацию.
    Ответ написан
    Комментировать
  • Бот рандомно выбирает вопрос, но проверяет по ответам для 1 вопроса, как исправить?

    Vindicar
    @Vindicar
    RTFM!
    if x == 1:
        @bot.message_handler(content_types="text")
        def send(message):
            ...

    Так работать НЕ будет. Ты явно не очень понимаешь, что делаешь.

    1. Должна быть только одна функция, декорированная как @bot.message_handler(content_types="text"). Если их несколько, отработате только одна.

    2. Ты должен хранить сведения:
    - Какой вопрос был последним задан тому или иному пользователю
    - Какие вопросы были уже заданы тому или иному пользователю
    В рамках обучения их можно хранить в словаре, но в реальном боте потребуется постоянное хранилище (например, БД), в котором эти сведения пережили бы перезапуск бота

    3. Внутри обработчика @bot.message_handler ты должен получить ID пользователя, отправившего сообщение, взять из описанного выше хранилища номер последнего заданного вопроса (если есть), и уже на основании этого номера судить о том, правильный ли ответ.
    Ответ написан
  • Как склеить программно 2 изображения?

    Vindicar
    @Vindicar
    RTFM!
    Ну базовый вариант, если используешь OpenCV, ориентируйся на поиск локальных особенностей, а потом findHomography(), чтобы найти такое преобразование, которое переведёт точку на первом кадре в эквивалентную точку на втором. После этого warpPerspective(), чтобы преобразовать первый кадр в систему координат второго. Это должно совместить общие точки.

    Но это сработает только если на обоих кадрах есть достаточно контрастных общих точек, по которым их можно склеить.
    С другой стороны, если относительная позиция двух кадров не меняется со временем, то достаточно вычислить преобразование один раз на "удачной" паре кадров, и потом применять его ко всем парам.
    Ответ написан
    Комментировать
  • Как поделиться переменными между потоками из разных модулей?

    Vindicar
    @Vindicar
    RTFM!
    Для начала скажи, какую задачу ты пытаешься решить.
    Для случая с одноразовым потоком-воркером, тебе не нужна глобальная переменная. Достаточно класса.
    import threading
    
    class MyWorkerThread(threading.Thread):
        def __init__(self, arg1: float, arg2: float): # передаём потоку входные данные 
            # поток не должен их менять!
            super().__init__()
            self.arg1 = arg1
            self.arg2 = arg2
            self.result: t.Optional[float] = None
        def run(self):
            time.sleep(10) # имитируем длительную работу
            self.result = self.arg1 + self.arg2

    И тогда ты можешь его использовать так:
    worker = MyWorkerThread(42, 69)
    worker.start()
    while True: 
        if worker.is_alive():  # проверяем, жив ли поток
            # делаешь ещё что-то, пока поток работает
            print('Still working...')
            time.sleep(0.5)
        else:
            # поток завершился, даём знать пользователю.
            print(f'Done! Result is {worker.result}!')
            break # выходим из цикла

    Если же тебе нужно просто дождаться конца потока, ничего не делая в процессе, можно сделать просто worker.join()

    Сложности начинаются, когда тебе нужно взаимодействовать с длительным потоком. Усложним пример:
    import threading, queue
    
    class MyWorkerThread(threading.Thread):
        def __init__(self, arg1: float, arg2: float): # передаём потоку входные данные 
            # поток не должен их менять!
            super().__init__()
            self.arg1 = arg1
            self.arg2 = arg2
            self.result: t.Optional[float] = None
            self.progress = queue.Queue()
        def run(self):
            for i in range(10):
                time.sleep(1) # имитируем длительную работу
                self.progress.put(i/10) # сообщаем о прогрессе
            self.result = self.arg1 + self.arg2
            self.progress.put(1.00)

    Тогда код использования изменится следующим образом:
    worker = MyWorkerThread(42, 69)
    worker.start()
    while True: 
        if worker.is_alive():  # проверяем, жив ли поток
            # делаешь ещё что-то, пока поток работает
            try:
                progress = worker.progress.get(block=True, timeout=0.5)
            except queue.Empty: # поток ничего не сообщил
                print('Still working...')
            else:
                print(f'Still working... {progress:.0%}')
                worker.progress.task_done() # один вызов task_done() на один успешный вызов get()!
        else:
            # поток завершился, даём знать пользователю.
            print(f'Done! Result is {worker.result}!')
            break # выходим из цикла

    Если тебе нужно передать потоку новые задания, то можешь использовать ещё одну queue.
    Ответ написан
    Комментировать
  • Как выполнять функцию каждую минуту в определенный интервал времени aioschedule?

    Vindicar
    @Vindicar
    RTFM!
    Вариант А. Выполнять каждые 5 минут, внутри функции проверять текущее время. Ничего не делать, если время не в заданном интервале.

    Варинат Б. Запланировать две функции. Одна, в 10:00, запустит через asyncio.create_task() простую зацикленную функцию, которая будет вызывать твою функцию, а потом делать await asyncio.sleep(300). Ссылку на задачу, возвращённую create_task(), надо будет сохранить в глобальную переменную.
    Другая функция, в 14:00, остановит эту задачу.

    Вариант А проще, и надёжнее в плане ситуации, когда программа запущена в промежуток между 10:00 и 14:00.
    Ответ написан
  • Multiprocessing.Process OSError: [WinError 87] Параметр задан неверно, что делать?

    Vindicar
    @Vindicar
    RTFM!
    Ну так тебе же говорят:
    _pickle.PicklingError: Can't pickle <function <lambda> at 0x00000122F23CEB00>: attribute lookup <lambda> on __main__ failed

    Для передачи данных в соседний процесс они сериализуются через модуль pickle. А сериализовываться так может далеко не всё.
    Если тебе нужно скинуть в соседний процесс код... это проблема. Может, получится скинуть словарь с локальными переменными, строку с кодом, и вычислить эту строку через eval() уже "на месте".
    Альтернативно, просто замени лямбду на нормальную функцию, и попробуй передать либо её, либо имя этой функции, чтобы дочерний процесс сам её взял из globals() или еще откуда.
    Ответ написан
    Комментировать
  • Как решить данную задачу на python?

    Vindicar
    @Vindicar
    RTFM!
    Вычисляешь корень, вычисляешь первый элемент последовательности - x, вычисляешь второй элемент (x + x/x) / 2.
    Потом в цикле, пока модуль (abs) разницы корня и последнего вычисленного элемента больше заданной точности, повторяешь вычисление. Предыдущему элементу previous присваиваешь последний элемент last, а последний элемент last вычисляешь как last = (x + x/previous) / 2. Считаешь итерации.
    Когда выйдешь из цикла, выводишь номер итерации, последний вычисленный элемент last, его отличие от реального корня.
    Ответ написан
  • Не работает replace в голосовом ассистенте?

    Vindicar
    @Vindicar
    RTFM!
    Ну ты же явно какую-то глупость делаешь.
    if cmd == "sreachyoutube":
            search_term = cmd.replace("Кеша видео", " ")

    Если в переменной cmd лежит строка sreachyoutube(!), то там по определению не может содержаться подстроки "Кеша видео".
    Ответ написан
    8 комментариев
  • Как узнать находятся ли все элементы списка в другом списке?

    Vindicar
    @Vindicar
    RTFM!
    Преврати первый список и второй список в множества. Если первое множество является подмножеством (issubset()) второго, то условие выполнилось.
    Если есть возможность строить множество одновременнео с первым списком, это упростит задачу.
    Ответ написан
    1 комментарий
  • Как сделать таймер в python?

    Vindicar
    @Vindicar
    RTFM!
    1. При получении команды получить текущее время.
    2. Проверить в хранилище (словарь в памяти, база данных, не принципиально) когда этот человек посылал команду в прошлый раз.
    3а. Если интервал времени достаточно длинный, выполнить команду и сохранить текущее время в хранилище.
    3б. Если интервал времени недостаточно длинный, дать предупреждение/забанить/застрелиться.
    Подробности

    Что за команда, о чём речь, каким кодом это реализовано... гадать никто не собирается.
    Ответ написан
    Комментировать
  • Где ошибка в коде?

    Vindicar
    @Vindicar
    RTFM!
    Ну что, ошибка правильно тебе говорит.
    def __init__(self, replaybtn):
            self.replaybtn = replaybtn

    Ты говоришь, что конструктор твоего класса Dinobot принимает один параметр, replaybtn.
    А ты ему потом передаёшь два параметра: (470, 440), (202, 442)
    Ответ написан
    2 комментария
  • Как объединить в проверке (if call.data == '') несколько параметров?

    Vindicar
    @Vindicar
    RTFM!
    if call.data == 'apple' or 'melon':    #Вот в этом месте проблема

    Ещё один ботописатель с этой проблемой. Вот откуда такое упорное желание дословно переводить с русского на питон?

    Правильно:
    if call.data in ('apple', 'melon'):
    Ну или так:
    if call.data == 'apple' or call.data == 'melon':

    То, что ты написал, расшифровывается как
    if (call.data == 'apple') or ('melon' != ''):
    что эквивалентно
    if (call.data == 'apple') or True:
    А x or True всегда даст True, так же как x and False всегда даст False.
    Так что получается в итоге
    if True:

    Учи основы языка - потом уже берись за ботов.
    Ответ написан
    1 комментарий
  • Как сделать перенос строк в парсере?

    Vindicar
    @Vindicar
    RTFM!
    Так же, как и всегда. Добавь символ "\n" в конец выводимой строки.
    Ответ написан
    2 комментария