• Можно ли импортировать что-то из разных... серверов?

    Vindicar
    @Vindicar
    RTFM!
    И как это сделать?

    sundnl, взять и сделать. Не зная подробностей, тебе никто ничего не подскажет. С такой формулировкой тебя даже на фрилансе пошлют, и будут правы.

    Что за игра, что за сервер? Может, у него уже есть какое-то API, по которому можно вытащить интересующие данные?

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

    Если API нет, есть ли доступ к исходникам сервера? Как организован рабочий цикл сервера? Потребуется ли нам запускать отдельный поток - а значит, синхронизировать доступ к искомым данным? Или же там что-то на базе asyncio, и мы можем просто добавить асинхронную задачу?

    Нужно определиться с форматом отдачи данных - тут лучше не изобретать велосипед, а использовать JSON, если данных не очень много.

    Можно подумать о том, чтобы добавить в серверный скрипт небольшой сервер на Flask, или на базе asyncio streams, или на голых сокетах. Конкретная реализация зависит в том числе от того, кто проявляет инициативу: если бот запрашивает, а сервер отвечает, то Flask позволит обращаться к серверу по HTTP, а не громоздить велосипед на сокетах. Если же сервер может что-то слать по своей инициативе, то тут уже HTTP подойдёт так себе.

    Когда ответишь на все перечисленные вопросы, вот тогда у тебя будет вопрос, стоящий обсуждения. В конце концов, правильно поставленный вопрос - это половина ответа.
    Ответ написан
    Комментировать
  • Насколько допустимо с точки зрения стилистики вызывать Exception в конструкции if/else?

    Vindicar
    @Vindicar
    RTFM!
    Подход, предложенный @Ипатьев, в принципе неплох.
    Но я считаю, стоит помнить, что питон - язык с динамической типизацией. Если какой-то тип умеет выполнять требуемые от него операции, стоит этот тип принимать. Иными словами, тебе необязательно принимать именно список или кортеж - тебе подойдёт любая коллекция, которую можно перечислить, и у которой есть длина.
    Так что я бы посоветовал сделать иначе:
    import collections.abc as abc
    # Collection требует поддержки итерации, проверки вхождения и длины.
    def avg(data_set: abc.Collection[int]) -> float:  # type hint для разработчика и IDE
        # если получим что-то не то, будет выкинуто TypeError - а нам это и надо.
        avg = sum(data_set) / len(data_set)  # такое деление вернёт float
        return avg


    Либо, если тебе хочется своей обработки ошибки:
    import collections.abc as abc
    
    def avg(data_set: abc.Collection[int]) -> float:  # type hint для разработчика и IDE
        # протокол abc.Collection можно проверять через isinstance()
        if not isinstance(data_set, abc.Collection):  
            raise TypeError(f'data_set must be a collection of ints, got {type(data_set)}')
        avg = sum(data_set) / len(data_set)  # такое деление вернёт float
        return avg

    Иными словами, может иметь смысл определить минимально необходимый тебе набор операций, и описывать как входной тип именно его. Хотя зачастую можно и не заморачиваться. Если ты значешь, что будешь передавать в функцию только список - можешь прописывать только список.

    И это будет работать:
    >>> avg([1,2,3])  # список
    2.0  # работает
    >>> avg({1,2,3})  # множество
    2.0  # работает
    >>> avg(x for x in range(3))  # выражение-генератор
    Traceback (most recent call last):  # отказ, у генераторов нет заранее известной длины
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 3, in avg
    TypeError: data_set must be a collection of ints, got <class 'generator'>
    Ответ написан
    Комментировать
  • Как сделать активным свой выбор в меню?

    Vindicar
    @Vindicar
    RTFM!
    Ну гугл по "pygame menu" выводит на одноименный пакет pygame-menu. Посмотри примеры кода, если понравится - установи и пользуйся.
    Ответ написан
  • Как спарсить данные с сайта?

    Vindicar
    @Vindicar
    RTFM!
    Этот формат называется JSON. В стандартной библиотеке Питона есть одноименный модуль для работы с ним.
    Он позволит превратить строку в обычный питоновский словарь. Как со словарём работать, надеюсь, знаешь.
    Вытащишь из словаря нужные данные, и с ними уже делай что надо. Хоть выводи на экран, хоть закинь в другой пустой словарь (чтобы лишнего ничего не было) и запакуй обратно в JSON.
    Ответ написан
    1 комментарий
  • Различия работы requests в Windows и Linux?

    Vindicar
    @Vindicar
    RTFM!
    Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:103.0)

    Попробуй на винде воткнуть User-Agent от виндовой версии мозиллы.
    Ответ написан
  • Почему сайт отклоняет запросы?

    Vindicar
    @Vindicar
    RTFM!
    сначала всё работает хорошо, но черех некоторе время выдает ошибку

    Как ни странно, сайт подозревает, что твой бот-парсер - это бот-парсер.
    Задержки, которые у тебя прописаны внутри скрипта, никакого значения не имеют. К этому моменту данные уже получены с сайта, и с ним ты больше не взаимодействуешь. Имеет значение интервал между повторными вызовами requests.get(). У тебя в скрипте вызов не повторный, но ты же сам скрипт неоднократно дёргаешь, я так понял?
    Ответ написан
    5 комментариев
  • Как прервать и перезапустить программу?

    Vindicar
    @Vindicar
    RTFM!
    if bet != 0 or 1 or 2:
    Ну конечно дословный перевод с русского на питон будет работать неправильно. Это условие интерпретируется как
    if (bet != 0) or (1) or (2):
    В питоне целые числа истинны, если они не нулевые. Т.е. получаем
    if (bet != 0) or (1 != 0) or (2 != 0):
    Как следствие
    if (bet != 0) or True or True:
    А как известно, X or True всегда даст True, независимо от значения X.
    Так что всё условие всегда даст True.
    Правильно или так:
    if (bet != 0) and (bet != 1) and (bet != 2):
    или так
    if bet not in (0, 1, 2):

    По поводу зацикливания - заверни кусок программы, отвечающий за ввод, в цикл while.
    Ответ написан
    Комментировать
  • Как ускорить работу Python в разы?

    Vindicar
    @Vindicar
    RTFM!
    Ты документацию читал?
    get_symbol_ticker(**params)[source]
    Latest price for a symbol or symbols.

    Выделение моё. Судя по докам, get_symbol_ticker() позволяет за один запрос получать инфу сразу о нескольких символах. Готов спорить, что это будет быстрее.

    Так как в заголовке функции **params вместо нормального описания параметров, я подозреваю, что переданные параметры пробрасываются прямиком в API binance. Открываем доки на это API, благо ссылка есть прямо в первых доках. Видимо, что можно в параметрах передать строку symbol, или строку-список symbols вида
    ["BTCUSDT","BNBUSDT"]. Как я понял, это именно строка такого вида, а не список.

    Вот скажи мне, что тебе помешало найти эту информацию самостоятельно? Две минуты гуглежа, и это при том что я с бинансом не работал вообще.

    Ну и да, серьёзно? f'{str(ticker1)}', притом что ticker1 - это уже заведомо строка? Больше строк богу строк...
    Ответ написан
    Комментировать
  • Как вызвать асинхронную функцию с синхронной функции?

    Vindicar
    @Vindicar
    RTFM!
    Если твой вызов асинхронной функции сводится к реакции на завершение выполнения синхронного кода, то используй run_in_executor(), он позволяет выносить код хоть в процесс, хоть в поток (смотря какой executor используешь), и оборачивает его в обычную асинхронную корутину, которую можно await-ить. Для простых случаев есть asyncio.to_thread(), но тут вопрос в природе выполняемого кода. CPU-bound код на питоне будет занимать GIL, тормозя остальные потоки (эта общая болезнь для потоков в питоне).

    А вообще есть асинхронные версии селениума, типа aioselenium или selenium-async. Можешь попробовать одну из них.

    Если же тебе нужно вызвать асинхронную корутину именно посреди синхронного кода в другом потоке, то run_coroutine_threadsafe() может помочь. Пример из доков на питон.
    async def coro_func():
         return await asyncio.sleep(1, 42)
    
    # Later in another OS thread:
    
    future = asyncio.run_coroutine_threadsafe(coro_func(), loop)
    # Wait for the result:
    result = future.result()
    Ответ написан
  • Как исправить str() takes at most 3 arguments (123 given)?

    Vindicar
    @Vindicar
    RTFM!
    Потому что непосредственное преобразование списка в строку всегда возвращает именно такой вид.
    А если тебе нужно соединить список строк разделителями, смотри в сторону str.join(), ну или сам итерируйся по списку и склеивай строки.
    Запрос в гугл тебе выше уже написали.
    Ответ написан
    Комментировать
  • Проблема с циклом while?

    Vindicar
    @Vindicar
    RTFM!
    else:
        logger.success(f'{current_otc} | The message was successfully sent')
        sleep_messages = random.randint(3, 7)
        logger.info(f"I will sleep {sleep_messages} seconds")
        time.sleep(sleep_messages)
        return  # <---- это прервёт выполнение функции. Сдаётся, мне, ты не этого хотел.
    Ответ написан
    Комментировать
  • Можно ли внутри асинхронных функций запускать обычные?

    Vindicar
    @Vindicar
    RTFM!
    Да, можно, если они кратковременные.

    Идея асинхронности в питоне проста как две копейки: асинхронные функции выполняются в рамках однопоточного рабочего цикла (loop), и умеют сказать ему "когда вот эта операция закончится - продолжи выполнять меня. А пока займись чем-нибудь" (await-вызов).

    Соответственно, пока асинхронная функция выполняет синхронный код, т.е. код между await'ами (ну и началом/завершением в т.ч.), рабочий цикл не может выполнять никакую другую асинхронную функцию. Это плюс, так как не приходится беспокоиться из-за одновременного доступа, как при работе через потоки. Но минус в том, что долгие синхронные операции не позволяют циклу выполнять другие асинхронные функции, т.е. реагировать на внешние события.

    Отсюда вывод: если твой синхронный код выполняется быстро - его можно вызывать из асинхронных функций без проблем. Если это длительный (блокирующий) код - его либо нужно заменить асинхронным, либо засунуть в отдельный поток с помощью run_in_executor(), либо на худой конец разбавить вызовами await asyncio.sleep(0). Такой вызов просто возвращает управление в рабочий цикл, чтобы тот мог разобраться с текущими делами, а потом вернуться и продолжить выполнение этой асинхронной функции.

    Обращения к БД на малых объёмах и малых нагрузках не слишком длительны. Если очень надо, есть асинхронный aiosqlite.
    Ответ написан
    Комментировать
  • Как задать формат вывода для типа float по умолчанию?

    Vindicar
    @Vindicar
    RTFM!
    Нет. Можно вынести формат в строковую переменную и использовать её для форматирования при выводе.
    Ответ написан
    Комментировать
  • Как вывести фото на экран?

    Vindicar
    @Vindicar
    RTFM!
    Заголовок Content-Type попробуй прописать, в конструкторе Response. Без него сервер не знает, что ты отдаёшь, и отдаёт контент как application/octet-stream, т.е. какой-то произвольный бинарный блоб. А такие вещи браузер может только сохранить.
    Тебе нужно знать формат твоего файла, и отдать правильный content type, например, image/jpeg.
    Ответ написан
    1 комментарий
  • Как отследить изменения поля класса, если это список?

    Vindicar
    @Vindicar
    RTFM!
    Замени список на свой класс, в котором будет механизм оповещения об изменениях. Тогда вышележащий класс должен будет подписаться на эти изменения.

    Альтернативно, спрячь список (сделай приватным) и сделай в классе публичные методы работы с ним: получение по индексу, задание по индексу, добавление, удаление.
    Ответ написан
    Комментировать
  • Почему возникает ошибка TypeError: join() argument must be str, bytes, or os.PathLike object, not 'int'?

    Vindicar
    @Vindicar
    RTFM!
    Ты где-то передал число вместо строки. Судя по трейсбеку, ведущему в clickupython, где-то при вызове методов ClickUpClient. Читай документацию, сверяй типы данных с тем, что ты реально передаёшь.
    Ответ написан
    Комментировать
  • Почему выдаёт ошибку с @bot?

    Vindicar
    @Vindicar
    RTFM!
    Блин, еще раз - текст ошибки угадывать нужно?
    Вбил в гугл "@bot.callback_query_handlers", он подсказывает, что наверно нужно "@bot.callback_query_handler" (в конце нет буквы S).
    Ответ написан
    Комментировать
  • Как раскодировать request?

    Vindicar
    @Vindicar
    RTFM!
    Это обычное указание символа по коду, принятое в XML (и как его подмножество, в HTML).
    import html
    print(html.unescape('&#1087;&#1080;'))
    Ответ написан
    Комментировать
  • Как составить из букв слово?

    Vindicar
    @Vindicar
    RTFM!
    0. Скачай откуда-нибудь подходящий список существующих слов.
    1. Отсей слова, которые начинаются не на одну из заданных букв.
    2. Если кажду букву надо использовать ровно один раз, отсей слова, у которых длина не подходит.
    3. В оставшихся словах отсортируй буквы и сравнивай результат с отсортированным списком данных букв. Это если каждая буква используется один раз. Если буквы могут повторяться, то сделай множество букв слова и множество данных букв, и сравнивай их.
    Ответ написан
    Комментировать
  • Как решить проблему с SQLite3?

    Vindicar
    @Vindicar
    RTFM!
    С чего ты взял, что возвращаемое значение второй раз будет не None? Ты проверял, что данные заносятся?
    Собственно, в том и ошибка - у тебя уже есть запись с таким userid, второй раз вставить нельзя.

    А твоя GetInfo() не работает. Почему? Внезапно, в SQL сравнение - это =, а не ==. А ошибку тебе не пишет, потому что ты сделал except: pass. За такую практику вообще надо бить по пальцам линейкой, надеюсь, ты теперь понял почему.
    Ну и до кучи, если хочешь проверить существование, то лучше сделать запрос вида SELECT COUNT(*) FROM main WHERE user_id = ? или
    SELECT EXISTS(SELECT * FROM main WHERE user_id = ?)
    . Эти запросы гарантированно вернут одну строку с одним значением, 0 или 1. 0 - строка не существует, 1 - строка существует.
    Ответ написан
    1 комментарий