Перейти к содержимому

Как скрыть часть кода в python

  • автор:

Code hiding and line numbers IDLE

Is there any way to enable code hiding (hides the details of a class or a function just shows the definition) and line numbers in IDLE ?

Kavit Shah's user avatar

2 Answers 2

Don’t think so. It was discussed briefly on the mailing lists, but I don’t believe anything’s come out of it since.

If you’re interested in code folding, look into slightly more powerful editors — Geany (GTK) and Sublime Text both support code folding.

A code/line folding feature was asked before in that Python Issue. It was closed and rejected but with good reasons.

If you know this features of IDLE you maybe do not need code folding anymore.

Module Browser: To get an outline view of a file’s classes and functions, use File => Module Browser ( ALT + C ).

Code Context: To get a dynamic view of nested compound statement headers with Options => Code Context.

Об одном способе защиты исходников Python-программы

Однажды мне пришлось участвовать в разработке одного небольшого проекта для научных расчётов, который разрабатывался на языке программирования Python. Изначально Python был выбран как удобный и гибкий язык для экспериментов, визуализации, быстрого прототипирования и разработки алгоритмов, но в дальнейшем стал основным языком разработки проекта. Надо заметить, что проект был хоть и не большим, но довольно насыщенным технически. Для обеспечения требуемой функциональности, в проекте широко применялись алгоритмы теории графов, математическая оптимизация, линейная алгебра и статистика. Также использовались декораторы, метаклассы и инструменты интроспекции. В процессе разработки пришлось использовать сторонние математические пакеты и библиотеки, например, такие как numpy и scipy, а также многие другие.

Со временем стало ясно, что переписывать проект на компилируемом языке слишком затратно по времени и ресурсам. Скорость работы и потребление памяти не являлись критичными показателями в данном случае и были вполне приемлемыми и достаточными. Поэтому было принято решение оставить всё как есть, и продолжить разработку и поддержку проекта на языке Python. К тому же, документация по большей части уже была написана с использованием Sphinx.

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

Здесь сразу обозначилась новая проблема: как защитить исходные коды нашей Python-библиотеки? Может быть, в ином случае никто бы не стал этим заниматься, я бы уж точно, но в библиотеке были реализованы некоторые ноу-хау, и руководители проекта не хотели, чтобы данные наработки попали к конкурентам. Так как я был одним из исполнителей, мне пришлось озаботиться данной проблемой. Далее я постараюсь рассказать об основной идее, что из этого вышло, и как нам удалось скрыть Python-исходники от лишних глаз.

Что предлагают люди

Как известно, наверное, большинству разработчиков, Python — язык интерпретируемый, динамический с богатыми возможностями интроспекции. Бинарные файлы модулей *.pyc и *.pyo (байт-код) легко декомпилируются, поэтому распространять их в чистом виде нельзя (если уж мы решили не показывать исходники по-настоящему).

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

  • Забить и не париться, всё равно, кому надо — расковыряет;
  • Переписать на компилируемом языке;
  • Сделать обфускацию исходников, например с помощью раз и два;
  • Транслировать все Python-модули в модули расширения (*.pyd) с помощью Cython или Nuitka (как сделал warsoul — автор данной статьи);
  • Заменить опкоды в исходниках Python-интерпретатора и распространять свою сборку, как предлагалhodik.

По многим причинам я отбросил все эти способы как неподходящие. Например, обфускация Python-кода. Ну какая может быть обфускация, когда синтаксис языка построен на отступах, а сам язык пронизан «хитрой интроспекцией»? Транслировать все Python-модули в бинарные модули расширения тоже не представлялось возможным, т. к. проект, напомню, был достаточно сложным технически с использованием множества сторонних пакетов, да и сам состоял из большого числа модулей в многоуровневой иерархии пакетов, которые было утомительно перегонять в *.pyd, а потом ловить баги, вылезающие на ровном месте. Возиться с заменой опкодов не хотелось, так как пришлось бы распространять и поддерживать собственную сборку интерпретатора Python, да ещё и компилировать им Python-модули всех используемых сторонних библиотек.

В какой-то момент мне показалось, что эта идея с защитой Python-исходников бесполезная, надо всё это бросить и убедить руководство, что ничего не выйдет и заняться чем-нибудь полезным. Отдаём *.pyc файлы и ладно, кто там будет разбираться? Убедить не получилось, переписывать библиотеку на C++ никому не хотелось, а проект нужно было сдавать. В итоге всё же кое-что получилось сделать. Об этом, если всё ещё интересно, можно прочитать далее.

Что сделали мы

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

Ход моих мыслей был следующим:

  • Шифруем каким-либо способом все исходники нашей Python-библиотеки, можно их даже перемешать и изменить имена файлов модулей и пакетов;
  • Пишем обвязку для того, чтобы Python-интерпретатор умел загружать и импортировать модули из зашифрованных текстовых файлов (расшифровка, восстановление структуры пакетов и имён файлов, импорт и т. д.);
  • «Прячем» всё это в бинарный модуль расширения (*.pyd), чтобы никто не догадался.

Основная идея, думаю, ясна — это более продвинутая обфускация. Как это сделать? Погуглив, я пришёл к выводу, что сделать это вполне реально и даже достаточно просто. С шифрованием исходников всё понятно, зашифровать и/или обфусцировать файлы можно множеством способов, главное, чтобы там была «каша» и «ничего не понятно», а также всё это должно возвращаться к первоначальному виду неизвестным способом (в случае обфускации). Для приведённого здесь примера я буду использовать Python-модуль base64 для «шифрования». В некритичных случаях можно применять замечательный пакет obfuscate.

Python the Importer Protocol

Как же нам реализовать возможность импортировать модули из зашифрованных файлов? К счастью, в Python реализована система хуков при импорте, которая работает на основе Importer Protocol (PEP 302). Значит эту возможность и будем использовать. Для перехвата импортов используется словарь sys.meta_path , в котором должны храниться объекты finder/loader , реализующие Importer Protocol. Опрос этого словаря всегда происходит до того момента, как будут проверены пути в sys.path .

Для минимальной реализации протокола импорта нужно реализовать два метода: find_module и load_module . Метод find_module отвечает за поиск конкретного модуля/пакета (ведь нам нужно перехватывать импорт только своих модулей, а остальные отдавать на откуп стандартному механизму), а метод load_module , соответственно, загружает конкретный модуль только если он был «найден» в методе find_module .

Итак, вроде бы добрались до сути. Можно привести простой пример. Минимальный пример класса, реализующего Importer Protocol, подходящего для наших целей. Он будет заниматься импортом модулей «зашифрованных» base64 из обычной структуры пакетов (в данном случае для простоты мы просто «зашифровали содержимое» файлов, но никак не меняли их имена и структуру пакетов). Считаем, что расширения файлов для наших модулей будут гордо называться ".b64".

Как это работает? Первым делом при создании экземпляра класса собирается информация о модулях нашей библиотеки, которую мы «шифруем». Затем при загрузке конкретного модуля, читается нужный «зашифрованный» файл, «расшифровывается» и импортируется с помощью средств модуля imp уже из «расшифрованной» текстовой строки. Как использовать данный класс? Очень легко. Буквально, одной строчкой включается возможность импортировать «зашифрованные» исходники нашей библиотеки, а по сути ставится хук на импорт:

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

Вот и всё, с этого момента импорт модулей из нашей библиотеки осуществляется с перехватом и «расшифровкой». Наш хук будет дёргаться при любом вызове инструкции import, и если импортируется модули нашей библиотеки, хук будет их обрабатывать и загружать, остальные импорты будут обрабатываться стандартно. Что нам и требовалось для более продвинутой обфускации. Представленный код импортёра и установки хука можно положить уже в *.pyd файл и надеяться на то, что никто не будет его дизассемблировать в надежде понять, что мы тут наворотили. В реальном проекте можно использовать настоящее шифрование, в том числе с использованием аппаратного ключа, что должно повысить надёжность данного метода. Также изменение имён файлов и структуры пакетов может быть полезным для большего запутывания.

Заключение

В качестве заключения хочу сказать, что я противник скрывать исходники, которые нельзя просто так взять и скрыть. В данном случае я не осмелюсь обсуждать этическую сторону вопроса и нужность/полезность сокрытия Python-исходников. Тут я просто представил метод, как это можно сделать и получить какой-то результат. Естественно, это не панацея. Python-код, действительно, невозможно скрыть полностью и от всех. Код модулей всегда можно получить с помощью интроспекции встроенными возможностями языка после их загрузки, например, из переменной sys.modules . Но это уже не так очевидно, как если бы исходники были открыты изначально.

Возможно, что всё, что тут написано и яйца выеденного не стоит — давно известные истины, либо бред сумасшедшего. Но если вышеописанное кому-то может оказаться полезным, я буду рад. Лично для меня данный опыт был полезен, хотя бы потому, что позволил лучше разобраться в мощной и гибкой системе загрузки и импортирования модулей и Importer Protocol. О тех самых штуках, которые чаще всего не требуются разработчикам для написания программ на Python. Всегда интересно узнать что-то новое.

Спасибо за внимание.

UPD 14.08.2013:
По просьбе tangro сделал минимальный проект, в котором демонстрируется описанный способ, но без настоящего шифрования (применены только некие алгоритмы обратимого преобразования).
Скачать zip-архив можно по ссылке. Нужен Python 2.7 x86 под Windows. Запускать нужно скрипт «test_main.py».

UPD 2:
И более интересный пример, в котором производятся некоторые вычисления. Здесь все импорты и вызовы функций из зашифрованных модулей скрыты в бинарном модуле. Скачать архив можно по ссылке.

Шифруемся — обфускация Python кода

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

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

В этом нам поможет инструмент "обфускатор". Он шифрует код и делает его недоступным для других людей.

Таких инструментов достаточно много, давайте посмотрим основные. Некоторые из них есть в online версии, т.е сайт

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

Давайте посмотрим, как его преобразит наш инструмент.

Видим зашифрованный результат:

Это достаточно сильный инструмент, однако всегда найдется рыбка покрупнее!

Переходим к обфускатору, уже больее серьезного типа.

Как видите — данный инструмент уже требует загрузку файла, и результат так же выдает в файловом формате.

В этой статье мы наглядно увидели обфускацию Python кода онлайн-инструментами. Ссылки на все инструменты оставляем ниже:

Что такое инкапсуляция в Python?

При работе с языком объектно-ориентированного программирования, таким как Python, инкапсуляция в Python является одной из 4 важных концепций, которые необходимо понять. Остальные три — это наследование, полиморфизм и абстракция.

Что такое инкапсуляция в Python?

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

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

Концепция инкапсуляции одинакова для всех объектно-ориентированных языков программирования. Разница видна, когда концепции применяются к конкретным языкам.

По сравнению с такими языками, как Java, которые предлагают модификаторы доступа (общедоступные или частные) для переменных и методов, Python предоставляет доступ ко всем переменным и методам.

Приведенный ниже код показывает, как легко получить доступ к переменным.

Поскольку у нас нет модификаторов доступа в Python, мы будем использовать несколько различных методов для управления доступом к переменным в программе.

Методы контроля доступа

Python предлагает несколько методов для ограничения доступа к переменным и методам в программе. Давайте подробно рассмотрим методы.

Использование одиночного подчеркивания

Распространенное соглашение программирования Python для идентификации частной переменной — это префикс с подчеркиванием. Теперь это не имеет никакого значения для компилятора. Переменная по-прежнему доступна в обычном режиме. Но поскольку это соглашение, принятое программистами, оно сообщает другим программистам, что переменные или методы должны использоваться только в рамках класса.

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

Использование двойного подчеркивания

Если вы хотите сделать члены класса, то есть методы и переменные, частными, вам следует поставить перед ними двойное подчеркивание. Но Python предлагает некоторую поддержку модификатора private. Этот механизм называется изменением имени. При этом по-прежнему можно получить доступ к членам класса извне.

Имя Mangling

В Python любой идентификатор с __Var переписывается интерпретатором python как _Classname__Var, а имя класса остается как текущее имя класса. Этот механизм изменения имен называется изменением имен.

В приведенном ниже примере в Class person переменная age изменена, и ей предшествуют двойные символы подчеркивания в начале.

Вы можете заметить, что к переменным по-прежнему можно обращаться с помощью методов, которые являются частью класса. Но вы не можете получить доступ напрямую извне, поскольку это частная переменная.

Использование методов Getter и Setter

Если вы хотите получить доступ и изменить частные переменные, следует использовать методы доступа getter и setter, поскольку они являются частью Class.

Преимущества

Инкапсуляция не только обеспечивает лучший поток данных, но и защищает данные от внешних источников. Концепция инкапсуляции делает код самодостаточным.

Это очень полезно на уровне реализации, вы должны скрыть данные в блоке, чтобы упростить инкапсуляцию, а также защитить данные.

Зачем нужна инкапсуляция?

Следующие причины показывают, почему разработчики находят инкапсуляцию удобной и почему объектно-ориентированная концепция превосходит многие языки программирования.

  • Инкапсуляция помогает в достижении четко определенного взаимодействия в каждом приложении.
  • Объектно-ориентированная концепция фокусируется на возможности повторного использования кода в Python.
  • Приложения можно безопасно обслуживать.
  • Это обеспечивает гибкость кода за счет правильной организации.
  • Способствует плавному взаимодействию с пользователями без каких-либо внутренних сложностей.
  • Это улучшает читаемость кода. Любые изменения в одной части кода не помешают другой.
  • Инкапсуляция обеспечивает защиту данных и предотвращает случайный доступ к данным. Доступ к защищенным данным можно получить с помощью описанных выше методов.

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *