Думали ли вы когда-нибудь о том, что однажды слишком быстро втянулись в веб-программирование на PHP? И вот уже прошло много лет, у вас хороший опыт, и вы не думаете ни о каких других способах „делать“ веб, кроме как на PHP. Может быть, у вас возникают сомнения в правильности выбора, однако непонятно, как найти способ быстро его проверить. А хочется примеров, хочется знать, как изменятся конкретные аспекты деятельности.
Сегодня я попробую ответить на вопрос: «А что если вместо PHP писать на Python?».
Сам я долгое время задавался этим вопросом. Я писал на PHP 11 лет и даже являюсь сертифицированным специалистом. Я научился его «готовить» так, чтобы он работал в точности, как мне надо. И когда я в очередной раз читал на Хабре перевод статьи о том, как всё в PHP плохо, я просто недоумевал. Однако подвернулся случай пересесть на Ruby, а потом и на Python. На последнем я и остановился, и теперь попробую рассказать вам PHP-шникам, как нам питонистам живётся.
Формат статьи
Наилучший способ познавать новый язык — сравнение с регулярно-используемым, если новый язык не принципиально отличается от текущего. Неплохая попытка сделана на сайте Ruby, но, к сожалению, там мало примеров.
Также я должен отметить, что я сравню не все аспекты деятельности, а только те, которые будут бросаться в глаза в первые недели работы с новым языком.
Подготовка консолей
Я попытался сделать эту статью интерактивной. Поэтому при прочтении настоятельно рекомендую набирать примеры из неё в консолях. Вам понадобится консоль PHP 5.3+, а лучше сразу psysh:
1 |
php -a |
И консоль Python 2/3. Лучше поставить более удобные варианты bpython или ipython, чем встроенная в язык по умолчанию, так как в них уже есть автодополнение. Но можно и так:
1 |
python |
1 2 3 4 |
<span class="keyword">import</span> rlcompleter <span class="keyword">import</span> readline readline.parse_and_bind(<span class="string">"tab: complete"</span>) <span class="comment"># Это включит автодополнение</span> |
Сам язык
- Python — язык со строгой неявной динамической типизацией (см. Ликбез по типизации). Python — не имеет чёткого назначения, используется для веб, демонов, приложений, научных расчётов, как язык расширений. Близкие аналоги по типизации: Ruby.
- PHP — язык с нестрогой неявной динамической типизацией. PHP — тоже язык общего назначения, однако области применения, отличные от веб и демонов, в нём проработаны плохо и не пригодны к продакшену. Некоторые полагают, что это из-за того, что PHP создан чтобы умирать. Близкие аналоги по типизации: JavaScript, Lua, Perl.
Основные особенности
- Код пишем в файлах с расширением .py вне зависимости от версии питона. Никаких открывающих тегов аналогичных <?PHP не нужно, так как питон изначально создавался как язык программирования общего назначения.
- Кстати, по этой же причине нет такой вещи как php.ini. Есть два десятка переменных окружения, но почти всегда они не определены (кроме PYTHONIOENCODING). То есть, никаких дефолтных конекшенов к базам, управлений фильтрами ошибок, лимитами, расширениями и пр. Что, между прочим, характерно для большинства языков общего назначения. И в связи с этим поведение программ практически идентично всегда (а не зависит от любимых настроек вашего тимлида). Настройки аналогичные php.ini почти всегда хранятся в главном конфиге приложения.
- Нет точки с запятой в конце строки. Если её поставить, то она будет работать так же, как и в PHP, но вообще она является необязательной и нежелательной. Поэтому можно сразу забыть о ней.
- Переменные не начинаются с $ (кстати, PHP унаследовал это от Perl, а тот — от баш).
- Присваивание в циклах и условиях не работает. Сделано это специально, чтобы никто не перепутал сравнение с присваиванием, что, по мнению автора языка, является нередкой ошибкой.
- Python при парсинге файлов автоматически рядом кладет копию с расширением .pyc (если у вас Python < 3.3 и вы не установили PYTHONDONTWRITEBYTECODE), где находится байт-код того, что вы написали. Затем он всегда выполняет только этот файл, если вы не изменили исходник. Данные файлы автоматически игнорируются во всех IDE и обычно не мешают. Это можно воспринимать как полный аналог PHP APC, с учётом того .pyc файлы скорее всего будут находится в памяти в файловом кэше.
- Вместо: NULL, TRUE, FALSE — None, True, False и только в таком регистре.
Вложенность отступами
Ну и самая необычная вещь: вложенность кода определяется не фигурными скобками, а отступами. То есть вместо того, чтобы писать так:
1 2 3 4 5 |
<span class="keyword">foreach</span>(<span class="variable">$a</span> <span class="keyword">as</span> <span class="variable">$value</span>) { <span class="variable">$formatted</span> = <span class="variable">$value</span>.<span class="string">'%'</span>; <span class="keyword">echo</span> <span class="variable">$formatted</span>; } |
Надо делать так:
1 2 3 4 |
<span class="keyword">for</span> value <span class="keyword">in</span> a: formatted = value + <span class="string">'%'</span> print(formatted) |
Стойте, стойте! Не спешите закрывать вкладку. Здесь вы можете сделать ошибку, такую же, как сделал я. Когда-то мысль о том, что вложенность кода определяется отступами, казалась мне полным идиотизмом. Все защитные силы организма протестовали в едином порыве. Ведь несмотря на всякие Style Guide, все пишут по-разному.
Я открою вам страшную тайну. Проблемы отступов не существует. Отступы в 99% процентах случаев автоматически расставляются IDE точно так же, как и в любом другом языке. Вы вообще даже не думаете об этом. За 2 года работы с языком я не припомню ни одного случая, когда кто-нибудь накосячил бы с отступами.
Строгая типизация
Следующая вещь на которой стоит сфокусировать внимание — строгая типизация. Но для начала немного кода:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<span class="keyword">print</span> <span class="string">'0.60'</span> * <span class="number">5</span>; <span class="keyword">print</span> <span class="string">'5'</span> == <span class="number">5</span>; <span class="variable">$a</span> = <span class="keyword">array</span>(<span class="string">'5'</span>=><span class="keyword">true</span>); <span class="keyword">print</span> <span class="variable">$a</span>[<span class="number">5</span>]; <span class="variable">$value</span> = <span class="number">75</span>; <span class="keyword">print</span> <span class="variable">$value</span>.<span class="string">'%'</span>; <span class="variable">$a</span>=<span class="string">'0'</span>; <span class="keyword">if</span>(<span class="variable">$a</span>) <span class="keyword">print</span> <span class="string">'non zero length'</span>; <span class="comment">// Самая частая ошибка</span> |
Все указанные вещи возможны благодаря нестрогой типизации. Но в питоне это не работает:
1 2 3 4 5 |
<span class="prompt">>>> </span><span class="keyword">print</span> <span class="string">"25"</span> + <span class="number">5</span> Traceback (most recent call last): File <span class="string">"<stdin>"</span>, line <span class="number">1</span>, <span class="keyword">in</span> <module> TypeError: cannot concatenate <span class="string">'str'</span> <span class="keyword">and</span> <span class="string">'int'</span> objects |
Правда, обычно у вас в коде типы перемешиваться не будут и данный эффект не будет мозолить вам глаза. В принципе, когда я писал на PHP, ситуаций когда нестрогая типизация реально помогала, было 1-2 на проект, а так обычно взаимодействовали переменные одного типа.
Философия строгой типизации накладывает свой отпечаток и на обработку ошибок. Например, если функция int должна возвращать целый тип, то она не может вернуть None на строку, из которой нельзя однозначно извлечь этот тип. Поэтому генерируется исключение. Это грозит тем, что всё, что прислал пользователь, надо преобразовывать в нужный тип, иначе вы рано или поздно схватите эксепшн на проде.
1 2 3 4 5 |
<span class="keyword">try</span>: custom_price = int(request.GET.get(<span class="string">'custom_price'</span>, <span class="number">0</span>)) <span class="keyword">except</span> ValueError: custom_price = <span class="number">0</span> |
Это касается не только стандартных функций, но и некоторых методов для списков, строк, части функций во вспомогательных библиотеках. Обычно питон-разработчик примерно на память помнит, где какое исключение может упасть, и учитывает это. Если не помнит, иногда лазит в код библиотеки, чтобы подсмотреть. Но конечно же иногда бывает, что не все варианты учитываются, и порой пользователи ловят эксепшены на проде. Но поскольку это нечастое явление, и обычно веб-фреймворк присылает их админу на почту автоматически, всё довольно быстро чинится.
Чтобы использовать значения разных типов в одном выражении, вам нужно их преобразовать, для этого есть функции: str,int, bool, long. Ну а для форматирования есть более элегантные конструкции.
Строки
Форматирование
Было:
1 2 3 4 5 |
<span class="variable">$tak</span> = <span class="string">'так'</span>; <span class="keyword">echo</span> <span class="string">"Вы сейчас делаете $tak или {$tak}."</span>; <span class="keyword">echo</span> <span class="string">"Или "</span>.<span class="variable">$tak</span>.<span class="string">"."</span>; <span class="keyword">echo</span> sprintf(<span class="string">"Но бывает и %s или %1$'.9s."</span>, <span class="variable">$tak</span>); |
Теперь вам нужно просто переучиться:
1 2 3 4 5 6 7 8 9 10 |
etot = <span class="string">'этот'</span> var = <span class="string">'вариант'</span> print(<span class="string">'На %s вариант'</span> % etot) print(etot + <span class="string">' вариант тоже можно использовать, но не рекомендуется'</span>) print(<span class="string">'Или на %s %s'</span> % (etot, var)) print(<span class="string">'Или на %(etot)s %(var)s'</span> % {<span class="string">'etot'</span>: etot, <span class="string">'var'</span>: var}) <span class="comment"># Очень удобно для локализаторов</span> print(<span class="string">'Или на {} {}'</span>.format(etot, var)) print(<span class="string">'Или на {1} {0}'</span>.format(var, etot)) print(<span class="string">'Или на {etot} {var}'</span>.format(var=var, etot=etot)) |
Вариантов вроде больше, а вот подстановки одной-двух переменных через фигурные скобки в двойных кавычках реально не хватает. Зато есть хороший вариант для локализаторов.
Методы строки
Самое главное, что есть в Python и чего не хватает в PHP, — это встроенные методы. Давайте сравним:
1 2 3 |
strpos(<span class="variable">$a</span>, <span class="string">'tr'</span>); trim(<span class="variable">$a</span>); |
vs
1 2 3 |
a.index(<span class="string">'tr'</span>) a.strip() |
А как часто вы делали что-то типа такого?
1 2 |
substr(<span class="variable">$a</span>, strpos(<span class="variable">$a</span>, <span class="string">'name: '</span>)); |
vs
1 2 |
a[a.index(<span class="string">'name: '</span>):] |
Поддержка юникода
Ну и наконец юникод. В Python 2 все строки по умолчанию не юникод (В Python 3 — по умолчанию юникод). Но стоит вам подставить магическую букву u вначале строки, как она автоматически становится юникодной. И далее все встроенные (и не встроенные) строковые методы Python будут работать хорошо.
1 2 3 4 5 |
<span class="prompt">>>> </span>len(<span class="string">'Привет мир'</span>) <span class="number">19</span> <span class="prompt">>>> </span>len(<span class="string">u'Привет мир'</span>) <span class="number">10</span> |
В PHP, кстати, вы можете воспользоваться MBString function overloading php.net/manual/en/mbstring.overload.php и получить аналогичный эффект. Правда, вы лишаетесь работы с помощью перегруженных функций с бинарными строками, но вы по прежнему можете работать со строкой как с массивом.
Массивы
Теперь разберёмся с массивом. В PHP вы могли запихнуть в качестве ключей целые числа или строки:
1 2 |
var_dump([<span class="number">0</span>=><span class="number">1</span>, <span class="string">'key'</span>=><span class="string">'value'</span>]); |
Несмотря на то что array переводится как массив, в PHP array не обычный массив (то есть список), а ассоциативный (то есть, словарь). Обычный массив в PHP тоже есть, это SPLFixedArray. Он ест меньше памяти, потенциально быстрее, но ввиду сложности объявления и сложности расширения практически не используется.
В Python для массива мы используем 3-4 типа данных:
- list — список.
1234567a = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>] <span class="comment"># краткая форма</span>a[<span class="number">10</span>] = <span class="number">11</span> <span class="comment"># Нельзя добавлять произвольный индекс</span><span class="comment"># > IndexError: list assignment index out of range</span>a.append(<span class="number">11</span>) <span class="comment"># но можно добавлять в конец</span><span class="keyword">del</span> a[<span class="number">0</span>] <span class="comment"># удалять по ключу</span>a.remove(<span class="number">11</span>) <span class="comment"># удалять по значению</span> - dict — словарь. Интересная особенность, что словарь не гарантирует сохранение порядка (в PHP гарантирует).
12345d = {<span class="string">'a'</span>: <span class="number">1</span>, <span class="string">'b'</span>: <span class="number">2</span>, <span class="string">'c'</span>: <span class="number">3</span>} <span class="comment"># краткая форма</span>d[<span class="number">10</span>] = <span class="number">11</span> <span class="comment"># Можно добавлять произвольный индекс</span>d[<span class="built_in">True</span>] = <span class="built_in">False</span> <span class="comment"># И использовать для ключей любые неизменяемые типы (число, строка, булевские, кортежи, замороженные множества)</span><span class="keyword">del</span> d[<span class="built_in">True</span>] <span class="comment"># удалять по ключу</span> - tuple — кортеж. Эдакий фиксированный массив с неоднородными значениями. Отлично подходит для возврата из функции нескольких значений и компактного хранения настроек.
123456789t = (<span class="built_in">True</span>, <span class="string">'OK'</span>, <span class="number">200</span>, ) <span class="comment"># краткая форма</span>t[<span class="number">0</span>] = <span class="built_in">False</span> <span class="comment"># Нельзя менять элемент</span><span class="comment"># > TypeError: 'tuple' object does not support item assignment</span><span class="keyword">del</span> t[<span class="built_in">True</span>] <span class="comment"># Нельзя удалять по ключу</span><span class="comment"># > TypeError: 'tuple' object doesn't support item deletion</span>t = ([], ) <span class="comment"># Но можно менять вложенные изменяемые структуры (списки, словари, множества, массивы байт, объекты)</span>t[<span class="number">0</span>].append(<span class="number">1</span>)<span class="comment"># > a == ([1], )</span> - set — множество. По сути, список уникальных значений не гарантирующий сохранения их порядка.
1234567891011s = set([<span class="number">1</span>,<span class="number">3</span>,<span class="number">4</span>])s[<span class="number">0</span>] = <span class="built_in">False</span> <span class="comment"># Нельзя работать с элементами по индексу</span><span class="comment"># > TypeError: 'set' object does not support indexing</span>s.add(<span class="number">5</span>) <span class="comment"># Можно добавлять элемент</span>s.remove(<span class="number">5</span>) <span class="comment"># Удалять</span><span class="comment"># Ну и стандартная математика для множеств</span>s | s <span class="comment"># Объединение</span>s & s <span class="comment"># Пересечение</span>s - s <span class="comment"># Разность</span>s ^ s <span class="comment"># Объединение уникальных</span>
В PHP массив — эдакий швейцарский нож, всё в одном. А Python больше склоняет к тому, что надо использовать более нативные для Computer Science наборы данных, в каждом место свои, более подходящие. «Да ну их, опять задротам неймётся, программирование должно быть простым», — могут воскликнуть некоторые читатели. И будут неправы, так как:
- Во-первых: наличие выбора между tuple, set, list и dict не отягощает — это становится привычкой, становится подсознательным выбором, как переключение передач.
- Во-вторых: почти всегда используется или list или dict.
- В-третьих: почти всегда, когда нужно хранить пару ключ-значение, не важен порядок и наоборот, когда нужно хранить порядок, очень редко есть при этом пара ключ-значение, а не просто значение.
- В-четвёртых: существует упорядоченный dict — OrderedDict.
Импорты
Ещё одна интересная вещь — импорты. Своеобразный альтернативный взгляд на неймспейсы с обязательным использованием.
В PHP ты написал require_once и дальше тебе это доступно, пока жива PHP-шная сессия выполнения. Обычно при использовании CMS люди запихивают всё в классы, а классы располагают в специальных местах, и пишут свою маленькую функцию, которая знает эти места и регистрируют её через spl_autoload_register в самом начале файла.
В питоне каждый файл — своя область видимости. И в нём будет доступно только то, что вы в него подгрузите. По умолчанию доступна только стандартная библиотека питона (около 80 функций). Но давайте лучше на примере:
Допустим, вы сделали файл tools/logic.py
1 2 3 4 5 6 7 8 9 10 11 |
<span class="function"><span class="keyword">def</span> <span class="title">is_prime</span><span class="params">(number)</span>:</span> max_number = int(sqrt(number)) <span class="keyword">for</span> multiplier <span class="keyword">in</span> range(<span class="number">2</span>, max_number + <span class="number">1</span>): <span class="keyword">if</span> multiplier > max_number: <span class="keyword">break</span> <span class="keyword">if</span> number % multiplier == <span class="number">0</span>: <span class="keyword">return</span> <span class="built_in">False</span> <span class="keyword">return</span> <span class="built_in">True</span> |
И теперь хотите его использовать в файле main.py. В этой ситуации вам необходимо импортировать или весь файл или нужные вам части в файл, где вы работаете.
1 2 3 4 |
<span class="keyword">from</span> tools.logic <span class="keyword">import</span> is_prime print(is_prime(<span class="number">79</span>)) |
И так абсолютно везде. Почти все файлы на питоне начинаются с импортов в текущий файл вспомогательных питонячих объектов: ваших и встроенных библиотек. Это всё равно как если бы функции в PHP вида mysqli_*, pdo_*, memcached_*, а также весь ваш код находились только в неймспейсах, и вам приходилось бы каждый раз их импортировать в каждом файле. Какие преимущества у такого подхода?
- Во-первых: под одинаковым именем в разных файлах могут быть разные объекты. Но именно вы решаете, что и под каким именем будет использовано конкретно здесь.
- Во-вторых: резко упрощается рефакторинг. Вы всегда можете отследить класс, функцию или другую сущность. Простейший поиск показывает, где она используется и как.
- В-третьих: это принудительно заставляет разработчиков минимально продумывать структуру организации кода.
Из минусов можно отметить только появление такого эффекта как циклические импорты, но, во-первых, это редкое явление, во-вторых, это штатная ситуация и вполне понятно, как с ней бороться.
Удобно ли каждый раз прописывать импорты? Это зависит от вашего склада ума. Если вам нравится больший контроль над кодом, то вы предпочтёте прописывание импортов, чем их отсутствие. В некоторых командах существует даже своя система правил, описывающих в каком порядке можно подключать внешний код для минимизации циклических импортов до минимума. Если в вашей команде нет таких правил и вы не хотите особо заморачиваться, то можно просто положиться на IDE, которая автоматически проставит импорты для всего, что вы используете. Ну и в довесок: импорты не уникальная особенность питона, в Java и C# тоже есть импорты, вроде никто не жаловался.
Параметры в функции *args, **kwargs
Синтаксис с параметрами по умолчанию в целом похож:
1 2 3 4 5 |
<span class="function"><span class="keyword">function</span> <span class="title">makeyogurt</span><span class="params">(<span class="variable">$flavour</span>, <span class="variable">$type</span> = <span class="string">"acidophilus"</span>)</span> {</span> <span class="keyword">return</span> <span class="string">"Making a bowl of $type $flavour."</span>; } |
vs
1 2 3 |
<span class="function"><span class="keyword">def</span> <span class="title">makeyogurt</span><span class="params">(flavour, ftype=<span class="string">"acidophilus"</span>)</span>:</span> <span class="keyword">return</span> <span class="string">"Making a bowl of %s %s."</span> % (ftype, flavour, ) |
Но порой вам нужна функция под неизвестное количество аргументов. Это может быть: проксирующая функция, логирующая функция или функция для получения сигналов. В PHP, начиная с 5.6, вам доступен следующий синтаксис:
1 2 3 4 5 6 7 8 9 10 11 12 |
<span class="function"><span class="keyword">function</span> <span class="title">sum</span><span class="params">(...<span class="variable">$numbers</span>)</span> {</span> <span class="variable">$acc</span> = <span class="number">0</span>; <span class="keyword">foreach</span> (<span class="variable">$numbers</span> <span class="keyword">as</span> <span class="variable">$n</span>) { <span class="variable">$acc</span> += <span class="variable">$n</span>; } <span class="keyword">return</span> <span class="variable">$acc</span>; } <span class="keyword">echo</span> sum(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>); <span class="comment">// Или </span> <span class="keyword">echo</span> add(...[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>]); |
В Python аналогично можно ловить в массив неименнованные и в словарь именованные аргументы:
1 2 3 4 5 6 7 8 9 10 |
<span class="function"><span class="keyword">def</span> <span class="title">acc</span><span class="params">(*args, **kwargs)</span>:</span> total = <span class="number">0</span> <span class="keyword">for</span> n <span class="keyword">in</span> args: total += n <span class="keyword">return</span> total print(acc(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>)) <span class="comment"># Или </span> print(acc(*[<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>])) |
Соответственно *args — list неименованных аргументов, **kwargs — dict именованных аргументов.
Классы
Давайте посмотрим на следующий код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<span class="class"><span class="keyword">class</span> <span class="title">BaseClass</span>:</span> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self)</span>:</span> print(<span class="string">"In BaseClass constructor"</span>) <span class="class"><span class="keyword">class</span> <span class="title">SubClass</span><span class="params">(BaseClass)</span>:</span> <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, value)</span>:</span> super(SubClass, self).__init__() self.value = value <span class="function"><span class="keyword">def</span> <span class="title">__getattr__</span><span class="params">(self, name)</span>:</span> print(<span class="string">"Cannot found: %s"</span> % name) c = SubClass(<span class="number">7</span>) print(c.value) |
Какие основные отличия от PHP мы можем выделить:
- self используется вместо $this и обращение всегда происходит через точку. При этом self обязан быть первым аргументом во всех методах (вернее, почти во всех). Идея здесь заключается в том, что Python во все методы передаёт первым аргументом указатель на сам объект (его, кстати, можно ловить в переменную с любым именем).
- Как и в PHP, здесь есть аналог магических имён. Вместо __construct — __init__. Вместо __get — __getattr__ и т.д.
- Не нужен new. Создать экземпляр класса — все равно, что вызвать функцию.
- Более громоздкое обращение к родительскому методу. С super надо постоянно помнить, что там и куда.parent:: в PHP — всё же более элегантная конструкция.
О чем еще следует сказать:
- Можно наследовать более чем один класс.
- Нет public, protected, private. Питон позволяет в runtime менять структуру экземпляра, да и сам класс обычным присваиванием, поэтому от какой-либо защиты решено было отказаться. По этой же причине не нужен и Reflection. Есть только аналог protected — если перед именем написать двойное подчеркивание. Но это просто меняет имя переменной/метода снаружи на неблагозвучное _%ClassName%__%varname%, и по нему прекрасно можно напрямую работать со скрытым.
- Нет static, финальных классов и интерфейсов. В Python более простая объектная модель в целом. Вместо Singleton у вас скорее всего будет файл со всем необходимым функционалом или файл, который при импорте будет возвращать один и тот же экземпляр. Вместо интерфейса вы скорее всего напишете класс, который бросает исключения на методы, которые забудут переопределить.
- Чистое ООП не приветствуется. Как бы странно это ни звучало, но благодаря тому, что всё и так объект (даже bool), а также потому, что в синтаксисе нет разных операторов для обращения к методу или функции из импортированного файла, любое обращения идёт через точку. Так вот, благодаря всему этому задача инкапсуляции решается не только через ООП. Поэтому в большинстве проектов классы пишутся только там, где они нужны.
Стиль кодирования
Не знаю как у вас, а я писал на несколько долгоиграющих проектов и всегда отмечал, что стиль кодирования у разных членов команды разный. Нередко по коду можно понять, кто это писал. И всегда хотелось, чтобы был какой-то стандарт оформления кода для единообразия. И всегда были большие споры при согласовании этого документа внутри команды. Для питона это тоже справедливо, но в меньшей степени, ибо есть рекомендации от людей, в квалификации которых мало кто может сомневаться и советов от которых на первое время хватит:
- PEP 8. Рекомендации от самой команды питона и одноимённая утилита для проверки.
- Рекомендации от Google.
Кроме того существует так называемый Дзен Питона, согласно одному из правил которого, «должен существовать один — и, желательно, только один — очевидный способ сделать это». То есть, нельзя один и тот же код написать множеством примерно аналогичных способов. Конечно же, это идеализм, однако он приятно проявляется в мелочах:
- Вместо большой строковой библиотеки, с некоторыми функциями, частично перекрывающими друг друга, гораздо меньший набор методов и дополнительные встроенные библиотеки (например для контрольных сумм).
- Вместо strlen и count — всегда len.
- И т.д.
Версии питона
В PHP новые версии всегда обратно совместимы со старыми. В питоне есть Python 2 и Python 3. Они не совместимы. По этой причине вся «тяжёлая промышленность» до сих пор сидит на Python 2. С Python 3 выпускаются на прод только энтузиасты. Основная причина этого — не портированы на Python 3 или портированы совсем недавно некоторые нужные вещи. Если вы собираетесь что-либо делать, то Python 2.7 вам более чем будет достаточен. Если вы увлечётесь питоном, вы со временем поймёте, что такое Python 3 и когда его можно использовать.
Что на что меняется
Здесь я просто оставлю набор ключевых слов, по которым будет понятно, как называется альтернатива той технологии, которой вы пользуетесь сейчас.
- composer -> pip
- mod_php -> mod_wsgi
- nginx + php-fpm -> nginx + uwsgi + uwsgi_python
- daemon.io -> tornado, twisted
- Zend Framework -> Django
Вместо выводов
Как понять надо ли оно вам?
- Вы считаете, что чем строже типизация, тем лучше.
- Вы предпочитаете язык с хорошо продуманной архитектурой.
- Вы перфекционист, вас раздражает излишнее разнообразие.
- Вакансии по питону в вашем городе выглядят интереснее (или надоело писать только сайты).
- Хотите, чтобы на основном языке программирования можно было писать любой софт (учитывая разумные ограничения, связанные с динамической типизацией).
- Вам не нравится квалификация новичков (из-за низкого порога входа).
Мой способ освоить Python
Если вы разработчик с опытом, то на всё не сильно напрягаясь уйдёт максимум две-три недели.
- 1-я неделя: Чтение Dive Into Python, главы со 2-й по 7-ю включительно. Остальные быстро пролистать и остановиться на интересных моментах. Параллельно решаем на языке 10 задачек с Project Euler. И в конце крайне желательно написать консольную утилиту, принимающую параметры. Это может быть порт какого-то вашего старого bash-скрипта, аналог ls из BusyBox или что-то совсем другое. Важно, чтобы скрипт делал что-то полезное, желательно то, чем вы часто пользуетесь. Я, например, сделал порт своей PHP-утилиты, которая умеет показывать данные в мемкэше.
- 2-я неделя: Напишите простенький аналог хабра на Django и запустите на любом хостинге. Не забудьте состав: регистрация, логин, восстановление пароля, добавления постов и комментариев, удаление, проверка прав на действия.
- 3-я неделя: выбор конторы, где бы вы хотели работать, засылка им резюме с просьбой выслать тестовое задание на питоне для проверки вашей квалификации.
Ещё есть Google Python Classes.
Удачи!
Обновлено: Мелкие исправления и улучшения (благодаря: dginz, defuz, dsx, Stepanow, Studebecker), найден драйвер MySQL для Python 3.3 (благодаря svartalf).
Обновлено: Нашлись абстрактные классы (благодаря: yktoo). Так же со временем вам придётся познакомиться с удивительным миром декораторов.
Источник: http://habrahabr.ru/company/wargaming/blog/221035/