Ответы пользователя по тегу Python
  • Обьясните пожалуйста работу setup.py и distutils?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Не совсем. setup.py - это скорее файл, описывающий ваш пакет, чтобы distutils знал как его устанавливать, какие у него зависимости, кто автор, какие точки входа и прочее.
    Вот на хабре отличная статья как сделать идеальный пакет: https://habr.com/ru/post/483512/
    Ответ написан
    Комментировать
  • Как вывести первый ключ из словаря?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Как вывести первый ключ из словаря?

    Как вывести только 'Pomidorka' из словаря?

    Вы спрашиваете как вывести первый ключ, а потом говорите про помидорку, а это третий ключ. Так чего именно вы хотите?

    Если речь о том, чтобы вообще получить все ключи из словаря, то воспользуйтесь учебником, по питону и там вы увидите:
    list(users.keys())  # ['Ivan', 'Anton', 'Pomidorka', 'Ananas']

    Такой порядок для вашего кода будет в питоне начиная с 3.6.

    Если нужно взять именно первый ключ, то так:
    list(users.keys())[0]

    Если речь о современном питоне (начиная с 3.6), то порядок ключей в словаре сохраняется при добавлении элементов, поэтому помидорку получать придётся запрашивая 2 (третий по счету) элемент списка ключей:
    list(users.keys())[2]

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

    Короче. Бесят эти лентяи, которые вместо чтения крошечной книжки для чайников задают тут тупые бестолковые и неконкретные вопросы, на которые, чтобы нормально ответить, нужно тратить уйму времени. ХВАТИТ ЭТО ТЕРПЕТЬ!
    Даёшь дизлайки за вопросы и за ответы!
    Ответ написан
    Комментировать
  • Как работает табуляция в python?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Описанная вами ошибка происходит из-за смешивания в отступах табов и пробелов.
    Иногда редактор не очень понятно показывает вам где у вас табуляция, а где группа пробелов. Этим грешит, например, mcedit.
    рецепт прост: никогда не пользуйтесь табами в питоне. Вопрос, конечно, холиварный, но если у вас с табами проблемы, то вам они точно нигде не нужны. Это значит, что вы не можете адекватно настроить редактор и увидеть где табы и где пробелы.
    Для вас будет правильным объяснить редактору, что для питоновских файлов следует всегда заменять таб на 4 пробела.

    В питоне табуляция работает также как и везде. Просто операторные скобки в этом языке определяются отступами. Лично мне это решение очень нравится, хотя и порождает ряд неприятных проблем. Кстати запрет на смешивание отступов - это не проблема. Их смешивать - это плохой тон во всех языках, в том числе и yaml и где угодно.
    В питоне с такими операторными скобками проблемы с ограниченностью лямбда-функций, а ещё затруднительно писать однострочники для `py`.
    Ответ написан
  • Почему не работает сортировка списка в Python?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    5e3948e66cddf596697310.png
    Есть похожие или даже одинаковые по начертанию, но совершенно разные по коду и порядку символы в юникоде.
    Это часто вызывает проблемы.
    Если вы точно знаете, что в ваших именах должны быть только русские буквы, то можете обработать строки заменяя похожие по начертанию символы. В таком виде, конечно, решение не пригодно в случае, если у вас попадётся имя полностью на английском.
    Можно также проверять наличие непохожих по начертанию символов в имени, и если таковые есть, значит замены сделаны не по ошибке. Можно сделать автоматическую обратную подстановку, если в имени нет непохожих на английские русских букв.
    В любом из этих случаев могут возникнуть ситуации некорректного трактования имени. К примеру к вам пришел "АВРААМ" и утверждает, что его родители большие затейники, русского не знают, к евреям отношения не имеют, а дома его называют "Абпаамом".
    users = ["Андрей", "София", "Cветлана", "Валерий", "Илья", "Mаксим", "Дмитрий", "Лиза"]
    trans_table = str.maketrans(
        'ABCEHKMOPTXacekmopuxy', 
        'АВСЕНКМОРТХасекмориху',
    )
    russian_letters_normalizer = lambda s: s.translate(trans_table) if isinstance(s, str) else s
    print('Original:', users)
    print('Sorted:  ', list(sorted(users, key=russian_letters_normalizer)))
    Ответ написан
    Комментировать
  • Как правильно реализовать ООП python?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    import telebot
    import requests
    import pprint
    import time
    
    botToken = "token"
    chanelName = "@wo"
    
    class Bot:
      def __init__(self,nameChanel,token):
        # todo: проверьте pep8: форматирование (пробелы, indent=4), нейминг (CamelCase vs snake_case)
        self.name = nameChanel
        self.bot = telebot.TeleBot(token)
        # todo: Неадекватное имя bot. Вызывает путаницу в связи с именем класса Bot
        #self.source = source
    
      def getIDGroup(self,str):
        # todo: str - это встроенный тип, по смыслу должно быть ясно, что можно итерировать
        arr = []
        # todo: Неадекватное имя arr. Имя должно указывать не на тип, а на суть того, что поименовано.
        for nameGroup in str:
          url = f"url"  # todo: Зачем тут форматная строка, если нет переменных? Видимо ошибка.
          response = requests.get(url).json()['response']['object_id']
          # todo: Где проверка ответа на ошибки?
          # todo: Неадекватное имя. Назовите object_id
          arr.extend(self._getPostsGroup(response))
        return self._editPosts(arr)
    
      def _getPostsGroup(self,number):
        # todo: Неадекватное имя number. Назовите group_id 
        number = str(number)
        url = f"url"
        response = requests.get(url).json()['response']['items']
        # todo: Неадекватное имя. Назовите object_id
        return response
    
      def _editPosts(self,posts):
        with open('id.txt','r') as file:
          list = file.read().split()
          # todo: имя переменной перекрывает встроенный тип, не отражает содержимое
          # todo: Зачем read и split, если можно list(file) и идентификаторы хранить в строках?
          file.close()
          # todo: Зачем close, если with?!
        
        for item in posts:
          count = list.count(str(item['id']))
          # todo: Зачем вам тут count, если нужна лишь проверка на вхождение?
          if count:
            continue
          photo = ""
          # todo: почему не None?
          for img in item['attachments'][0]['photo']['sizes']:
            if img['height'] > 300:
              photo = img['url']
              break
          text = item['text']
    
          self._sendMessageBot(text,photo)
          with open('id.txt','a') as file:
            # todo: ну использовали бы уже хотя бы shelve
            file.write(str(item['id'])+' ')
            file.close()
            # todo: опять close
    
    
      def _sendMessageBot(self,text,photo):
        if photo:
          if text:
            self.bot.send_photo(self.name,photo,caption=text)
            return
          else:
            self.bot.send_photo(self.name,photo)
        if text:
          self.bot.send_message(self.name,text)
    
        # Функция могла выглядеть так:
        # if photo:
        #   self.bot.send_photo(self.name, photo, caption=text)
        # elif text:
        #   self.bot.send_message(self.name, text)
        # Но лучше не допускать вызова с пустыми аргументами. Это бессмысленно и плохо
    
    bot = Bot(chanelName, botToken)
    # вот как понимать такое: bot.bot? Нейминг!!!
    posts = bot.getIDGroup() #name of group

    Зачем каждый раз читать и писать файл, когда у вас бот в памяти остаётся?
    По меньшей мере вы можете хотя бы не читать каждый раз, сохраняя идентификаторы в множестве памяти (кэш), а загружать это множество из файла только при старте бота. Писать можно и так. Но у вас функции не соответствуют принципу single responsibility (почитайте SOLID)

    Всё плохо. Прежде чем думать об ООП почитайте хотя бы туториал по питону или любую книжку Питон для чайников.
    Хороший тон давать код на ревью в гитхабе. Там можно удобно, с подсветкой синтаксиса и нумерацией строк прокомментировать весь ваш ... код, а вы сможете его потом итеративно улучшать и мне не придётся заново убеждаться, что вы учли все замеченные проблемы при повторном ревью.
    Вот бесит прям. Пожалуй не буду больше ревьюить первые потуги настолько самоуверенных программистов. Просто не вежливо дёргать сообщество не почитав даже основы.
    Ответ написан
    3 комментария
  • Как при помощи bat-файла запустить программу python и ввести данные в нее?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Конечно возможно. У меня сейчас винды под рукой нет, но выглядеть будет примерно так.
    Программа, назовём её my_python_script.py:
    x = input()
    print('Text from input:', x)

    Батник:
    echo the string for python | python my_python_script.py

    Если инпутов несколько, то передать нужно несколько строчек.
    Чтобы сделать это с помощью echo, нужно написать строку с абзацем внутри. Я понятия не имею как экранируется абзац в bat-файлах, поэтому могу предложить такой вариант.
    my_python_script.py:
    x = input()
    y = input()
    z = input()
    rest = []
    while z != 'END':
        rest.append(z)
        z = input()
    
    print('x=', x, 'y=', y)
    print('rest=', rest)


    my_script.bat:
    echo The X string
    echo The Y string
    echo Other string 1
    echo line 2
    echo line 3
    echo line 4
    echo END

    Вызываем так:
    my_script.bat | python.exe my_python_script.py
    Весь выхлоп из батника попадёт на вход питоновского скрипта.
    Можно сделать еще один батник, который сделает такой вызов. Можно описать подпрограмму внутри батника, которая будет печатать строчки и в том же батнике её вызвать пайпом с передачей питону.

    Пайп - это такой виртуальный файл в операционной системе, который можно либо читать, либо писать. либо и то и другое. Зависит от того как сделан пайп. Для каждой программы система при запуске создаёт три пайпа: stdin, stdout, stderr.
    С помощью `|` в командной строке между командами можно сделать конвейер, когда выхлоп левой команды в stdout направляется на вход правой команды в stdin. Таким паровозом можно сколько угодно команд соединить.
    С помощью `>` можно перенаправить stdout в локальный файл с заданным именем:
    echo text to write into the file > the_file.txt
    С помощью `<` можно в stdin передать содержимое файла.
    Там много всяких хитростей с этими перенаправлениями, но лучше почитайте профильную статью или документацию.
    Питон читает с помощью input() из stdin и по умолчанию пишет с помощью print в stdout. echo в bat-файле тоже пишет в stdout.
    В линуксе (и в винде, если поставить поддержку шелла) есть куча других полезных команд и утилит для работы в командной строке (cat, tee, ...)
    Ответ написан
    7 комментариев
  • Python выдаёт ошибку: SyntaxError: invalid syntax что делать?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    if a / b ** > 25.00:
    Вы двойку забыли поставить после звёздочек. Возведение в степень - это бинарная операция, у неё аргументы должны быть слева и справа.
    Ответ написан
    Комментировать
  • Как устронить ошибку при запуске программы? Вот ошибка 'rar' is not recognized as an internal or external command, operable program or batch file?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Проблема в том, что питон пытается запускать rar (архиватор такой).
    Такая ошибка возникает, если ОС не может найти запускаемую программу.
    У вас есть два варианта:
    1. указать каталог, где лежит rar.exe в переменной среды окружения PATH

    Windows 10 и Windows 8
    В строке "Поиск" выполните поиск: Система (Панель управления)
    Нажмите на ссылку Дополнительные параметры системы.
    Нажмите Переменные среды. В разделе Переменные среды выберите переменную среды PATH. Нажмите Изменить. Если переменной PATH не существует, нажмите Создать.
    В окне Изменение системной переменной (или Новая системная переменная) укажите значение переменной среды PATH. Нажмите ОК. Закройте остальные открытые окна, нажимая ОК.

    2. В вашей программе указать полный путь к исполняемому файлу.

    Что-то вроде c:/program files/rar/rar.exe
    или где там он у вас лежит.
    Вот так:
    rar_command = '"c:/program files/rar/rar.exe" a -ag {}.rar {}'.format(target_dir,source)

    Ответ написан
    Комментировать
  • Насколько подходит предложенный мной вариант защиты python кода?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Тоже попробую пояснить.
    При разработке защиты ПО всегда нужно сопоставлять цену взлома и профит от взлома.
    Арифметика примерно такая.
    Если цена взлома в k раз меньше суммарного профита от взлома (с учетом масштабирования) и сильно не превышает цену повторного написания приложения, то продукт будет взломан и это вопрос времени.
    Это пуассоновский процесс и чем больше k тем быстрее произойдёт вероятный взлом.

    Разработчик защищая продукт огребает существенный геморрой с поддержкой, отладкой, диагностикой, обновлением и расширением ПО.
    Цена этого геморроя может оказаться не сильно ниже ущерба от взлома. Тогда такую защиту применять не стоит. Особенно если ваш продукт развивается и растёт, в нём регулярно появляются новые фичи и каждый раз ломать дорого (даже с учетом, что повторный взлом дешевле первого).

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

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

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

    В итоге. У вас с вашим списком мер есть шанс построить бастион вокруг сортира. Если сортир с золотыми унитазами, то их всё равно сопрут, а если нет, то нафиг столько геморроя?

    Если у вас в коде есть алгоритмические участки, которые можно изолировать и трудено повторить или эмулировать (это должны быть нужные функциональные участки реально постоянно работающего кода), то их можно вынести в крипто-ключ в виде USB-донгла. Это тоже немалый гемор, но порой вполне применимый.

    Я не знаю что у вас за продукт, стало бы понятнее при наличии подробностей, но в общем случае хорошо работают и достаточно эффективны (если речь не идёт о "ломе") следующие меры в порядке убывания удобства:
    1. вынос функциональности на сервер в виде API
    2. байткод без исходников
    3. обфускация (лёгкая)
    4. обфускация (тяжелая, с поддержкой полиморфности кода)

    Всякие упаковки в экзешники и шифрование - это уже так... от лукавого.
    Просто вынесите ключевой ресурс на сервер и всё.
    Ответ написан
    Комментировать
  • Как поменять данные в JSON из Python?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Да, JSON нецелесообразно менять прямо на диске. Его нужно загрузить, распарсить, заменить значение, потом снова сериализовать данные в JSON и сохранить на диск.
    import json
    with open('myfile.json') as f:
        data = json.load(f)
    data['example1'] = 'bye'
    with open('myfile.json', 'w') as f:
        json.dump(data, f, ensure_ascii=False, indent=4)
    Ответ написан
    8 комментариев
  • Как опубликовать модуль на pypi?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Ответ написан
    Комментировать
  • Как работает перевод в другую систему исчисления Python?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Если на входе строка, то перевод в целое значение (в двоичный вид) осуществляется стандартной функцией int, у которой есть необязательный аргумент, указывающий на систему счисления.

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

    В n-ричной системе счисления каждая очередная цифра числа - это очередной остаток от деления числа на базу.
    Ответ написан
    Комментировать
  • Как с помощью API работать с Яндекс картами?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Для 37.677751,55.757718:

    https://static-maps.yandex.ru/1.x/?ll=37.677751,55.757718&size=200,200&spn=0.016457,0.00619&l=map

    https://static-maps.yandex.ru/1.x/?ll=37.677751,55...
    Ответ написан
    Комментировать
  • Как записывать в фаил чтобы можно было редактировать вручную?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    json.dumps(my_data, ensure_ascii=False)
    Там выше правильно ответили ссылкой на документацию.
    Аргумент ensure_ascii требует экранировать не ASCII символы при сериализации. Если его поставить в False, то будет то, что вам нужно.
    Ответ написан
    Комментировать
  • Как не прерывать python при ошибках, которые не критичны для приложения?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Есть ещё удобный контекстный менеджер для подавления исключений в случаях, когда не требуется какой бы то ни было обработки.
    from requests.exceptions import ConnectTimeout
    from contextlib import suppress
    
    with suppress(ConnectTimeout):
        # code
    Ответ написан
    Комментировать
  • Как исправить ошибку 'ascii' codec can't decode byte 0xd0 in position 0: ordinal not in range(128)?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    yourorder = yourorder.decode('utf-8')  # или 'cp1251' или 'cp866' или что та у вас
    district = district.decode('utf-8')
    bot.edit_message_text(
        chat_id=c.message.chat.id,
        message_id=c.message.message_id,
        text= u'{}Страна: {}\n\nВыбери товар'.format(yourorder, district), 
        reply_markup=key,
    )

    Ещё вы смешиваете конкатенацией юникод-строки и неюникод ('\n\n'). Не надо так.
    Ответ написан
    Комментировать
  • Как получить русский текст из json на Python?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Не надо там ничего энкодить и декодить.
    В ответе текст в юникоде и парсится функцией `json.loads` адекватно.
    Проблема скорее всего у вас из-за кодировки в консоли винды. там какая-нибудь однобайтовая кодировка вроде cp1251 или cp866.
    При попытке напечатать юникод в этом терминале вы получаете ошибку из-за того, что при автоматическом преобразовании из юникода в кодировку консоли питон пытается взять кодек по умолчанию, который, конечно 'ascii'.

    Винда такая винда со своим беспощадным терминалом и кодировками по умолчанию.

    Но вы можете напечатать этот текст, в нём нет непечатных символов для однобайтовой кодировки. Попробуйте так:

    x = obj['result'][-1]['status']
    try:
        print('cp1251:', x.encode('cp1251'))
    except:
        try:
            print('cp866:', x.encode('cp866'))
        except:
            print('no way')


    Общие правила работы с кодировками такие:
    - на входе в программу мы всё преобразовываем в юникод.
    - на выходе всё кодируем в нужную кодировку.
    - если выход - это печать в стандартный вывод (stdout), то ситуаций может быть 4:
    1) печатаем в терминал винды и терминал у нас в кодировке 1251
    2) печатаем в терминал и он у нас в 866 кодировке
    3) печатаем в stdout, который перенаправлен в файл и пайп не знает в какой он кодировке, то есть кодировка не задана и мы можем заэнкодить в любую и в файл это запишется. Пользутейс utf8 - самая правильная кодировка для всего.
    4) вы в линуксе и терминал у вас в кодировке по умолчанию - utf8 и всё хорошо.

    В любом случае, печатая или сохраняя что-то в файл вы должны понимать, что текст нужно закодировать в кодировку. Это может произойти неявно (как в ашем случае) но при попытке закодировать в кодировку по умолчанию (ascii) не каждый символ в ней можно представить. В ASCII всего 127 символов. Получилась закономерная ошибка.

    У потоков стандартного ввода/вывода есть атрибут encoding:
    import sys
    sys.stdout.encoding  # 'UTF-8'

    В вашем случае будет либо None, если вывод перенаправлен в файл,
    либо 'cp1251', либо 'cp866' ну или ещё что-нибудь эдакое.
    Если не None, то в эту кодировку можно постараться заэнкодить вашу строку. По-прежнему некоторые символы могут не конвертнуться (не в вашем случае), их можно игнорировать специальным аргументом метода encode.
    Ответ написан
    1 комментарий
  • Как корректно извлечь данные из CSV-датасета?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    import csv
    with open('dataset.csv') as f:
        reader = csv.reader(f)
        for row in reader:
            print(row)

    Можно воспользоваться csv.DictReader, если полей очень много и с ними удобнее работать как со словарями по имени.

    Могут быть нюансы:
    - проблемы с кодировкой файла (решается указанием кодировки при открытии);
    - необычные разделители (решается указанием или настройкой диалекта);
    - данные изображений, скорее всего, не лежат прямо в csv (хотя могли бы=), там скорее всего имена файлов. Не думаю что корректно загружать весь датасет для обучения целиком. Лучше это делать в потоке по одному элементу и забывать использованные сразу не оставляя в памяти.

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

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    Вы не оттуда импортируете `QTableWidgetItem`. Уберите его из импорта и там, где он опоминается напишите `QtGui.QTableWidgetItem`.
    Внутри осуществляется проверка на конкретный класс, а этот класс у вас существует дважды в разных модулях. Об этом чётко сказано в сообщении об ошибке.
    Ответ написан
  • Какой алгоритм выборки данных из списка Python?

    trapwalker
    @trapwalker Куратор тега Python
    Программист, энтузиаст
    s_list = [
        {'one': 1, 'two': 2, 'seven': 7, 'fix': 'price', 'number': [5, 4, 2, 3, 5, 4], 'dig': 4},
        {'one': 5, 'two': 4, 'seven': 6, 'fix': 'nix', 'number': [3, 5, 7, 2, 3, 9], 'dig': 5},
        {'one': 8, 'two': 3, 'seven': 9, 'fix': 'pix', 'number': [3, 2, 3, 1, 8, 4], 'dig': 9}
    ]
    for i, item in enumerate(s_list):
        print('\nItem #', i, ':')    
        for key in item:
            print(key, '=', item[key])
    Ответ написан
    1 комментарий