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

    Vindicar
    @Vindicar
    RTFM!
    Ну вот так абстрактно мало что можно посоветовать.
    Хотя взаимодействие B, C и D говорит о неудачном распределении обязанностей.
    Есть два варианта.

    А) Один класс занимается взаимодействием с пользователем. Он же (или отдельный, если проект достаточно большой) занимается определением того, когда какую операцию выполнять. Остальные классы предоставляют реализации отдельных операций, и друг о друге не знают.

    Б) Один класс (роутер/машина состояний) определяет, какой сценарий взаимодействия с пользователем сейчас выполняется. Другие классы реализуют по одному сценарию взаимодействия каждый, предоставляя интерфейс, хранение данных и выполнение операций в рамках сценария. Они не реализуют переход между сценариями сами - вместо этого они оповещают роутер о желаемом переходе. А тот уже оповещает текущий сценарий о завершении, подгружает другой сценарий (экзепляр класса) и оповещает его о начале работы.
    Ответ написан
  • Из-за чего возникла ошибка 'TypeError: Bot.send_message() missing 1 required positional argument: 'text''?

    Vindicar
    @Vindicar
    RTFM!
    await Bot.send_message(message.from_user.id, message.text)

    Ты пытаешься вызвать метод класса Bot, а не экземпляра bot.

    Поясню. В питоне методы устроены довольно прямолинейно:
    class Test:
        def test(self, x):
            print(f"Я {self} и я получил {x}")
    
    t = Test()  # создаём экземпляр
    t.test(42)  # Я <__main__.Test object at 0x000001BB195CBC70> и я получил 42
    # это тоже сработает, и это практически эквивалентно вызову выше
    Test.test(t, 42)  # Я <__main__.Test object at 0x000001BB195CBC70> и я получил 42
    # а это - то, что попытался сделать ты:
    Test.test(42)  # TypeError: Test.test() missing 1 required positional argument: 'x'
    # потому что вызван метод класса, а не объекта, и его первый параметр (42) интерпретирован как self
    Ответ написан
    4 комментария
  • Как сделать проверку if на тип переменной?

    Vindicar
    @Vindicar
    RTFM!
    Ну во-первых, оператор is проверяет идентичность объектов. Учи язык.
    a = [1, 2, 3]
    b = [1, 2, 3]
    print(a == b)  # True - списки имеют одинаковое содержимое
    print(a is b)  # False - a и b ссылаются на разные объекты-списки, а не на один и тот же.


    Если тебе нужно узнать, содержит ли переменная ссылку на объект указанного типа, используй isinstance().
    a = 1
    b = 1.0
    print(isinstance(a, int), isinstance(a, float))  # True False - a это int, но не float
    print(isinstance(b, int), isinstance(b, float))  # False True - b это не int, это float
    print(isinstance(a, (int, float)))  # True - a является чем-то из двух: или int, или float

    Но это работает только для значений корректного типа - это НЕ позволит проверить, содержит ли строка корректное представление числа, к примеру. Для этого либо используй try-except, либо регулярные выражения. Только вот в except не стоит писать pass - нужно подумать, что программа должна делать, если введено не число.
    Ответ написан
    1 комментарий
  • Бот обратной связи на Aiogram?

    Vindicar
    @Vindicar
    RTFM!
    Ну во-первых, "не получилось" - это, конечно, офигенно детальное и полезное описание проблемы.

    Во-вторых, я подозреваю, что дело вот в этом:
    photo=message.photo[0].file_id
    Наверняка если к сообщению не приложено фото, коллекция photo пуста, тогда попытка обращения к нулевому элементу выкинет исключение, так как этого нулевого элемента просто нет. Проверяй, есть ли вообще что-то в message.photo.
    Ответ написан
    Комментировать
  • Как вызвать функции зависимо от колбека?

    Vindicar
    @Vindicar
    RTFM!
    У объекта call (тип CallbackQuery) есть свойство data. Ты его можешь задать при создании кнопки (которое почему-то опущено в коде), тогда оно будет иметь значение, соответствующее нажатой кнопке. А дальше просто сравниваешь это значение с желаемым.
    Ответ написан
    3 комментария
  • Можно ли сгенерированный Literal передать в параметры функции?

    Vindicar
    @Vindicar
    RTFM!
    поэтому о статическом литерале речи не идет

    А ничего, что литералы, как и большинство инструментов type-checking, предназначены для статической проверки кода? Интерпретатор их игнорирует при выполнении. Их использование в discord.py, хотя и красивое, но всё же нестандартное.
    Поэтому само сочетание "динамический литерал" есть бессмыслица.

    Принимай жанр как строку, и проверяй её самостоятельно, либо, если очень хочется, прописывай для жанра свой конвертер.
    Ответ написан
    Комментировать
  • Как в reply_markup добавить больше переменных с копками?

    Vindicar
    @Vindicar
    RTFM!
    bot.send_photo(message.chat.id, photo, " Выберите нужную функцию:",
    parse_mode="html", reply_markup=tg, info)

    reply_markup=tg - аргумент, переданный по имени
    info - аргумент, переданный позиционно.
    Питон не позволяет указывать позиционные аргументы ПОСЛЕ именованных. Укажи для info имя аргумента, в который ты хочешь передать это значение, по аналогии с reply_markup= или parse_mode=.
    Ответ написан
    Комментировать
  • Как разделить текст на части?

    Vindicar
    @Vindicar
    RTFM!
    Т.е., если переформулировать: разбить текст по символу перевода строки так, чтобы размер первой части не превышал N символов?
    text = """Текст слово Текст
    Новая строка
    Ещё новее строка"""
    N = 12
    
    start, rest = text[:N], text[N:] # отделяем ту часть текста, где мы ищем перевод строки, от остатка
    first, _, second = text.rpartition('\n') # ищем последний перевод строки в этой части - до него "начало"
    last = (second + rest) if second else rest # "конец" собираем из того что после перевода строки и остатка
    print('-'*10)
    print(first)
    print('-'*10)
    print(last)
    print('-'*10)

    Если перевода строки в первой части текста нет, то текст будет просто разрезан по N символам.
    Ответ написан
    2 комментария
  • Как из main.py запустить несколько других файлов .py, чтобы они работали параллельно?

    Vindicar
    @Vindicar
    RTFM!
    Другие идеи есть в документации, просто её надо читать.

    subprocess.Popen() БЕЗ использования wait() или communicate().
    Ответ написан
  • Можно ли узнать возврат функции при использовании многопоточности Thread на Python?

    Vindicar
    @Vindicar
    RTFM!
    Лучше используй долгоживущие потоки и пару queue.Queue. Из первой потоки в цикле извлекают задания и обрабатывают их, во вторую складывают ответы. Главный поток - наоборот, кладёт задания в первую очередь и извлекает ответы из второй.

    См. также: паттерн "поставщик-потребитель".
    Ответ написан
    Комментировать
  • Как сделать вывод в лог logging python?

    Vindicar
    @Vindicar
    RTFM!
    Добавь помимо FileHandler еще и StreamHandler.

    И да, я бы не советовал настраивать логи в конструкторе класса. Пусть класс использует getLogger() и пишет в лог, но определять уровни и места, куда лог пишется, должна основная программа.
    Ответ написан
    Комментировать
  • Как убрать лишние знаки?

    Vindicar
    @Vindicar
    RTFM!
    Ещё один не выучил основы языка, но пытается работать с БД.

    fectchone() возвращает кортеж, в твоём случае кортеж с одним элементом. Скобки - это строковое представление кортежа. Как вытащить значение из кортежа - читай по ссылке.

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

    Vindicar
    @Vindicar
    RTFM!
    asyncio создаёт цикл-реактор (loop) только для главного потока. Если тебе нужен отдельный реактор в другом потоке (что само по себе повод остановиться и задуматься - нахрена?), создавай его сам в начале потока, потом уже вызывай асинхронный код.
    См. asyncio.new_event_loop() и asyncio.set_event_loop().
    Ответ написан
    1 комментарий
  • Почему 2-handler не запускается?

    Vindicar
    @Vindicar
    RTFM!
    @bot.message_handler() означает, что следующая функция будет обслуживать ВСЕ входящие сообщения, независимо от их содержимого. Соответственно, будет вызываться она, а последующие обработчики сообщений - нет.
    Либо используй параметры message_handler(), чтобы сузить круг обрабатываемых этой функцией сообщений.
    Либо помещай всю логику обработки сообщений в эту функцию, т.е. соедини оба обработчика в один.
    Ответ написан
    Комментировать
  • Из за чего появляется ошибка в строке client.run(config.TOKEN)import discord?

    Vindicar
    @Vindicar
    RTFM!
    В чём моя проблема ?

    1. В том, что ты не знаешь питон, а рвёшься писать ботов. Иначе знал бы, что client.run(config.TOKEN)import discord - это и впрямь неверный синтаксис.
    2. В том, что ты не осилил редактор текста на этом сайте, и не озаботился отформатировать код.
    3. Ну и в том, что ты, походу, вставил код бота в файл дважды.
    Ответ написан
    Комментировать
  • Как ипортировать функции из файлов?

    Vindicar
    @Vindicar
    RTFM!
    Ещё один товарищ не учил Питон, но рвётся написать божественного бота...

    Когда ты импортируешь файл (модуль), этот модуль выполняется - практически так же, как если бы ты его запустил непосредственно. Различие есть, но небольшое. Теперь посмотрим на твои файлы.
    В первом файле ты объявляешь переменную bot. Она существует в пространстве имён первого файла (модуля).
    Если ты в нём делаешь import second_file, в нём тоже присутствует создание переменной bot - в локальном пространстве имён этого модуля. Это две разные переменные, и два разных экземпляра класса Telebot.
    Поэтому когда ты выполняешь в одном файле bot.run() (ну или как там бот запускается), ты запускаешь только один экземпляр. Второй остаётся неактивированным, и всё, что к нему привязано, не работает.

    Тебе надо как-то передать переменную bot во-второй файл, не нарвавшись при этом на циклический импорт (чтобы не было "первый импортирует второй, а второй - первый").
    Тут поможет ещё один простой факт: в питоне всё - операторы. Т.е. объявление функции - это оператор. Его можно помещать куда угодно, внутрь любого блока программы: внутрь if, внутрь цикла, внутрь другой функции. Он выполнится при выполнении соответствующего блока.
    Так что ты можешь завернуть свои обработчики из второго файла в функцию, принимающую ссылку на bot. А потом импортировать эту внешнюю функцию в первый файл и там её вызвать.
    #второй файл, second_file.py
    import telebot
    from telebot import types
    # эта функция создаст все обработчики и зарегистрирует их в предоставленном боте
    # вызывай её строго один раз за скрипт
    def register_handlers(bot):
        # а тут уже пошли обработчики
        @bot.message_handler(commands=['start'])
        def start(message):
            markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
            btn0 = types.KeyboardButton(' Каталог фильмов')
            btn1 = types.KeyboardButton(" Каталог фильмов")
            btn2 = types.KeyboardButton(' Случайный фильм')
            btn3 = types.KeyboardButton(' Предложить фильм')
            markup.add(btn0, btn1, btn2, btn3)
            bot.send_message(message.from_user.id, ' Привет, {0.first_name}. Я Kinomorph - бот, с которым ты можешь найти интересный фильм для просмотра вечером\n \n Если у тебя есть номер или название фильма, ввести его можно прямо сейчас'.format(message.from_user), reply_markup=markup)
    
    # любой код, который не должен исполняться при импорте, оформляй так:
    if __name__ == '__main__':   # переменная __name__ содержит имя, под которым импортируется модуль
        print('Этот код выполнится ТОЛЬКО если файл запущен напрямую.')
        print('Он не выполнится при импорте файла.')


    # первый файл, main.py
    import telebot
    import config
    import second_file  # модуль импортируется - в нём __name__ будет равно "second_file", а не "__main__"
    
    # инициализация
    bot = telebot.TeleBot(config.Token)
    second_file.register_handlers(bot)  # тут вызывается импортированная функция
    Ответ написан
    Комментировать
  • Почему не работает bot_func.stop(Client, module Pyrogram)?

    Vindicar
    @Vindicar
    RTFM!
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)

    Зачем?!
    Если у тебя бот асинхронный, просто сделай саму функцию GetUserByUsername() async.
    Ответ написан
  • Как получить списки в переменные?

    Vindicar
    @Vindicar
    RTFM!
    list_of_lists = [spisok[i:i + n] for i in range(0, len(spisok), n)]
    Ответ написан
    Комментировать
  • Как исправить "io.UnsupportedOperation: read"?

    Vindicar
    @Vindicar
    RTFM!
    fp = open(f'captcha_{str(ran)}.jpg', 'wb')
    fp.write(res.content)

    Ты открыл файловый объект для записи, а чтобы его отправить, нужно чтение.
    Или открой объект для модификации ("wb+") и сделай fp.seek(0, 0) после записи, чтобы вернуться в начало файла.
    Или закрой файл, и открой его снова, уже для чтения ("rb").
    Ответ написан
  • Не выполгяется последняя часть кода @bot.callback_query_handler(func=lambda call:True) def callback2(call): почему и как исправить?

    Vindicar
    @Vindicar
    RTFM!
    @bot.callback_query_handler(func=lambda call:True)
    func говорит боту, когда вызывать обработчик. Бот вызывает только ОДИН обработчик (первый подходящий).
    func=lambda call:True означает, что обработчик должен вызываться для ВСЕХ кнопок.
    Научись различать обработчики по call.data. Например, пусть у одной группы кнопок data начинается с "foo.", а у другой - с "bar.".
    item = types.InlineKeyboardButton('4', callback_data='foo.question1')
    item2 = types.InlineKeyboardButton('3', callback_data='foo.question2')

    gotov = types.InlineKeyboardButton('Готов', callback_data='bar.gotov')

    Тогда ты сможешь прописать два обработчика:
    @bot.callback_query_handler(func=lambda call:call.data.startswith('foo.'))

    и
    @bot.callback_query_handler(func=lambda call:call.data.startswith('bar.'))


    Разумеется, вместо foo и bar можно придумать свои префиксы, в том числе многоуровневые (типа callback_data='questions.q1.answer1').
    Ответ написан
    1 комментарий