Задать вопрос
Ответы пользователя по тегу Python
  • ООП сработало не правильно?

    Vindicar
    @Vindicar
    RTFM!
    Ты в питон из какого языка пришёл? =)
    class Test:
      a: list = []

    Ты объявил атрибут класса, а не экземпляра класса.
    Так как у экземпляра класса нет атрибута a, питон ищет этот атрибут в самом классе - и находит.
    У тебя в примере и Test.a тоже даст [3].

    Атрибут экземпляра класса в питоне объявляется вот так:
    class Test:
        def __init__(self):  # конструктор
            self.a: list = []

    Тут у каждого экземпляра будет своя копия списка.
    Ответ написан
    9 комментариев
  • Как мне отфильтровать csv файл по датам?

    Vindicar
    @Vindicar
    RTFM!
    Xion, ну дай угадаю, перебирал с начала списка?
    Пусть у нас есть список букв:a b b a b a a ....
    Мы хотим убрать из него буквы b, и перебираем его с начала.
    Текущая буква A: A b b a b a a ....
    Ничего не делаем.
    Переходим к следующей.
    Текущая буква B: a B b a b a a ....
    Удаляем, следующие элементы смещаются на позицию: a B a b a a ....
    Переходим к следующей: a b A b a a ....
    Как видишь, следующую букву b мы из-за этого пропустили.

    Отсюда настоятельная рекомендация: избегай модифицировать коллекцию в процессе перебора! Лучше (реально лучше в случае с файлами) - генерируй по ходу перебора новую коллекцию, куда попадают только "хорошие" элементы. Вместо того, чтобы пытаться удалять "плохие" из уже существующей.

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

    Vindicar
    @Vindicar
    RTFM!
    Клавиатура обычно прикреплена к сообщению. Для её смены проще всего отправить поясняющее сообщение с новой клавиатурой.
    Ответ написан
    Комментировать
  • Как проверить количество цифер после точки во float в Python?

    Vindicar
    @Vindicar
    RTFM!
    Число цифр - штука коварная. Вот беру я Питон и вбиваю:
    >>> 0.1 + 0.2
    0.30000000000000004

    Сколько цифр должен вывести код?
    Ответ написан
    Комментировать
  • Насколько такой метод проверки является корректным и как его можно сократить?

    Vindicar
    @Vindicar
    RTFM!
    1. Не надо проверять в рантайме type(m) == int. Достаточно указать в заголовке функции
    def add_time(self, h: int = 0, m: int = 0, d: int = 0, dw: int = 0, mh: int = 0, y: int = 0):

    Этого будет достаточно, чтобы IDE/статический анализатор сказал программисту "эй, ты фигню передаёшь в этот метод". Да, это не будет контролироваться во время выполнения, но тут уже другой вопрос: если клиент-программист сделал класс, неотличимый от int, стоит ему позволить этот класс передать вместо int. Ответственность будет на нём.

    2. Ну для конкретно твоей проверки по значению можно просто:
    if any(v < 0 for v in [h,m,d,dw,mh,y]):
        raise ValueError()

    Если хочешь красиво, можно и выпендриться:
    args = {'h':h, 'm':m, 'd':d, 'dw':dw, 'mh':mh, 'y':y}
    bad = list(filter(lambda k: args[k] < 0, args.keys()))
    if bad:
        raise ValueError('Invalid values for: ' + ','.join(bad))


    Ну а при большом желании можно и целый велосипед для декларативной проверки параметров замутить.
    Но смысл?
    import functools
    import inspect
    
    # пусть чек-функция имеет вид (value) -> bool, и возвращает True для "хороших" значений. Пример:
    def not_whitespace(s: str) -> bool:
        'String must not contain only whitespace'  # док строка будет использоваться в сообщении об ошибке
        return bool(s.strip())  # проверяем что строка не состоит из одних пробелов.
    # чек-функции можно генерировать и на ходу:
    def in_range(low, high):
        def check(value):
            return (low is None or low <= value) and (high is None or value <= high)
        check.__doc__ = f'Value must be between {low} and {high}.'
        return check
    # теперь сделаем декоратор, который умеет принимать чек-функции и применять их перед вызовом цели
    def check(**checks):
        def wrapper(func):
            sign = inspect.signature(func)
            names = list(sign.parameters.keys())  # имена параметров по порядку
            not_found = set(checks.keys()) - set(names)  # все ли чеки ссылаются на известные параметры?
            if not_found:
                # у нас есть чек на неизвестный параметр!
                raise NameError(', '.join(not_found))
            # всё ок, делаем обёртку над функцией
            
            @functools.wraps(func)
            def wrapped(*args, **kwargs):
                bad = []
                for param_name, check_func in checks.items():
                    idx = names.index(param_name)
                    if idx < len(args):
                        # параметр был передан через args
                        value = args[idx]
                        if not check_func(value):  # вызываем чек-функцию
                            err = getattr(check_func, '__doc__', '')
                            if err:
                                bad.append(f'{param_name} ({err})')
                            else:
                                bad.append(param_name)
                    else:
                        pass  # могут быть хитрости с kwargs-only параметрами. Тут уж извини, мне влом писать.
                if bad:  # нашли ошибки?
                    raise ValueError('Bad value for parameters: '+', '.join(bad))
                    # тут ещё можно помудрить над скрытием последнего фрейма в traceback, но мне опять влом
                else:  # не нашли, вызываем функцию
                    return func(*args, **kwargs)
            
            return wrapped
        return wrapper
    
    # пример использования
    # строка должна быть не из одних пробелов
    # число должно быть в пределах от 1 до 10 включительно
    @check(s=not_whitespace, n=in_range(1, 10))
    def repeat(s: str, n: int) -> str:
        return s * n
    
    print(repeat('test ', 3))
    
    try:
        print(repeat('test ', 20))
    except ValueError as err:
        print('yep! it failed!', err)
    
    try:
        print(repeat('test ', -1))
    except ValueError as err:
        print('yep! it failed!', err)
    
    try:
        print(repeat('    ', 5))
    except ValueError as err:
        print('yep! it failed!', err)
    
    try:
        print(repeat('    ', 15))
    except ValueError as err:
        print('yep! it failed!', err)
    Ответ написан
    3 комментария
  • Как получить все 3 канала изображения?

    Vindicar
    @Vindicar
    RTFM!
    По умолчанию каналы изображения в opencv идут в порядке blue, green, red.
    Так что 0 - это blue, ну и так далее.
    Ответ написан
  • Бот перестаёт отвечать после возврата в главное меню, как исправить?

    Vindicar
    @Vindicar
    RTFM!
    button1 = types.KeyboardButton(" Поздороваться")
    button2 = types.KeyboardButton("❓ Задать вопрос")

    Сравни это с реализацией команды /start. У тебя тут посторонние пробелы, а сравнение строк требует ТОЧНОГО совпадения. В твоём коде - вплоть до регистра букв.
    Ответ написан
    Комментировать
  • Как понять работу следующего кода по перегрузке операторов?

    Vindicar
    @Vindicar
    RTFM!
    Потому что питон пытается "извернуться", если описаны не все операторы.
    Если выполняется a < b, но не описан оператор a.__lt__(), питон попробует вызвать b.__gt__().
    Аналогично, если не описан __ne__() а только __eq__(), и выполняется a != b, питон сделает not (a == b)
    Кое что есть тут
    Также советую глянуть в сторону functools.total_ordering.
    Ответ написан
    3 комментария
  • Для чего нужна черепашья графика?

    Vindicar
    @Vindicar
    RTFM!
    Для обучения основам составления алгоритмов сойдёт. Больше, считай, ни для чего.
    Ответ написан
    Комментировать
  • Как сделать что б while работал пока может?

    Vindicar
    @Vindicar
    RTFM!
    Выяснить, почему он зацикливается, и исправить.
    Обходные варианты существуют, но они привносят куда больше проблем, чем решают.
    Ответ написан
    Комментировать
  • Почему не происходит отправка сообщений ботом в установленное время?

    Vindicar
    @Vindicar
    RTFM!
    if current_time == '12:00':
    У тебя значение current_time определяется один раз, ДО цикла. Ты ожидаешь, что оно волшебным образом будет следовать за текущим временем?
    Ответ написан
    Комментировать
  • Почему проходят первые тесты, но не проходят вторые на Codewars?

    Vindicar
    @Vindicar
    RTFM!
    Тормозит, потому что ты брутфорсишь перебор простых чисел. Используй решето Эратосфена.
    Иными словами, тебе не нужно перебирать все числа меньшие N, чтобы найти делители - достаточно проверить все простые числа, меньшие или равные N/2. А так как ты находишь простые числа по возрастанию, то все эти числа ты уже знаешь.
    До кучи, 2 всегда простое, а вот другие чётные числа - нет. Можешь добавить 2 в список заранее, а цикл по i делать от 3 с шагом 2.

    Ну и да, не называй переменную list. Это сбивает с толку.
    Ответ написан
    Комментировать
  • Как из текстового файла достать строки в определённом диапазоне?

    Vindicar
    @Vindicar
    RTFM!
    Пропустить нужное число строк, прочитать нужное число строк.
    def read_lines_in_range(f, ifrom: int, ito: int) -> list[str]:
        f.seek(0)
        for i in range(ifrom):
            f.readline()
        return [f.readline() for i in range(ito-ifrom)]

    Единственное, позиция чтения в файле должна быть в начале файла. Так что файл надо либо закрыть и открыть, либо сделать f.seek(0).
    Ответ написан
    Комментировать
  • Как найти ближайшее меньшее к моему числу из заданных чисел?

    Vindicar
    @Vindicar
    RTFM!
    Так как у тебя степени двойки, то можно рассчитать математически.
    import math 
    z = float(input('Z = '))  # например, 10
    logz = math.log(z, 2)  # 10 находится между 2**3 и 2**4, так что logz будет 3 с копейками (но меньше 4)
    pwr = int(logz)  # отбрасываем дробную часть, получаем 3
    value = 2 ** pwr  # ближайшее меньшее значение - 2 ** 3

    Но для произвольных чисел это не сработает.
    Ответ написан
    Комментировать
  • Как сделать так, чтобы бот отвечал на команду start?

    Vindicar
    @Vindicar
    RTFM!
    Что за @bot.send_message? Здесь декоратору не место, тут нужен просто вызов функции.
    Ответ написан
    7 комментариев
  • Как распарсить строку (python)?

    Vindicar
    @Vindicar
    RTFM!
    shlex.split(), например?
    Ответ написан
    Комментировать
  • Как скачать музыку с Vk с помощю Python?

    Vindicar
    @Vindicar
    RTFM!
    youtube-dl?
    Оно не только YouTube умеет, а ещё много какие сайты. Есть командная строка, вроде был и питоновский интерфейс. Хотя можно тупо через subprocess запустить.
    Ответ написан
    Комментировать
  • Как записать файл в папке?

    Vindicar
    @Vindicar
    RTFM!
    Ну тебе тут и насоветовали... Читай что такое относительный и абсолютный пути.
    C:\папка\user_file - это абсолютный путь.
    \папка\user_file - это относительный путь от корня текущего диска.
    папка\user_file - это относительный путь от текущей директории.
    Текущая директория (равно как и диск) может быть разной при запуске скрипта, может быть изменена в ходе работы скрипта, и не обязательно совпадает с директорией скрипта.
    Если тебя это устраивает, например, если ты пишешь программу для командной строки, которая принимает путь как параметр - то можешь использовать относительный путь.
    Если же ты хочешь обратиться к какому-то файлу с данными в каталоге скрипта - лучше сконструировать абсолютный путь. Не указать его явно (тогда придётся менять при перемещении скрипта в другую папку), а сконструировать. Например, так:
    import pathlib  # стандартный модуль питона. Очень советую его освоить!
    import sys
    # путь к папке скрипта, например, C:\myscript
    script_dir = pathlib.Path(sys.argv[0]).parent  
    # путь к файлу собирается из частей вот так
    user_file = script_dir / "some_folder" / "user_file"  # C:\myscript\some_folder\user_file
    # обрати внимание, мы не паримся по поводу того, что 
    # под виндой разделитель каталогов \, а под линуксом /
    # это уже забота pathlib
    with user_file.open('w+') as f:
        pass  # делаешь что тебе нужно с файлом
    # через функцию open() тоже сработает, метод open() просто для удобства
    with open(user_file, 'w+') as f:
        pass  # делаешь что тебе нужно с файлом

    Так ты гарантируешь, что будешь обращаться к файлу в каталоге скрипта, независимо от расположения скрипта и от текущей рабочей директории.
    Ответ написан
  • Как распарсить GotoIfTime из астериска?

    Vindicar
    @Vindicar
    RTFM!
    Регулярное выражение вида
    GotoIfTime\((?P<from>\d+:\d+)-(?P<to>\d+:\d+),(?P<days>[a-z-]+),\*,\*\?open,s,1\)
    извлечёт из строки нужные части. Их можно будет вытащить так:
    regexp = re.compile(r'GotoIfTime\((?P<from>\d+:\d+)-(?P<to>\d+:\d+),(?P<days>[a-z-]+),\*,\*\?open,s,1\)', re.I)
    m = regexp.match('GotoIfTime(09:00-17:59,mon-fri,*,*?open,s,1)')
    if m:
        print(m.group('days'), m.group('from'), m.group('to'))

    Для работы с датами datetime ну и просто работа со строками. C днём недели можно будет справиться как-то так:
    now = datetime.datetime.now()
    weekday = now.weekday()
    days = m.group('days').lower()
    days_of_week = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']  # datetime.datetime.weekday()
    if '-' in days:  # диапазон
        dfrom, _, dto = days.partition('-')
        dfrom, dto = days_of_week.index(dfrom), days_of_week.index(dto)
        if dfrom <= dto:  # обычный кейс, вроде mon-fri
            day_is_good = dfrom <= weekday <= dto
        else:  # на случае если нужно зацикливание вида fri-tue
            day_is_good = (weekday >= dfrom) or (weekday <= dto)
    else:  # один день, не диапазон
        dow = days_of_week.index(days)
        day_is_good = weekday == dow
    print(day_is_good)  # True или False


    С временем тоже несложно, разбиваешь через partition() по двоеточию, преобразуешь в целое, потом делаешь datetime.datetime.now().replace(hour=h, minute=m) и получаешь указанное время в текущий день.

    Таким образом у тебя будет два момента времени, один на базе from другой на базе to. Их можно просто сравнить с текущим: if from <= now <= to:
    Ответ написан
  • Как добавить кнопки в бота, через телеграм в Aiogram?

    Vindicar
    @Vindicar
    RTFM!
    Гипотетически можно, но практически тяжело. Объясню почему.

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

    2. Ты можешь загрузить в бота код, реализующий новую функциональность. Для этого нужно будет:
    - разбить бота на изолированные компоненты, по типу Cogs из библиотеки discord.py.
    - предусмотреть механизм подгрузки файла с компонентом в бота "на ходу".
    - предусмотреть механизм выгрузки компонента из бота "на ходу", что намного сложнее. Это потребуется, если ты захочешь заменить компонент обновлённой версией, не перезапуская бота.
    - предусмотреть механизм, позволяющий тебе отдать боту файл с кодом, чтобы тот поместил этот файл к остальным компонентам.
    Это всё нетривиальные задачи, которые требуют очень хорошего понимания как Питона, так и устройства библиотеки aiogram. Собственно, беглый взгляд на доки показывает, что aiogram вообще не предусматривает удаления обработчиков событий. А это значит что единственный способ выгрузить функциональность из бота - это его перезапуск.
    Ответ написан
    Комментировать