Як подати проект на Python пересічному користувачеві без компіляторів та милиць, або підлаштовуємо велосипед під вершника

Здрастуй, читач.

Я люблю Python таким, який він є: спритний, лаконічний, має з-під коробки дуже багато корисних речей (наприклад, можна дізнатися, чи є число полиморфом всього у 1 рядок).
На ньому в даний момент пишу клітинний автомат — спрощене відтворення життя в чашці Пельтьє. 5 класів живих істот, спадковість, вплив «сили водню» на життя і розвиток клітини. Але це вже інша історія.

Власне, це не залишилося непоміченим з боку оточуючих. З'явилися люди, які хотіли «поганяти» за свою колонію ціанобактерій і вивести їх в еліту своєї чашки, витіснивши інших. Але тут виявляється, на думку деяких, не дуже гарна риса даного ЯП — він (майже) не компілюємо — доводиться з собою тягати 80 мегабайт додаткового вантажу. А що, якщо…

Мета — зробити Python більш добрим по відношенню до простого смертному користувачеві, тобто:
— не примушуємо юзера ставити середовище;
— не змушуємо качати великі файли (> 25 мб);
— не посилаємо танцювати з бубнами, «натисни там, потім намалюй п'ятикутну зірку»;
— не втрачаємо швидкість виконання програми. Лише трохи почекати початку запуску.

Для своїх цілей я обрав ось таку алхімію:

1) Беремо невинно чистий Python (у статті використовується Python 3.4, але вас ніщо не стримує використовувати більш пізні\ранні версії), без Tkinter, IDLE, pydoc, тестів;
Спойлер

2) Додаємо в нього додаткові (не стандартні, + нами спеціально вилучені) потрібні модулі, що використовуються в програмі, додаємо їх в "/lib/" директорію. Поміщаємо в окрему директорію папку з інтерпретатором + виконуваний скрипт;
3) Стискаємо;
Обережно, нецензурна лексика!

4) Створюємо на компилируемом ЯП (найпростіше — pascal) маленьку програмку, яка расшакалит розпакує це справа вже на комп'ютері кінцевого користувача і запустить;
5) Завдання, виконана, my master!

Пункти 1 і 2. Чистимо Python

Цей пункт можна виконати і самостійно. Виконуємо їх для зменшення розміру готового велосипеда. (У розгорнутому стані інтерпретатор у мене важить 60,9 мб, в стислому — всього 11,9 мб, тобто стиск становить 80,5%, що важливо).
Обережно, нецензурна лексика!

Посилання на Dropbox. (12 мб)

Потім складаємо zip архів, файл (.py або .pyc) і супутні файли (картинки, ресурси та ін.) в одну папку. Важливо! Основний файл повинен називатися python main.py або main.pyc щоб уникнути плутанини з іншими .py або .pyc файлами вашого проекту.

Вийде щось схоже:

dir_test/
… python.zip
… main.py
… image.bmp
… README.txt

Пункт 3

Тепер стискаємо весь вміст папки (!!!) в zip файл. Навіщо ми знову архівуємо інтерпретатор? Інтерпретатор ми стискаємо з високим ступенем стиснення і, якщо ми при кожній пробі будемо заново архівувати його, то буде йти досить багато часу.

Пункт 4

Тепер залишається написати програму на pascal/delphi:
Код :
program python;

{$APPTYPE CONSOLE}

{$R *.res}

uses
System.SysUtils, System.Zip, ShellAPI;

var a, path : string;
zip : TZipFile;
i, s, p : integer;
begin
try
// якщо вже проводилася розпакування...
if fileexists('.sourse\\main.py') or fileexists('.sourse\\main.pyc') then begin
writeln('Starting...');
if fileexists('.sourse\\main.py') then ShellExecute(0, nil, PChar('"'+ExtractFilePath(ParamStr(0))+'\\.sourse\\python\\py.exe"'), PChar(string('"'+ExtractFilePath(ParamStr(0))+'\\.sourse\\main.py"')), ", 1)

else if fileexists('.sourse\\main.pyc') then ShellExecute(0, nil, PChar('"'+ExtractFilePath(ParamStr(0))+'\\.sourse\\python\\py.exe"'), PChar(string('"'+ExtractFilePath(ParamStr(0))+'\\.sourse\\main.pyc"')), ", 1)
else begin
write('File not found! Press any key...');
read(i);
end;

exit();
end;

//розпаковуємо файл .zip
zip := TZipFile.Create;
zip.UTF8Support := True;
s := 0; // індикатор наявності main файлу
p := 0; //індикатор наявності python
zip.Open('sourse.zip', zmRead);
for I := 0 to zip.FileCount - 1 do
begin
writeln(zip.FileNames[i], ' extracting...');
if zip.FileNames[i] = 'main.py' then s := 1;
if zip.FileNames[i] = 'main.pyc' then s := 2;
if zip.FileNames[i] = 'python.zip' then p := 1;
zip.Extract(zip.FileNames[i], '.sourse');
end;
zip.Close;
DeleteFile('sourse.zip');
//починаємо роботу з розпакуванням пайтона
write('Extracting Python, it may take a few seconds...');
zip.Open('.sourse\\python.zip', zmRead);
zip.ExtractAll('.sourse\\python');
write('Done!'+#10#13 +'Starting...');
zip.Destroy();
DeleteFile('.sourse\\python.zip');
//перевірки
if s = 0 then //якщо в ході розпакування основний файл не був виявлений
begin
write('No .py or .pyc file!', #10#13, 'Press any key...');
read(a);
exit();
end;
if p = 0 then //якщо в ході розпакування python не був виявлений
begin
write('No Python!', #10#13, 'Press any key...');
read(a);
exit();
end;
//сам запуск
if s = 1 then ShellExecute(0, nil, PChar('"'+ExtractFilePath(ParamStr(0))+'\\.sourse\\python\\py.exe"'), PChar(string('"'+ExtractFilePath(ParamStr(0))+'\\.sourse\\main.py"')), ", 1) //PChar(string(ExtractFilePath(ParamStr(0))+'\\.sourse\\main.py'))
else ShellExecute(0, nil, PChar('"'+ExtractFilePath(ParamStr(0))+'\\.sourse\\python\\py.exe"'), PChar(string('"'+ExtractFilePath(ParamStr(0))+'\\.sourse\\main.pyc"')), ", 1); //PChar(string(ExtractFilePath(ParamStr(0))+'\\.sourse\\main.py'))

exit();
except
//на випадок, якщо щось трапиться
on E: Exception do begin
Writeln(E.ClassName, ': ', E.Message);
write('Broken! Press any button...');
read(a);
end;
end;
end.


Програма важить 559 кб, що дуже непогано.

Для перевірки напишемо скрипт-пробник на python:
Скрипт на python
print('Привіт! Я - переносний скрипт на python і я займаю в запакованому вигляді менше 20 мб!')
print('Зараз я спробую імпортувати модуль random...')

try:
import random
print('Хех, мені це вдалося!')
print('Тримай псевдовипадкове число :', random.randrange(0,100))
except:
print('%( що Не вийшло')

ragnarok = input('Натисніть будь-яку кнопку...')



Все це важить у запакованому вигляді 12 мегабайт (але по збільшенню кількості коду вага не буде істотно змінюватися) і працює швидко — за тестами перша розпакування триває не більше 4 секунд, а наступні запуски — менш півсекунди.
У розгорнутому вигляді ми отримуємо 60,9 мегабайта.

Посилання на тест:
https://www.dropbox.com/s/17xdpeju7u0oieh/python%20test.zip?dl=0 (Dropbox, 12 мб)

Підіб'ємо підсумок

Ми здатні повноцінно запускати python програми на комп'ютерах під керуванням Windows, де не варто інтерпретатор Python (також в ситуаціях з встановленої версії 2.x), збільшили мобільність додатки, не втрачаючи швидкості виконання.

Спасибі, що дочитали мою статтю. У мене мало досвіду в такій справі, але я буду старатися! Наступною буде стаття про клітинний автомат.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.