Задать вопрос
Ответы пользователя по тегу Python
  • Можно ли сделать переменную глобальной в функции?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Вообще глобальные переменные – это плохо и ведёт в ряде случаев к типичным, но трудно уловимым и неочевидным багам.
    Если вам нужно, чтобы разные вызовы разных функций имели доступ к одной и той же переменной, нужно этим функциям передать контекст. Контекстом может служить объект, куда всё необходимое добавлено в виде аргументов.
    Нужно помнить о необходимости правильно и своевременно инициализировать контекст.
    Думаю у aiogram есть штатный способ передачи контекста в обработчики, но в простых случаях достаточно сделать глобальную переменную и при запуске инициализировать в ней контекст. Так вам не придётся декларировать ее как глобальную в функциях, она будет найдена при обходе неймспецсов.
    Присвоения будут внутри контекста, а глобальная переменная останется неизменной.
    Ответ написан
  • Как исправить код телеграмм бота, чтобы вместо всей информации о погоде можно было выводить( с помощью команд) отдельные данные погоды?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    1. Добавить новые команды.
    2. Выводить по ним частичные данные.
    Ответ написан
    Комментировать
  • При создании телеграм бота на PyDroid вылезает ошибка, что делать?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Ну вот же написано:
    ValueError: Unrecognised argument(s): Level

    Где у вас такой аргумент поищите глазами!
    А, не т не надо искать, ведь уже написно где:
    File "", line 6, in

    ...
    logging.basicConfig(Level=logging.INFO)
    ...

    А теперь читайте документацию на эту функцию, или посмотрите какие у нее аргументы в исходниках, или идите изучать питон с начала. Рано вам такое.
    Ответ написан
    3 комментария
  • Как зациклить пока не выполниться условие?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Вам тут не нужно никакого цикла. Просто считайте, что в ответ на каждое сообщение или нажатие пользователя вы по новой заходите в эту функцию. Разделите куски алгоритма условием по содержимому входного текста. Делайте действия только в ветках.
    Ответ написан
  • Можно ли использовать open('file','r').read() в python?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Можно вот так делать:
    content = pathlib.Path('file').read_bytes()
    В таком случае всё правильно закроется.
    Вообще нужно стараться уже современные методы работы с файлами и путями использовать, а не доисторические.

    Вы, кстати, самозакрывающуюся читалку и сами сделать можете:
    def readfromfile(filename, mode='t'):
        assert mode in {'b', 't'}
        with open(filename, mode=mode) as f:
            return f.read()

    Но зачем, когда есть замечательный pathlib в третьем питоне из коробки?

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

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    А в чем проблема? Пусть от хранит состояние в БД и в ту же БД ходит админка за инфой.
    Что именно вам не понятно и что не получается?
    Ответ написан
    Комментировать
  • Python - как облегчить скрипт Python?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Проблема в том, что задержка тут имеется только в do_some*, а в остальных случаях ваш скрипт с максимальной возможной скоростью скриншотит, кропает и сравнивает картинки. То есть программа написана так, что должна и будет утилизировать своим процессом всё ядро полностью. Я так понимаю проц у вас четырёхядерный, отсюда и 25 процентов.
    Добавьте задержку в основной цикл проверки и вы сильно разгрузите ваш процессор.
    Ответ написан
    3 комментария
  • Как хранить схемы диалогов для чат-бота?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Нормально ORM работает с JSON, но не понятно зачем вам именно реляционная БД, если вы фактически отказались от нормализации и джойнов.
    Для вашего этого варианта подойдёт и NoSQL.
    таких ботов/диалогов может быть много.

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

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

    В вашем случае можно сделать всё на ORM и реляционной базе. Включая отдельные модели для вариантов ответов и прочего.
    Можно отказаться от ORM и размещать одного бота в одном документе. Тогда можно использовать монгу и десериализацию документа в собственную структуру классов. Тут писать получится больше, но и гибкость будет выше, можно будет пользовтаельские плагины какие-то прикручивать... вопрос - надо ли это и понадобится ли в будущем?

    Фактически диалог - это конечный автомат. Его можно представить в виде графа. Человечество уже давно придумало много способов сохранять и оперировать графом в любой БД, в том числе реляционной.
    Ответ написан
    2 комментария
  • Программа "Python" не работает. Возникшая проблема привела к прекращению работы программы. Краш ntdll.dll. Куда копать?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Избавляйтеь от винды и от QT. У вас там через GUI с чем-то взаимодействвать надо? Стройте процесс так, чтобы всё было максимально просто. Если куда-то ходите через браузер, есть Selenium для этого.
    Делайте всё headless, делайте стабильной простой и предсказуемой OS (linux).
    Максимально упрощайте код, избавляйтесь от лишних зависимостей, тем более бинарных. Чем меньше у вас таких вот внешних черных ящиков, тем лучше.
    Ответ написан
    Комментировать
  • Как отсортировать по ORDER BY используя ещё и rowid?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Если вам зачем-то нужен rowid, скорее всего вы делаете что-то не так. Для чего он вам нужен?
    В реляционных БД положение в таблице (не в выборке, а именно в таблице) ничего не значит. Вы не должны этим управлять и не за чем получать это положение. Уверен, есть другие способы достичь того, что вы там пытаетесь достичь. К примеру, если вам нужно узнать сколько пользователей имеют кэш меньше вашего, то так и запрашивайте:
    SELECT count(*) 
    FROM users u 
    WHERE u.cash < (SELECT cash FROM users WHERE id = :my_user_id)

    Если нужен какой-то рейтинг беднейших игроков до вас включительно, то можно использовать сортировку:
    SELECT u.id, u.cash 
    FROM users u 
    WHERE u.cash <= (SELECT cash FROM users WHERE id = :my_user_id)
    ORDER BY u.cash

    Очередность выборки по индексу одинаковых значений не гарантирована. Если нужна стабильност ьпорядка выборки, добавьте вторым параметром сортировки обычный уникальный идентификатор, тогда люди с одинаковым кэшем не будут от запроса к запросу меняться местами.
    Ответ написан
  • Что не так с кодом?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Не соблюдены отступы, не сбалансированы скобки.
    Ответ написан
    Комментировать
  • Sorted Object в Python. Миф или реальность?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Да, в старых версиях sorted выдавал генератор, у которого можно было запрашивать элементы по одному через next. Что нужно знать - это то, что в современном питоне сортировка возвращает материализованный список.
    Ответ написан
  • Что предпочтительнее в python - проверять значение в словаре или обработать исключение исключение?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Вы можете сами произвести замеры, но ставлю на то, что быстрее окажется проверка по словарю, поскольку она делается за ~O(1) благодаря хешированию.
    Однако я бы предложил чуть более эффективню схему:
    D = dict()
    NOTFOUND = object()
    
    def f1(x):
        result = D.get(x, NOTFOUND)
        if result is NOTFOUND:
            result = D[x] = long_calculation()
        return result


    Не поленитесь (как я), сделайте замеры. Всем тут будет интересно.
    А ещё в питоне как-то не принято экономить на спичках в ущерб чтаемости и прозрачности кода.
    Но если всё как следует "посахарить"... Лучше всего такое кэширование смотрится в виде декоратора.

    UPD:
    Забавно. Я ошибся и с исключением действительно выходит быстрее. На это указал уже автор вопроса, а я на всякий случай пересчитал, причем по отдельности для прогрева, для повторного взятия и для неполучения из прогретого хеша.

    import time
    from math import tan, atan
    import timeit
    
    
    NOTFOUND = object()
    
    
    def long_calculation(x):
        return atan(tan(x) / 2)
    
    
    def f1(x):
        if x not in D:
            D[x] = long_calculation(x)
        return D[x]
    
    
    def f2(x):
        try:
            return D[x]
        except:
            D[x] = long_calculation(x)
        return D[x]
    
    
    def f3(x):
        result = D.get(x, NOTFOUND)
        if result is NOTFOUND:
            result = D[x] = long_calculation(x)
        return result
    
    
    FUNCS = (
        (f1, 'get triple'),
        (f2, 'except'),
        (f3, 'get once'),
    )
    
    
    def work(f, gap=0.1, count=1000):
        for x in range(0, count):
            f(x + gap)
    
    
    D = {}
    number = 10000
    
    for func, descr in FUNCS:
        print(f'{func.__name__} ({descr}):')
        print(f'  Cache empty:', timeit.timeit(f"work({func.__name__})", setup=f'D=dict()', globals=globals(), number=number))
        print(f'  Total reuse:', timeit.timeit(f"work({func.__name__})", setup=f'D=dict(); work({func.__name__})', globals=globals(), number=number))
        print(f'  Total miss :', timeit.timeit(f"work({func.__name__})", setup=f'D=dict(); work({func.__name__}, gap=0.2)', globals=globals(), number=number))

    И вот результат:
    f1 (get triple):
      Cache empty: 2.8940897800493985
      Total reuse: 1.7486431139986962
      Total miss : 1.6964515489526093
    f2 (except):
      Cache empty: 1.2670072519686073
      Total reuse: 1.2622331579914317
      Total miss : 1.2547212480567396
    f3 (get once):
      Cache empty: 1.6983374420087785
      Total reuse: 1.6465996010228992
      Total miss : 1.6999219709541649
    Ответ написан
    2 комментария
  • Как нормально установить python?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    При установке питона обычным инсталлятором там должна быть галочка, которая заставит инсталлятор прописать пути к питону в path. Давно не имел дело с виндой, так что не ручаюсь.
    Однако, даже если без этой галочки, вы можете найти установленны йитон в файловой системе (посмотреть куда ведут ярлыки, например) и прописать в настройках путь, указав его в path.
    Ответ написан
    Комментировать
  • Как подключить python скрипт в автозапуск ubuntu 20.04?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Например прописать в crontab через директиву `@reboot`. Только пути надо даже для бинарников абсолютные указать.
    Ответ написан
    Комментировать
  • Почему configparser иногда не может правильно обработать русские символы в названии секции?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Ух каша у вас какая-то тут из гипотез, суеверий, заблуждений и кусков кода, которые, как вам кажется, полностью обрисовывают проблему. А проблема у вас в том, что вы неправильно работаете с кодировками.

    Общие правила работы с кодировками в питоне я уже много раз рассказывал на этом ресурсе.
    На входе в программу мы всё переводим в юникод, а на выходе всё кодируем в байты.
    Для ясности: юникод - это не кодировка, это абстрактный способ однозначной нумерации символов. Кодировка - это способ представить символ (а символ имеет свой однозначный код в таблице Юникода) в виде набора байт.
    Итак, текст в юникоде - - это, образно говоря, последовтаельность номеров символов из таблицы юникода.
    Текст в любой кодировке - это последовательность байтов.
    Важно отметить, что так или инае номера юникода тоже внутри компа хранятся как байты, а питон с ними работает не как с массивом чисел, а как с объектом "строка", значит внутри он всё же хранит юникод в какой-то специальной кодировке, но тут есть важная деталь.

    Есть кодировки, способные представить ВСЕ возможные символы Юникода, а есть кодировки, которые могут представить только некоторое подмножество этих символов. К первым относятся UTF-8, UTF-16, UTF-32 - они по-разному представляют номер символа таблицы Юникод в виде байтов, но способны представить любой символ.
    Ко вторым, к примеру, однобайтовые кодировки cp1862, cp866, koi8 прочие. Такие кодировки - пережиток прошлого, когда в угоду простоте люди жертвовали универсальностью. Однако со временем, когда требоания к ПО и набору поддерживаемых символов изменилось, появилась необходимость как-то между этими кодировками переключаться, преобразовывать тексты, учитывать, что какойто текст без потери данных вовсе нельзя перевести из одной в другую кодировку, потому что каких то букв просто нет в целевой кодировке. Так простота накопилась техническим долгом и обернулась многократно возросшей сложностью учета всех этих нюансов.

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

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

    У вас, очевидно, self.task_name хранится в закодированном виде или некорректно преоразовывается.

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

    Прологируйте значение вашего repr(self.task_name) перед взятием по ключу когда происходит ошибка и когда не происходит.
    Вы увидите что меняется.
    Ответ написан
  • Как преобразовать аудио в массив в python?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Мало данных. Если ваш аудиофайл в WAV формате, то это уже фактически массив данных, который вам нужен. Достаточно отрезать от него "шапку", посмотреть в шапке битрейт и число каналов и соответственно интерпретировать как массив сэмплов нужной битности.
    Если файл закодирован кодеком (mp3, ogg, и т.д.), то сперва надо декодировать файл, а потом уже смотри, как говорится, первый пункт.
    Как именно это будет выгядеть в коде зависит от того, какой формат, какие библиотеки для работы с массивами анных используете. Конкретизируйте, пожалуйста.

    Ищется, кстати, элементарно:
    https://stackoverflow.com/questions/3049572/how-to...
    https://pythonbasics.org/convert-mp3-to-wav/
    https://www.geeksforgeeks.org/convert-mp3-to-wav-u...

    UPD:
    https://google.gik-team.com/?q=wav+python

    В итоге имеем:
    https://habr.com/ru/post/113239/
    https://docs.python.org/3/library/wave.html
    https://coderoad.ru/2060628/Чтение-wav-файлов-в-Python

    Это три перые ссылки в гугле. Если вы это найти не смогли, то прочь из профессии.
    Ответ написан
    2 комментария
  • Можно ли отправлять все ошибки из компилятора в какой то канал?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Нужно делать это отдельным ботом, а лучше даже не ботом, а просто курлом дёргать API и засылать туда сообщения логов.
    Из самого бота это лучше не делать, особенно если речь о неожиданных ошибках.
    Ожидаемые (штатные) ошибки вполне можно слать из того же инстанса, где бот крутится.
    Итак, подключаете стандартный logging, настраиваете отдельный хендлер, фильтрующий нужный уровень сообщений, настраиваете форматтер. чтобы полноценный отчет об ошибке сформатировать.
    Можно поискать готовую либу такого хендлера, наверняка есть в pipy, а можно и самостоятельно заморочиться.

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

    UPD/
    Как я и говорил, полно готовых хендлеров:
    https://pypi.org/project/python-telegram-handler/
    https://pypi.org/project/python-telegram-logger/
    https://pypi.org/project/logging2telegram/
    https://pypi.org/project/tglogger/
    Ответ написан
    Комментировать
  • Не могу понять для чего нужна эта строка в коде?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Таким неэлегантным способом автор получает номер очередной бутылки, чтобы отреагировать особым обраом на предпоследнюю бутылку, то есть сказать, что после нее осталась одна бутылка (именно в единственном числе).
    Ответ написан
    1 комментарий
  • Как сделать проверку действий в минуту?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Для этого используют структуру данных очередь (FIFO - First In First Out).
    Туда будут добавляться таймштампы сообщений, а очередь должна хранить "минутное окно" этих таймштампов.
    То есть последнее сообщение (в хвосте очереди) - это самое старое сообщение, а первое (в голове) - самое новое. Ко времени последнего сообщения на текущий момент прибавляем минуту и получаем время, когда нужно вытащить из очереди хвостовой элемент. Текущая длина очереди - это и есть количество сообщений за текущую минуту.
    Это если вам надо без выравнивания.
    Если нужно знать сколько сообщений было каждую минуту дискретно, то да, накапливаете счётчик и обнуляете его каждую целую минуту. Всё зависит от задачи.
    Ответ написан
    Комментировать