Компания
65,52
рейтинг
12 марта 2015 в 13:32

Разработка → Если вы решили перейти с PHP на Python, то к чему следует подготовиться

Думали ли вы когда-нибудь о том, что однажды слишком быстро втянулись в веб-программирование на PHP? И вот уже прошло много лет, у вас хороший опыт, и вы не думаете ни о каких других способах „делать“ веб, кроме как на PHP. Может быть, у вас возникают сомнения в правильности выбора, однако непонятно, как найти способ быстро его проверить. А хочется примеров, хочется знать, как изменятся конкретные аспекты деятельности.

Сегодня я попробую ответить на вопрос: «А что если вместо PHP писать на Python?».

Сам я долгое время задавался этим вопросом. Я писал на PHP 11 лет и даже являюсь сертифицированным специалистом. Я научился его «готовить» так, чтобы он работал в точности, как мне надо. И когда я в очередной раз читал на Хабре перевод статьи о том, как всё в PHP плохо, я просто недоумевал. Однако подвернулся случай пересесть на Ruby, а потом и на Python. На последнем я и остановился, и теперь попробую рассказать вам PHP-шникам, как нам питонистам живётся.




Формат статьи


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

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

Подготовка консолей


Я попытался сделать эту статью интерактивной. Поэтому при прочтении настоятельно рекомендую набирать примеры из неё в консолях. Вам понадобится консоль PHP 5.3+, а лучше сразу psysh:

php -a

И консоль Python 2/3. Лучше поставить более удобные варианты bpython или ipython, чем встроенная в язык по умолчанию, так как в них уже есть автодополнение. Но можно и так:

python

import rlcompleter
import readline
readline.parse_and_bind("tab: complete")    # Это включит автодополнение

Как не делать это каждый раз
В файл ~/.pyrc положить:
import rlcompleter
import readline
readline.parse_and_bind("tab: complete")    # Это включит автодополнение

В ~/.bashrc добавить:

export PYTHONSTARTUP="${HOME}/.pyrc"
export PYTHONIOENCODING="UTF-8"

И, чтобы применить изменение прямо сейчас без перезапуска консоли, выполнить:
source ~/.bashrc



Сам язык


  • 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 и только в таком регистре.

Вложенность отступами

Ну и самая необычная вещь: вложенность кода определяется не фигурными скобками, а отступами. То есть вместо того, чтобы писать так:

foreach($a as $value) {
    $formatted = $value.'%';
    echo $formatted;
}
Надо делать так:
for value in a:
    formatted = value + '%'
    print(formatted)


Стойте, стойте! Не спешите закрывать вкладку. Здесь вы можете сделать ошибку, такую же, как сделал я. Когда-то мысль о том, что вложенность кода определяется отступами, казалась мне полным идиотизмом. Все защитные силы организма протестовали в едином порыве. Ведь несмотря на всякие Style Guide, все пишут по-разному.

Я открою вам страшную тайну. Проблемы отступов не существует. Отступы в 99% процентах случаев автоматически расставляются IDE точно так же, как и в любом другом языке. Вы вообще даже не думаете об этом. За 2 года работы с языком я не припомню ни одного случая, когда кто-нибудь накосячил бы с отступами.

Строгая типизация


Следующая вещь на которой стоит сфокусировать внимание — строгая типизация. Но для начала немного кода:

print '0.60' * 5;

print '5' == 5;

$a = array('5'=>true);
print $a[5];

$value = 75;
print $value.'%';

$a='0';
if($a) print 'non zero length';  // Самая частая ошибка

Все указанные вещи возможны благодаря нестрогой типизации. Но в питоне это не работает:

>>> print "25" + 5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: cannot concatenate 'str' and 'int' objects

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

Правда, обычно у вас в коде типы перемешиваться не будут и данный эффект не будет мозолить вам глаза. В принципе, когда я писал на PHP, ситуаций когда нестрогая типизация реально помогала, было 1-2 на проект, а так обычно взаимодействовали переменные одного типа.

Философия строгой типизации накладывает свой отпечаток и на обработку ошибок. Например, если функция int должна возвращать целый тип, то она не может вернуть None на строку, из которой нельзя однозначно извлечь этот тип. Поэтому генерируется исключение. Это грозит тем, что всё, что прислал пользователь, надо преобразовывать в нужный тип, иначе вы рано или поздно схватите эксепшн на проде.

try:
    custom_price = int(request.GET.get('custom_price', 0))
except ValueError:
    custom_price = 0

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

Чтобы использовать значения разных типов в одном выражении, вам нужно их преобразовать, для этого есть функции: str, int, bool, long. Ну а для форматирования есть более элегантные конструкции.

Строки


Форматирование

Было:

$tak = 'так';
echo "Вы сейчас делаете $tak или {$tak}.";
echo "Или ".$tak.".";
echo sprintf("Но бывает и %s или %1$'.9s.", $tak);

Теперь вам нужно просто переучиться:

etot = 'этот'
var = 'вариант'
print('На %s вариант' % etot)
print(etot + ' вариант тоже можно использовать, но не рекомендуется')
print('Или на %s %s' % (etot, var))
print('Или на %(etot)s %(var)s' % {'etot': etot, 'var': var})  # Очень удобно для локализаторов
print('Или на {} {}'.format(etot, var))
print('Или на {1} {0}'.format(var, etot))
print('Или на {etot} {var}'.format(var=var, etot=etot))

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

Методы строки

Самое главное, что есть в Python и чего не хватает в PHP, — это встроенные методы. Давайте сравним:

strpos($a, 'tr');
trim($a);
vs
a.index('tr')
a.strip()

А как часто вы делали что-то типа такого?

substr($a, strpos($a, 'name: '));
vs
a[a.index('name: '):]


Поддержка юникода

Ну и наконец юникод. В Python 2 все строки по умолчанию не юникод (В Python 3 — по умолчанию юникод). Но стоит вам подставить магическую букву u вначале строки, как она автоматически становится юникодной. И далее все встроенные (и не встроенные) строковые методы Python будут работать хорошо.

>>> len('Привет мир')
19
>>> len(u'Привет мир')
10

В PHP, кстати, вы можете воспользоваться MBString function overloading php.net/manual/en/mbstring.overload.php и получить аналогичный эффект. Правда, вы лишаетесь работы с помощью перегруженных функций с бинарными строками, но вы по прежнему можете работать со строкой как с массивом.

Немного про сырые строки
«Сырые» строки

Многие из вас знают чем одиночные кавычки отличаются от двойных:
$a = 'Hello.\n';
$a[strlen($a)-1] != "\n"; 

Что-то подобное есть и в Python. Если подставлять перед строкой литерал r, то это поведение почти аналогично одиночным кавычкам в PHP.
a = r'Hello.\n' 
a[-1] != '\n'


Массивы


Теперь разберёмся с массивом. В PHP вы могли запихнуть в качестве ключей целые числа или строки:

var_dump([0=>1, 'key'=>'value']); 

Несмотря на то что array переводится как массив, в PHP array не обычный массив (то есть список), а ассоциативный (то есть, словарь). Обычный массив в PHP тоже есть, это SPLFixedArray. Он ест меньше памяти, потенциально быстрее, но ввиду сложности объявления и сложности расширения практически не используется.

В Python для массива мы используем 3-4 типа данных:

  • list — список.
    a = [1, 2, 3]  # краткая форма
    a[10] = 11  # Нельзя добавлять произвольный индекс
    # > IndexError: list assignment index out of range
    a.append(11)  # но можно добавлять в конец
    del a[0]  # удалять по ключу
    a.remove(11)  # удалять по значению
    
  • dict — словарь. Интересная особенность, что словарь не гарантирует сохранение порядка (в PHP гарантирует).
    d = {'a': 1, 'b': 2, 'c': 3}  # краткая форма
    d[10] = 11  # Можно добавлять произвольный индекс
    d[True] = False  # И использовать для ключей любые неизменяемые типы (число, строка, булевские, кортежи, замороженные множества)
    del d[True]  # удалять по ключу
    
  • tuple — кортеж. Эдакий фиксированный массив с неоднородными значениями. Отлично подходит для возврата из функции нескольких значений и компактного хранения настроек.
    t = (True, 'OK', 200, )  # краткая форма
    t[0] = False  # Нельзя менять элемент
    # > TypeError: 'tuple' object does not support item assignment
    del t[True]  # Нельзя удалять по ключу
    # > TypeError: 'tuple' object doesn't support item deletion
    t = ([], )  # Но можно менять вложенные изменяемые структуры (списки, словари, множества, массивы байт, объекты)
    t[0].append(1)
    # > a == ([1], )
    
  • set — множество. По сути, список уникальных значений не гарантирующий сохранения их порядка.
    s = set([1,3,4])
    s[0] = False  # Нельзя работать с элементами по индексу
    # > TypeError: 'set' object does not support indexing
    s.add(5)  # Можно добавлять элемент
    s.remove(5)  # Удалять
    # Ну и стандартная математика для множеств
    s | s  # Объединение
    s & s  # Пересечение
    s - s  # Разность
    s ^ s  # Объединение уникальных
    

В PHP массив — эдакий швейцарский нож, всё в одном. А Python больше склоняет к тому, что надо использовать более нативные для Computer Science наборы данных, в каждом место свои, более подходящие. «Да ну их, опять задротам неймётся, программирование должно быть простым», — могут воскликнуть некоторые читатели. И будут неправы, так как:

  • Во-первых: наличие выбора между tuple, set, list и dict не отягощает — это становится привычкой, становится подсознательным выбором, как переключение передач.
  • Во-вторых: почти всегда используется или list или dict.
  • В-третьих: почти всегда, когда нужно хранить пару ключ-значение, не важен порядок и наоборот, когда нужно хранить порядок, очень редко есть при этом пара ключ-значение, а не просто значение.
  • В-четвёртых: существует упорядоченный dict — OrderedDict.

Импорты


Ещё одна интересная вещь — импорты. Своеобразный альтернативный взгляд на неймспейсы с обязательным использованием.

В PHP ты написал require_once и дальше тебе это доступно, пока жива PHP-шная сессия выполнения. Обычно при использовании CMS люди запихивают всё в классы, а классы располагают в специальных местах, и пишут свою маленькую функцию, которая знает эти места и регистрируют её через spl_autoload_register в самом начале файла.

В питоне каждый файл — своя область видимости. И в нём будет доступно только то, что вы в него подгрузите. По умолчанию доступна только стандартная библиотека питона (около 80 функций). Но давайте лучше на примере:

Допустим, вы сделали файл tools/logic.py
def is_prime(number):
    max_number = int(sqrt(number))

    for multiplier in range(2, max_number + 1):
        if multiplier > max_number:
            break
        if number % multiplier == 0:
            return False

    return True

И теперь хотите его использовать в файле main.py. В этой ситуации вам необходимо импортировать или весь файл или нужные вам части в файл, где вы работаете.
from tools.logic import is_prime

print(is_prime(79))

И так абсолютно везде. Почти все файлы на питоне начинаются с импортов в текущий файл вспомогательных питонячих объектов: ваших и встроенных библиотек. Это всё равно как если бы функции в PHP вида mysqli_*, pdo_*, memcached_*, а также весь ваш код находились только в неймспейсах, и вам приходилось бы каждый раз их импортировать в каждом файле. Какие преимущества у такого подхода?

  • Во-первых: под одинаковым именем в разных файлах могут быть разные объекты. Но именно вы решаете, что и под каким именем будет использовано конкретно здесь.
  • Во-вторых: резко упрощается рефакторинг. Вы всегда можете отследить класс, функцию или другую сущность. Простейший поиск показывает, где она используется и как.
  • В-третьих: это принудительно заставляет разработчиков минимально продумывать структуру организации кода.

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

Удобно ли каждый раз прописывать импорты? Это зависит от вашего склада ума. Если вам нравится больший контроль над кодом, то вы предпочтёте прописывание импортов, чем их отсутствие. В некоторых командах существует даже своя система правил, описывающих в каком порядке можно подключать внешний код для минимизации циклических импортов до минимума. Если в вашей команде нет таких правил и вы не хотите особо заморачиваться, то можно просто положиться на IDE, которая автоматически проставит импорты для всего, что вы используете. Ну и в довесок: импорты не уникальная особенность питона, в Java и C# тоже есть импорты, вроде никто не жаловался.

Параметры в функции *args, **kwargs

Синтаксис с параметрами по умолчанию в целом похож:

function makeyogurt($flavour, $type = "acidophilus")
{
    return "Making a bowl of $type $flavour.";
}
vs
def makeyogurt(flavour, ftype="acidophilus"):
    return "Making a bowl of %s %s." % (ftype, flavour, )

Но порой вам нужна функция под неизвестное количество аргументов. Это может быть: проксирующая функция, логирующая функция или функция для получения сигналов. В PHP, начиная с 5.6, вам доступен следующий синтаксис:

function sum(...$numbers) {
    $acc = 0;
    foreach ($numbers as $n) {
        $acc += $n;
    }
    return $acc;
}

echo sum(1, 2, 3, 4);
// Или 
echo add(...[1, 2, 3, 4]);

В Python аналогично можно ловить в массив неименнованные и в словарь именованные аргументы:

def acc(*args, **kwargs):
    total = 0
    for n in args:
        total += n
    return total

print(acc(1, 2, 3, 4))
# Или 
print(acc(*[1, 2, 3, 4]))

Соответственно *argslist неименованных аргументов, **kwargsdict именованных аргументов.

Классы


Давайте посмотрим на следующий код:

class BaseClass:
    def __init__(self):
        print("In BaseClass constructor")

class SubClass(BaseClass):
    def __init__(self, value):
        super(SubClass, self).__init__()
        self.value = value

    def __getattr__(self, name):
        print("Cannot found: %s" % name)

c = SubClass(7)
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), а также потому, что в синтаксисе нет разных операторов для обращения к методу или функции из импортированного файла, любое обращения идёт через точку. Так вот, благодаря всему этому задача инкапсуляции решается не только через ООП. Поэтому в большинстве проектов классы пишутся только там, где они нужны.

Стиль кодирования


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


Кроме того существует так называемый Дзен Питона, согласно одному из правил которого, «должен существовать один — и, желательно, только один — очевидный способ сделать это». То есть, нельзя один и тот же код написать множеством примерно аналогичных способов. Конечно же, это идеализм, однако он приятно проявляется в мелочах:

  • Вместо большой строковой библиотеки, с некоторыми функциями, частично перекрывающими друг друга, гораздо меньший набор методов и дополнительные встроенные библиотеки (например для контрольных сумм).
  • Вместо 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). Так же со временем вам придётся познакомиться с удивительным миром декораторов.
Автор: @gnomeby

Комментарии (211)

  • +4
    Интересная статья, Сам совсем недавно пересел с PHP на Python.Выйди эта статья пораньше, начал бы изучение именно с нее.Очень помогли курсы Codecademy.Также хотелось бы отметить лямбды в Python, которые существенно сокращают код
    • +5
      А в PHP замыкания не использовали? Имхо, из-за однострочности лямбд в Python я даже чувствую некоторую скованность после перехода на Python из PHP.
      • +1
        Как говорит Гвидо, вы можете объявить функцию внутри функции через обычный def, вот и будет замыкание.
      • 0
        Если выражение слишком длинное, то его можно расписать на много строк. Питон это позволяет, достаточно одной незакрытой скобки в строке, чтоб он временно закрыл глаза на табуляцию.
        Для больших кусков кода — локальные функции и локальные классы.
        Там, правда, нетривиальные правила видимости и захвата переменных, но не настолько, чтоб кричать ужас-ужас.
    • 0
      А о преимуществах Питона над PHP где-нибудь можно почитать? Подразумеваю, что речь идет о веб-разработке естественно.
      • +1
        Опрос: PHP vs Python вся суть, как всегда, в комментариях)Ну а вообще, если речь про веб, то имхо лучше сравнивать фреймворки, например yii и django
      • +1
        Нет конечно, это слишком субъективно.
        • 0
          Да вот мне тоже так кажется) Особенно если рассматривать альтернативу языка, который и создавался и используется исключительно для веб-разработки 90% проектов…
          • +4
            Я когда после 8 лет PHP в вебе, переезжал на питон (сразу на действующий большой проект) с параллельным обучением питону. То по началу жутко плевался на питон и боготворил пхп, но «продолжал грызть кактус». В итоге через примерно месяц работы (именно работы, а не вялого обучения) на питоне, меня уже ни чем было затащить назад в PHP.
  • +5
    Сам пишу на PHP уже около 10ти лет. Больше посматриваю в сторону Ruby. Синтаксис Ruby мне кажется более лаконичным и удобным, почему вы с Ruby перешли на Python? Это был ваш выбор (если да то почему ?) или так просто исторически сложилось?
    • +1
      Тоже пишу на PHP, и хочу переходить на Python. Ruby мне не понравился, когда на Coursera проходил курс Programming Languages (кстати рекомендую, там ML/Racket/Ruby). Какой-то он неинтуитивный.
    • +6
      Это бы мой выбор. Я работал в RightScale и по работе ковырялся с OpenStack и поймал себя на мысле, что индусткий код OpenStack на питоне мне понятнее, чем наш собственны код на Ruby.
      Мне не понравилось то, что в Руби очень много возможностей по метапрограммированию, которые лучше в командной работе не использовать. Кроме того, меня несколько напрягало отсутствие возможности узнать где именно произошло подмешивание в класс. Ну а питон прост и эффективен. Я использую его возможности по-полной, кроме того мне безумно максимальное использование слов для операторов вместо символосочетаний.
      • +2
        В Ruby есть возможность узнать место подмешивания. Нужно получить объект метода и вызвать source_location: object.method(:some_method_name).source_location. Вы получите ссылку на файл и номер строки, где этот метод определн. Это сработает даже для методов, определенных через class_eval. Часто используется в спеках или в консольке, когда нужно быстро найти исходник, который запрятан в геме.

        Метапрограммирование — это то, за что Ruby и любят больше всего. Вся его лаконичность в конечном итоге сокрыта в DSL, который создают разработчики. В командной работе с ним как правило проблем нет, тк используются наработки, которые переходят из проекта в проект.
        • 0
          (не туда)
      • 0
        > Кроме того, меня несколько напрягало отсутствие возможности узнать где именно произошло подмешивание в класс.

        gem 'pry' или ещё лучше 'jazz_hands'. show-method покажет вам всё.
    • +12
      Скажу со своей стороны:

      1. У Python больше комьюнити чем у Ruby, а значит больше разработчиков, больше проектов и т. д.

      2. Python более вездесущ, в то время как Ruby все таки больше ориентирован на web. Прелесть Python в том, что на нем с одинаковым удобством можно писать и веб-сервисы, и демоны, и оконные приложения. В Ruby дела обстоят немного хуже.

      3. Вы наверняка найдете библиотеку которая вам может понадобится — обработка изображений, массовые вычисления, байндинги на какую-нибудь малоизвестную базу данных и можете быть спокойны, что не попадете в ситуацию «на Ruby этого просто нет».
      • +1
        Ага, а тем временем
        С Python 3 выпускаются на прод только энтузиасты. Основная причина этого — драйвер MySQL не портирован на Python 3 (а также некоторые другие нужные вещи).
        • +7
          Сказки про то, как на Python 3 переходят только энтузиасты я слышу чаще всего именно в контексте «нет драйвера для MySQL» и немного реже «мы используем библиотеку X, которую никто на Py3 переводить не собирается». При этом, те, кто на MySQL никак не завязан (например, пользуются PostgreSQL) таких проблем не испытывают. Так что фразу корректнее было бы переписать как «Wargaming не использует Python 3 в проде потому, что нет MySQL-драйвера».
          • 0
            Драйвер нашёлся. Но нам ещё не хватает Fabric, gevent, twisted.
            • +3
              Так намного интереснее. Вместо gevent можно попробовать eventlet. Twisted когда-то там будет, вроде бы больше половины задач по портированию выполнены, может быть имеет смысл помочь в портировании для ускорения процесса. В Fabric в прошлом году намержили чего-то на тему Py3, но насколько всё действительно работает неизвестно. Вообще, что касается Fabric, у меня есть неожиданное предложение не пользоваться им вообще. Я так понимаю, что он нужен для деплоев, а для этого есть методы интереснее и, главное, надёжнее.
              • 0
                Приведите пример пожалуйста.
                • +1
                  Например, вот. Но этот пример не лежит в плоскости программирования на Питоне, и я не жду, что вы сейчас кинетесь всё ломать и переделывать.
            • 0
              Fabric -> ansible
              • 0
                К вопросу о драйвере mysql и иже с ним: джва месяца ищу python_ldap под py3 (нужен с аутентификацией Kerberos для AD-шного LDAP), может тут кто что дельного подскажет.
                • 0
                  Оооо, еще и с керберосом, ну удачи. Вообще можно ctypes попробовать просто либу ldap заюзать. Она точно умеет сама керберос, и скорее всего в скрипте об этом ломать голову не придется. По идее слабать необходимый сабсет возможностей можно быстрее чем за два месяца :)
                • 0
                  Или если есть под двойку, то можно попробовать портировать. Да хотя бы тем же py2to3 пройтись и прочее. Ну сурово ждать — никто не сделает мне кажется.
            • 0
              ansible и asyncio — зачем вам этот твистед на python 3?
          • 0
            Ну, работал в куче проектов где использовался уже со старта python 3, никаких проблем, все нужные вещи уже давным давно портированы.
        • 0
          «Скрипач (MySQL) не нужен!» ©
        • 0
          это бред, Python 3 уже во всю используется в продакшене.
      • +1
        2. У меня десятки демонов написаны на Ruby, работают 24x7 и всё в порядке, оконные приложения сейчас только пробую (не было нужды) на shoesrb.com" ощущения непонятные
        3. Ни сам не встречал и у знакомых которые пишут на Ruby про такое особо не слышал.

        От себя напишу что писать код в Ruby — невероятное удовольствие, его получается мало и он очень понятный. Очень радует качество gem'ов (библиотек). На питоне немного писал, но он мне не нравиться, он однозначно лучше PHP, но код получается мусорное чем на Ruby + очень непонятная ситуация с 2 -> 3 версиями + раздражает отношение к отступам (непонимаю почему не реализовали как в F#, там как захотел, так и отступил, лишь бы однообразно), даже разработчики sublime text, что-то приуныли с портированием на него, хотя они очень толковые ребята.
        • +1
          Я не хотел сказать, что на ruby нельзя что-то сделать или даже что это будет сделано плохо, я лишь хотел сказать в чем python лучше.

          Честно говоря я озадачен по поводу «раздражает отношение к отступам». Что с ними не так?
          • –3
            Так а чем именно он лучше? Чем вот удобнее демоны, например делать в Python нежели в Ruby?

            С отступами у меня привычка втыкать отладочный вывод чего либо (если не пользуюсь тестами) с нарушением отступа, то есть чтобы было видно эту лишнюю операцию и потом можно было легко удалить. И так как это я делаю на автомате, то это ломает код и меня раздражает, либо эти ненужные операции остаются в коде и их нужно выковыривать… В общем, это проблема «новичка» судя по всему.
        • +1
          Проверил, кстати, про отступы в Python, там оказывается не только пробелы, но и табы используются, их только мешать нельзя, что наверное плохо сказывается на копипасте и положительно сказывается на качестве кода =), так что я наверное всё же придираюсь попусту по поводу отступов.
          • 0
            Их можно мешать как угодно. Основные правила:

            1. Вложенный блок должен иметь в точности тот же отступ, что и блок уровнем выше + ещё хотя бы один пробельный символ.
            2. Начала всех statement’ов на одном уровне должны иметь одинаковый отступ.


            В Python-2 есть ещё правила, устанавливающие эквивалентность табуляции некоторому количеству пробелов, но в Python-3* это удалили.

            Т.е. вот это:
            if True:
            >-------if True:
            >-------    print('HERE')
            
            if True:
                if True:
                >---print('HERE')
            
                >---print(
            'HERE'
            )
                >---if True:
                >---    print('HERE')
            
            (> с дефисоминусами изображает один символ табуляции)

            есть валидный код на Python.
            • 0
              Разумеется то, что так можно писать, не означает, что так нужно писать. Но при копипасте на нулевой уровень отступов вам абсолютно без разницы, какие в копипасте отступы. Если при копипасте на некоторый уровень ваш редактор просто добавляет точную копию пробельных символов нужного вам уровня в начало каждой строки копипасты, то код опять будет работать. Код не будет работать, если вы напишете

              if True:
                  True# Four spaces and statement that does nothing
                   True# Five spaces
              



              Случайно обнаружил: правило эквивалентности (8 пробелов == 1 символ табуляции) из Python-3 никуда не делось, но работает не всегда и как‐то странно.
              • 0
                А откуда взялось 8?
                • 0
                  Я даже не знаю, кого вам следует спросить: DEC с их терминалами VT серии или производителей печатных машинок.

                  В общем, так сложилось исторически. А историю я знаю плохо. Это сейчас вы в редакторе можете установить любое желаемое количество пробелов, приходящееся на один символ табуляции. В терминале до сих пор 8 и по‐умолчанию так будет всегда из‐за обратной совместимости: проверьте echo $'\ta\n0123456789'.
        • +6
          >мало и он очень понятный [...] но код получается мусорное чем на Ruby

          У меня прямо противоположные ощущения, например. Каждый раз когда вижу код на руби — ощущение будто китайский читать пытаюсь, в то время как питон простой и лаконичный.
          • –10
            питон простой и лаконичный
            WAT?!
      • +1
        Можете сказать несколько примеров чего «на Ruby просто нет»?
        • 0
          Честно – не могу сказать. Но посмотрев например на отношение кода python/ruby на github'e, думаю можно сделать вывод, что есть масса чего-то такого эзотерического, что реализовано для python, но чего нет на ruby. Опять же, вопрос бы чем Python лучше Ruby, я совершенно не хотел сказать что с Ruby все плохо.
          • 0
            Дело в том, что на руби многие вещи приняты как стандарт, и их используют в 90%. Не так много клонов, ну а какой смысл изобретать свой велосипед, раз уже есть отличный, принятый сообществом и используемый повсеместно. Насколько я знаю, в питоне несколько иначе, когда есть несколько схожих по функционалу библиотек, кто-то использует одни, кто-то другие, нет чего-то принятого большинством, как стандарт. Комментарии выше это только подтверждают.
        • 0
          На Ruby просто нет pandas (http://pandas.pydata.org/).
      • 0
        1. Вот уж не знаю, мб. по количеству человек пишущих на питоне больше, но вот с точки зрения профессионалов не уверен.
        2. Почему это Ruby на веб? Вроде как всегда и везде был. Может вы спутали Ruby с RoR? На Mac так вообще по умолчанию.
        3. Не согласен, все что надо под руби есть, гемов как грязи.

        Сам я больше PHP / JS
        Но приходилось писать проекты и на питоне и на руби.

        Если соскакивать с PHP, то вероятно на JS или Ruby
        Это исключительно мое мнение.
    • 0
      потому что поезд руби уже ушел это «еще один скриптовый язык». оптимальный стэк сейчас это питон для задач вроде обработки данных, веб скрапинга и джаваскрипт для всего остального.
  • +2
    Тоесть senior-PHP разработчику можно перелезть на Python за 3 недели? Как-то это смахивает на «С++ за 21 день».
    • +6
      Смотря что вы вкладываете в понятие перелезть. Научится нормально ориентироваться в языке, чтобы быть готовым выполнять тестовые задания — вполне. Senior Python вы от этого сразу не станете, но Middle вполне.
    • +1
      даже middle легко переходит в течении двух-трех недель. На собственном опыте проверено
    • +8
      За 3 недели разве что в Junior Python Developer. Давайте будем честными. У языков совершенно разная идеология, у необходимо закончить хотя бы пару проектов именно на Python, чтобы уверенно ориентироватся в его принципах и подходах. К тому же за 3 недели невозможно разобратся во всем обилии библиотек на Python, а это важно, поскольку в этом смысле Python следует unix-way — большое количество небольших инструментов. Обычная ситуация, когда в среднем проекте 20-30 записимостей.
      • +2
        Разобраться в языке это не всё равно, что разобраться в тонкостях библиотек и API. Сам язык-то достаточно простой. Достаточно просто разбираться в основным парадигмах программирования и владеть на базовом уровне computer science, тогда никаких особых трудностей не возникнет. Senior'ом конечно не станешь, но и из Junior'а быстро вырастешь.
    • 0
      Да не такой уж он и хитрый, если есть опыт кроме php, то более менее удобочитаемый код будет получаться уже через пару недель.
      Я вообще на плюсах пишу, а на питоне ваяю всякие тестировщики и прочие утилиты для деплоймента. Разобрался как раз за пару недель.
    • 0
      Джуниором станете за 3 недели. Через месяца три непрерывной работы — мидлом.
      Это если были сеньором в аналогичной области.
    • 0
      гм… на самом деле любому программисту, с честным высшим образованием, достаточно легко переходить на разные языки в своей и смежных областях, не вижу проблем.
      Но одно дело перейти, а другое конечно набить практику, так как только в ней прошупываются реальные подводные камни.
  • 0
    драйвер MySQL не портирован на Python 3

    Есть другой довольно неплохой драйвер — pythonhosted.org/oursql/.
    • 0
      А еще есть pymysql — github.com/PyMySQL/PyMySQL
      • 0
        Есть же официальный dev.mysql.com/downloads/connector/python/
        • 0
          Да но он тоже на чистом питоне.
          Я вот посмотрел Django рекомендует mysqlclient, который умеет Python 3.3. Выглядит так как будто проблема решена.
          • 0
            Подозреваю, что django рекомендует mysqlclient вместо mysql-connector как минимум потому что mysql.connector.django до сих пор не умеет ГИС поля
            • 0
              Кому нужен ГИС, уходят на PostgreSQL/PostGIS. В MySQL с этим всё грустно.
              • +4
                Ну да, в идеальном мире.
                Поддержка ГИС в mysql есть, и драйвер джанги должен это уметь, независимо от степени тлена фичи базы данных.
  • +3
    Спасибо за статью. Python хороший язык.

    По своему опыту могу сказать, что переход на другой язык ускоряется, если взять какой-нибудь проект. У моём случае — был взят проект переписывания Access приложения на web-систему (для себя, в далёком 2007, в качестве эксперимента выбрал Ruby/Rails — хотя на них не было опыта работы, был php/python). Когда есть мотивация — изучение происходит более интересно :)
  • +5
    А самые вкусности: передача переменных по имени в функции и классы, декораторы, вложенность классов и методов, еще куча разной магии не описаны. К тому же намного более качественные пакеты. Пишу на php 11 лет, на python 3 года. Однозначно питон.
    ZF vs Django == LOL Symfony это недоджанго, т.к. многих интересных решений, которые реализованы на питоне пых не позволяет.
  • +1
    Было бы неплохо, если бы статья раскрывала еще и тему «зачем», а не только «что будет».
    • 0
      См. раздел: «Как понять надо ли оно вам?»
  • +10
    export PYTHONSTARTUP="/home/%username%/.pyrc"

    Не надо стесняться писать в .bashrc на баше:

    export PYTHONSTARTUP="${HOME}/.pyrc"


  • 0
    Python — красивый, удобный, простой и изящный язык. Использую его для определённого класса прикладных и административных задач. Но для web разработки, исходя из своего опыта, могу предположить, что PHP подходит больше. ZF и особенно ZF2, конечно, не конкурент Django. Но а если сравнить с Laravel? А если писать без фреймворка, например, прототип?

    У меня вопрос ко всем. А что с отладкой? Для Питона пока только освоил dbg, но это не всегда удобно. Xdebug для php отлично интегрируется почти со всеми популярными редакторами (например, Sublime).
    • +1
      Используйте pudb, он прекрасен и не привязан к редактору. Ну и PyCharm и Eclipse с PyDev неплохо справляются.
      • +3
        PyCharm, судя по описанию (и опыту работы с PHPStorm), отличный инструмент. Но я в последнее время подсел на Sublime.
        • 0
          Можно поинтересоваться, хватает ли возможностей Sublimа? ведь я полагаю всякие автодополнения из phpDoc он не поддерживает, так же нет фичей из рода дополнительных окон: для Базы данных, встроенной консоли?
          • +3
            Я юзаю Sublime, более чем достаточно для работы. Моя связка: Sublime 3 c плагинами+ Jedi, Jinja2 и Sublimelinter, дебаггер pudb.
            Насчёт дополнительных окон не скажу, вполне возможно есть плагины для sublime.
          • +1
            Работал с множеством редакторов, в том числе есть лицензионный PHPStorm. Sublime люблю за скорость, акцент на клавиатуре в UI, множественное редактирование, работу с окнами, поддержку большого количества языков и технологий. Автодополнения phpDoc поддерживает, встроенная консоль есть (REPL), но я ею не пользуюсь. Для баз данных плагинов не искал, не знаю. В целом, если работать только с PHP и JavaScript, PHPStorm выигрывает (прежде всего в навигации по коду). Однако, я работаю также с другими языками, Go и Python. И как один редактор для всего меня вполне устраивает.
          • +1
            Саблайма хватает выше крыши. Есть мощный плагин anaconda, который дает автокомплит, переход на определение функций, проверку синтаксиса и массу всего полезного.

            Плюс плагины для Сабла пишутся на чистом Питоне, можете посмотреть исходники.
    • 0
      Как вам сказать помягче. Ларавель отдыхает, притом сильно.
      1. ORM без костылей. Там очень сильная магия, можно строить очень сложные зависимости и запросы, не написав ни одной строке на SQL, в ларавеле у меня так не получается.
      2. Работа с наборами форм, ни в одном из php фреймворков я не встречал нормальный аналог Formset. Да и сами формы на порядок мощнее.
      3. Работа с моделями, миксины, пайплайны, менеджеры(хотя нечто похожее на менеджеры в ларавеле есть)
      4. Ну и моя самая большая попоболь ларавеля и симфы — это композер. Когда многие приложения в него добавились, но при этом нифига не адаптировли под работу с ним(из vendor не вынесены конфиги и фиг ты их переопределишь)

      p.s Любовь к постресу, и поддержка гео, а с 1.8 массивов в орм это уже доп. читы :)
  • +6
    Еще в синтаксисе питона особенно радует возможность написания таких конструкций в одну строчку, и код будет вполне читабельным:
    resList = [i for i in range(1, 10) if i % 2 == 0]
    

    в php придется делать так:
    $resList = [];
    for ($i = 1; $i <= 10; $i++) {
        if ($i % 2 == 0) {
            $resList[] = $i;
        }
    }
    
    • +8
      С такой любовью к сокращениям вам явно нужно писать на Ruby, там подобного вагон.
      • +1
        Код на ruby:

        odd = (1..10).step(2).to_a
        
        • +1
          вы рассмотрели слишком частный случай. в общем виде будет так
          (1..10).select {|i| i % 2 == 0}
          
          • 0
            мой вариант на насколько символов короче))

            а вообще да, в любом языке есть несколько разных вариантов реализовать такой код.
          • +2
            Ближе к натуральному языку надо ;-)

            (1..10).select(&:even?)
            • +1
              спасибо, я только учу ruby :) я знаю, что амперсанд конвертирует proc/lambda в block. но ":even?" выглядит как вызов функции через sybmol (как?). я загуглил и узнал, что ".even?" это метод класса Integer.

              как это работает?
              • +2
                invisibleblocks.com/2008/03/28/ruby-facets-symbolto_proc-classto_proc/
                www.iain.nl/going-crazy-with-to_proc

                вы всё правильно поняли у Symbol есть предопределённый метод #to_proc, который преобразует этот символ в Proc объект который принимает аргументом некоторый объект и посылает (#send у Object) ему этот символ (то есть по сути вызывает его метод).

                По первой ссылке грамотно описывается этот трюк (его ещё на объекты можно применять из коробки), по второй есть даже пример как это можно реализовать самостоятельно.
          • +1
            Haskell:

            [2,4..10]
            

            Или, если последовательность более сложная — например, числа от 1 до 100, кратные 3 и 5 одновременно — то на Haskell это выглядит так:

            [x | x <- [1..100], x `mod` 3 == 0, x `mod` 5 == 0]
            
    • +10
      Посыл понятен, но в порядке троллинга:
      $resList = range(2, 10, 2);
      

      • +4
        >>> print range(2,10,2)
        [2, 4, 6, 8]
        >>> 
        
        • +1
          Вот что меня смущает в питоне постоянно это какие-то неуловимые странности в работе стандартных функций, ключевых слов и интерфейсов библиотек. Вот, например, range — почему левая граница включена в ответ а правая нет?
          • +6
            Потому, что в мануале так написано :)

            stop: Generate numbers up to, but not including this number.


            А если серьезно — stackoverflow.com/questions/4504662/why-does-rangestart-end-not-include-end
            • 0
              Нет, то что документировано, это факт.

              Не очень убедительно всё таки звучит объяснение, надо пользоваться языком не задумываясь постоянно правильно ли мы написали следующее ключевое слово или оператор.
              • 0
                Ну вот такая особенность языка. Нужно о ней знать.

                range() (and Python in general) is 0-index based, meaning list indexes start at 0, not 1. eg. The syntax to access the first element of a list is mylist[0]. Therefore the last integer generated by range() is up to, but not including, stop. For example range(0, 5) generates integers from 0 up to, but not including, 5.
          • +5
            Вот что меня смущает в питоне постоянно это какие-то неуловимые странности в работе стандартных функций, ключевых слов и интерфейсов библиотек. Вот, например, range — почему левая граница включена в ответ а правая нет?

            Асимметричность интервалов [left, right) — это общепринятая в программировании нотация, причём тут Питон? Исключения составляют только Паскаль и, судя по вашему комментарию ниже, PHP. В нормальных языках стандартные библиотеки придерживаются соглашения, описанного ещё Эдсгером Дейкстрой: www.cs.utexas.edu/users/EWD/ewd08xx/EWD831.PDF
            • +6
              Я тут попробовал повспоминать языки программирования где есть range, любители Дейсктры получились в меньшинстве:

              Правая граница входит:
              Ruby -> (2..10).step(2)
              Haskell -> [2,4..10]
              PHP -> range(2, 10, 2)
              Erlang -> lists:seq(2,10,2)
              Perl -> grep { $_ % 2 == 0 } (2..10)
              R -> seq(2,10,2)
              F# -> seq
              Dart -> range

              Не входит:
              Python -> range(2,10,2)
              Clojure -> (range 2 10 2)
              Scala -> Range
              Rust -> std::iter::range

              P.S. И ещё, чем Python «нормальнее» чем Haskell?
              • +1
                В случае ruby есть ещё 2...10, который не включает правую границу.
              • +10
                Начнем с того, что «самый нормальный» язык — это C++, а там в STL полуоткрытые интервалы — стандарт.

                Теперь объяснение, почему так получилось.

                Во-первых, полуоткрытые интервалы — аддитивны. [a, b) плюс [b, c) даст [a, c) — в то время как для закрытых или открытых интервалов пришлось бы исхитряться.

                Во-вторых, у целочисленных полуоткрытых интервалов очень просто вычисляется мощность — это разность границ, и она совпадает с длиной. Для интервалов других типов в формуле появляется +1 или -1 (но только для целых чисел).

                В-третьих, полуоткрытые интервалы хорошо ведут себя при изменении масштаба (точности).

                Так, если у нас есть интервал [01.01.2015 00:00:00.0000, 01.01.2016 00:00:00.0000) — то он представляет собой 1 год независимо от того, какая единица измерения принята за шаг. Как при увеличении, так и при уменьшении точности формата интервал не изменится.

                Если же использовать закрытые интервалы, то они будут выглядеть по-разному:
                [01.01.2015 00:00:00.0000, 31.12.2015 23:59:59.9999] для миллисекундного шага;
                [01.01.2015 00:00:00, 31.12.2015 23:59:59] для секундного шага;
                [01.01.2015, 31.12.2015] для шага в 1 день.

                Отсюда возникает, к примеру, проблема при загрузке через ORM поля enddate из базы, когда в базе используется тип данных, не хранящий время — а в программе хранящий. Требуется либо договариваться, что «на время мы не смотрим», либо каждый раз явно дописывать 23:59:59.9999 к загруженной из БД дате. И то, и другое может оказаться причиной ошибок.
                • +1
                  Ну для итераторов и дат я с этим как бы согласен, но речь шла про генерацию числовых последовательностей из целых чисел (а ведь range делает именно это в Python и потому 2-й вариант не актуален ибо размер массива там легко и так определить, 3й неактуален потому что с целыми числами это не работает, а 1й вариант маловероятен, потому что оперируем мы не множествами, а результатами работы функции range, то есть lists) и тут этот подход делает простейшее действие непонятным.

                  Я вот выше писал — когда мы просим написать человека числа от 1 до 5, какой результат вы ожидаете?
                  • 0
                    Я бы расчитывал на уточняющий вопрос — включительно или нет? Полуоткрытый интервал это по сути удобный копромис.

                    P.S. Haskell -> [2,4..10] это не совсем range, это именно закрытый интервал. Квадратные скобки на это недвусмысленно намекают.

                    P.P.S. Там, где в Python действительно нужны закрытые интервалы — равномерное распределение точек по отрезку — есть numpy.linspace
                    • +1
                      Речь о интервалах в range() была бы оправдана если бы была возможность его использовать и как закрытый и как полуоткрытый (как в Ruby, например, (1..10) или (1...10)), а раз выбрали только один способ, то получилась некрасивая багофича.

                      Про Haskell:
                      это ИМЕННО range и лично я синтаксиса с полуоткрытым интервалом не знаю

                      Про numpy:
                      вот как раз мысли о интервалах надо было оставить именно им и такую неинтуитивную для обычных людей реализацию range разместить в numpy.

                      • 0
                        Синтаксис [] пошел из математики и везде означет закрытый интервал. Делать подругому — верх нелогичности.
                        • 0
                          Я в курсе, я думал речь о терминологии синтаксиса Haskell.
                  • 0
                    От того, чем мы оперируем, важность аддитивности интервалов не меняется — потому что это свойство используется при программировании, а не при выполнении.
                    • 0
                      А в чем такая важность у аддитивности интервалов, которые мы генерируем через range?
                      • +1
                        >>> r = range(0, 10)
                        >>> r
                        range(0, 10)
                        >>> r[:5]
                        range(0, 5)
                        >>> r[5:]
                        range(5, 10)
                  • +2
                    Если попросить человека пронумеровать, скажем, буквы в слове, он и с 0 вряд ли он станет нумеровать. А если сказать ему, что «приём работ до первого мая», скорее всего уточнит: «до первого или по первое?»
                • 0
                  А ещё… про «нормальные» языки:
                  во-первых я попросил ответа от Qbit и применительно к Python, потому что его заявление звучало достаточно пафосно
                  во-вторых я считаю что нет однозначного «нормального» языка, тот же c++ уже имеет очень узкую нишу применения, потому что есть другие языки более высокого уровня позволяют писать программы быстрее и с меньшим количеством ошибок и эти программы ещё и легче в поддержке. Либо предлагаю определить критерии «нормальности» и «ненормальности» языков программирования и посравнивать.
                  • 0
                    Во-первых, дискуссия публичная.
                    Во-вторых, нормальный язык — это распространенный язык. «Самый нормальный» — это наиболее распространенный. А на момент появления функции range в Питоне таким языком был точно не Хаскель и не Паскаль :)
                    • 0
                      Согласен.
      • +1
        Должно быть

        $resList = range(2, 9, 2);

        для того чтобы такой же ответ получился, в Python очень странный range, там левая граница включена, а правая нет.
        • 0
          Чего ж в нем странного? Вы когда говорите что уходите в отпуск — тоже скорее всего утверждаете, что в отпуске до понедельника, подразумевая, что в понедельник следующий уже будете на работе)
          • +1
            Не факт, многие говорят «до конца недели», опять же когда мы говорим про числовые последовательности: «напиши мне числа от 1 до 5», мы ожидаем что напишут «1 2 3 4 5».
          • 0
            В естественном языке многое зависит от контекста и его сравнивать с языком программирования вообще не стоит напрямую. И если вы опрос проведете, то выясните, что в восприятии большинства:

            «Сдача контрольных работ до понедельника» — скорее включает понедельник. При этом другую картину могут показать, например, юристы.
            а
            «отдыхаю до понедельника» — скорее не включает понедельник. При этом, если человеку выходить в середине недели, то случаев «включает» будет озвучено больше.

            Тут влияние логики далеко не 100%.

            Но последовательность пишется исходя из логики, поэтому я согласен с youlose. Просьба «написать список от 1 до 5» даст ответ «1 2 3 4 5».
    • 0
      в php можно похожим образом написать:
      for ($i = 1; $i <= 10; $i++) $resList[] = $i % 2 == 0 ?: $i;
      

      или для наглядности так:
      for ($i = 1; $i <= 10; $i++) $resList[] = ($i % 2 == 0) ?: $i;
      

      И для этого не нужно объявлять переменную в начале
      • +3
        Можно, но в php так никто не пишет, потому как мало читаемо, в питоне привычное дело.
      • +2
        php -r 'for ($i = 1; $i <= 10; $i++) $resList[] = ($i % 2 == 0) ?: $i; print_r($resList);'
        Array
        (
            [0] => 1
            [1] => 1
            [2] => 3
            [3] => 1
            [4] => 5
            [5] => 1
            [6] => 7
            [7] => 1
            [8] => 9
            [9] => 1
        )
        


        как-то не совсем то, что надо получается.
        • НЛО прилетело и опубликовало эту надпись здесь
          • +1
            Прямо ощущается наследие Perl. :)
            • 0
              на Perl так уже >10 лет как не пишут
        • 0
          $resList = array_filter(range(1, 9), 'even');
          • 0
            зачем так усложнять? выше уже написали вполне адекватный вариант:
            php -r 'print_r(range(2, 9, 2));'

            При том, что еще коллбэк even надо будет делать.
            • 0
              Т.е. предыдущий комментарий не был сарказмом?
      • 0
        Если непременно хочется с условием:
        $resList = array_filter(range(1, 9), function($i) { return $i % 2 == 0; });
    • +2
      Можно тоже поучаствовать в этой специальной дисциплине? =)
      for ($i = 1; $i <= 10; $i++, $i % 2 == 0 && $l[] = $i);
      

      Но разумеется писать так в рабочем продукте — фуфу.
      • 0
        Это уже из ряда вопросов: — Опишите код в одну строчку 10 разными способами =)
      • +1
        Ого, я даже не думал, что так можно
    • +1
      Perl.
      my @list = grep {$_ % 2} 1..10 ;
      
  • –13
    > Но в питоне это не работает

    Да щаз же. В Питоне своя тележка прелестных неявных приведений типов. Например:
    >>> 1,0 + 1
    (1, 1)
    
    • +4
      В Питоне действительно есть некоторые неоднозначности, но тем не менее документацию читать надо:

      Note that tuples are not formed by the parentheses, but rather by use of the comma operator. The exception is the empty tuple, for which parentheses are required — allowing unparenthesized “nothing” in expressions would cause ambiguities and allow common typos to pass uncaught.
      • –4
        Вопрос не в выражении tupl-а, а в том, что одиночное число в такой конструкции неявно приводится к tupl-у.
        • +11
          Нет. У вас описан tuple из элементов «0» и «0 + 1».
          Tuple и int, очевидно, не складываются:
          >>> (1,0) + 1
          Traceback (most recent call last):
            File "<stdin>", line 1, in <module>
          TypeError: can only concatenate tuple (not "int") to tuple
          

        • +3
          У "," как у операции самый высокий приоритет, и от того, что вы так поставите пробелы ничего не изменится. Это все равно что жаловатся что 2+2 * 3 равно 8, а не 12.
          • +2
            У + приоритет выше, иначе в данном выражении было бы (1, 0)+1.
          • 0
            Ровно наоборот. Приоритет операторов описан здесь. Описание tuple здесь. В Питоне "," — это не оператор, а часть синтаксиса языка. Если вам удобнее, можете воспринимать её как ключевое слово.
            • 0
              А разве операторы в питоне не являются частью синтаксиса?
            • 0
              "," не оператор в том смысле, что его нельзя например переопределить, но на уровне грамматики языка, которая как раз и определяет приоритетность это вполне себе оператор.
    • +5
      1,0+1 абсолютно аналогично (1,0+1)
      Не вижу тут ничего неявного, так как tuple образует оператор запятая
    • +6
      Вы, скорее всего, хотели написать это:
      >>> 1.0+1
      2.0
      

      С запятой у вас тьюпл из элементов «1» и «1+0», с точкой у вас вещественное число «1.0» и целое «1».
  • +1
    Спасибо за статью, но в вопросе перехода на Python я бы не стал делать столько упора на разницу в синтаксических конструкциях (большую часть можно освоить за день-два), а чуть подробнее рассказал бы о, собственно, том, как на него портировать простейшее веб-приложение, уже имеющееся на php (вот это ваше «nginx + php-fpm -> nginx + uwsgi + uwsgi_python»), т.к. тут имеются более принципиальные различия.
    • 0
      Перейдите с nginx + php-fpm на daemon.io и у вас будут отличия не менее сильные и во многом похожие.
  • +10
    Я уже больше 5 лет программирую на Python. Начать писать Python код легко. Документация обширная, книг море, StackOverflow ответит на большинство вопросов. А вот что было действительно сложно, так это начать писать идиоматический Python код. То что называется «Pythonic code». Например так писать не рекомендуется:
    data = [3, 14, 15, 92, 65, 35]
    for i in range(len(data)):
        print(i, "-", data[i])
    

    Правильнее переписать такой цикл с использованием встроенной функции enumerate(). Рациональное использование генераторов, магических методов, возможностей стандартной библиотеки — всё это приходит только с прочитанными книгами, статьями, и банально, с опытом.

    Мой друг, например, долгое время писал на Python и не знал, что есть стандартный тип set. И чуть было не начал придумывать свой велосипед. Так что вводные статьи для новичков — это хорошо. Но придётся избавляться от привычек, унаследованных от других языков (PHP/Perl/C++/Bash).

    От себя порекомендую:
    • +1
      Или nested for loops с помощью прямого умножения:
      for i in range(10):
          for j in range(10):
              pass
      
      # vs
      for i, j in itertools.product(range(10), range(10))
          pass
      


      Второе вроде бы работает быстрее.
  • +6
    >Когда-то мысль о том, что вложенность кода определяется отступами, казалась мне полным идиотизмом.

    Как же знакомо! Меня это тоже мучало, перед тем как решился перейти на Питон. Сейчас же, наоборот, мысль программировать «со скобками» кажется ужасной.

    Для тех, кто еще сомневается, поверьте, «программирование с отступами» — одна из самых сильных черт Питона, которой нет ни в одном другом (популярном) языке.
    • +9
      По мне так все эти бесконечные разговоры об отступах выеденного яйца не стоят. Мне эта особенность python как никогда не казалось идиотизмом, так и не казалась какой-то чрезвычайно остроумной и гениальной идеей.
      Часто это удобно, в редких случаях, наоборот, гибче было бы со скобками, но по большому счету — абсолютно непринципиально.
      • +4
        О вкусах не спорят, конечно. Для меня, напротив, «программирование с отступами» стало откровением: всегда правильно отформатированный код, отсутствие целого класса ошибок, «визуально» код без скобок гораздо проще читается.
      • 0
        А можно пример? Просто я себя всегда ловлю на мысли о том, что я никогда не пишу:
        while(condition) { do_stuff(); do_another_stuff(); }
        

        Я все равно это разбиваю на три строки с отступами и поэтому не вижу особого смысла еще и скобки ставить, поэтому Python мне был приятен — избавил от постоянной печати точек с запятой и скобок.
        Других примеров надобности скобок, кроме как попытки запихнуть выражение в одну строчку, мне в голову не приходит.
        • 0
          Других примеров надобности скобок, кроме как попытки запихнуть выражение в одну строчку, мне в голову не приходит.

          Смотря где. Например, в конструкторах в качестве параметров всяких колбеков используются функции, которые, если они односложные, компактнее и удобочитаемее записать инлайн с остальными параметрами {param1,param2,function() {alert(«aaa»);}, чем городить каскад, который при должном форматировании выйдет более страшным.

          Из косвенных недостатков: почти все текстовые редакторы, типа Notepad++, умеют скакать по хоткею между парными скобками, подсвечивать границы текущего блока или автоматически выделять текст блока. При этом питоновские индент-блоки они не понимают.
          • 0
            {param1,param2,function() {alert(«aaa»);},

            Ваш пример не совсем показателен, так как:
            map(lambda x: x * x, [1, 2, 3, 4])
            

            Но да, если там будет больше одной инструкции, то принимается. Но лично для меня пример граничит с травмой для читаемости.
        • +1
          Вы вполне можете написать в Python while condition: do_stuff(); do_another_stuff(). Эта часть совершенно не при чём, против могут быть только те, кто либо хочет видеть явные указания на конец (при их наличии выделять блок обычно легче), либо те, кто хочет писать текст со случайными отступами, а то и вовсе без них.
    • +1
      Угу. Навскидку могу вспомнить только Haskell и F#, которые сложно отнести к популярным. Даёшь двумерный синтаксис в массы!
      Что характерно — двое знакомых, которые пришли в IT совсем недавно после совсем непрофильного образования (биофак) и начали с питона, считают такой стиль более удобным и интуитивным, чем скобочки и begin-end'ы, о которых плохие воспоминания остались ещё со школы :)
  • +2
    Оставлю тут. Хорошее видео.

  • +1
    Еще следует добавить что в python нет stitch case, и в python3 отлично работает SQLAlchemy.
  • 0
    def acc(*args, **kwargs):
    total = 0;
    for n in args:

    Семиколонъ после total = 0 лишний-с
  • +3
    Более громоздкое обращение к родительскому методу.

    В Python3:

    class Derived(Base):
        def __init__(self):
            super().__init__()
    

  • 0
    Вы нечесно сравниваете куски кода на python и php. В КДПВ на php — массив, на python — словарь.
  • –5
    У КАЖДОГО ЯЗЫКА СВОИ МИНУСЫ И ПЛЮСЫ
    • +8
      Не кричите, мы и так это подозревали
  • –3
    Было бы лучше написать какие-то неявные моменты, о которые приходится биться собственной головой, а не просто примеры одного кода.

    Что, например будет в результате выполнения такого кода:

    a = {'name': 'Сергей'}
    b = a
    
    a['name'] = 'Петр'
    
    print(b['name'])
    


    Ответ: Петр.

    Странно, да? На PHP мы получим имя «Сергей», так как переменная b будет содержать копию первого массива. А Python тупо сделает ссылку на ту же область в памяти и по сути у вас обе переменные будут управлять одними данными.

    Зачем так сделано для меня загадка, но тупо приходится помнить об этом.

    Python мне действительно нравится своей компактностью, строгостью. Но логика местами у него удивляет не меньше чем на PHP.

    Проблемы отступов не существует. Отступы в 99% процентах случаев автоматически расставляются IDE точно так же, как и в любом другом языке.


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

    Что-то там меня удивляло еще в работе с типами данных…

    А, что если вы хотите сделать многомерный массив. Ну то есть словарь:
    a = {}
    a['test1']['test2'] = 1
    print(a)
    


    Что будет? Правильно, опять ошибка. Сначала нужно определить a['test1'], а потом что-то туда записывать.

    И да, доступ к данным, добавление и удаление, отличается в зависимости от типа. Это очень путает. В списке append, во множестве add. И те же del и remove. Очень странно встретить такое у «серьезного» языка.

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


    Не скажите. В PHP мы привыкли, что порядок уже изначально есть. Мы можем без проблем туда засунуть некий набор пунктов меню и потом также по порядку его вывести. А вот в Python как-то приходится мозг ломать. И делать список отдельный для сохранения порядка. Но список тоже не так прост, так как в него элемент абы как не воткнешь. Если понадобится вдруг воткнуть элемент в середину списка, то придется делать новый список.

    Поэтому при всей красоте языка и «строгости», я был слегка шокирован подобными странностями и слегка разочарован.
    • +9
      Ответ: Петр.
      А вас не смущает, что точно такой ответ будет в Java, JavaScipt, C# и остальных языках, в которых присваивание копирует ссылку а не значения? Для вас это непривычное поведение, но для Python — это совершенно логично, это описано в документации и это поведение сохраняется при вызове функций и методов (аргументы передаются по ссылке, а не по значению).

      А что будет если открыть другой редактор, который случайно вставит вместо пробелов Tab? Правильно, ошибка будет. Придётся искать где это произошло.
      Теоретически — такое возможно. Но Я ни разу с таким не сталкивался. В крайнем случае Python, как воспитанный интерпретатор, выкинет Indentation Error и покажет номер «плохой» строки.

      Что будет? Правильно, опять ошибка. Сначала нужно определить a['test1'], а потом что-то туда записывать.
      Опять же, в JavaScript, в Ruby, и в других современных языках это нормальное поведение. Если очень хочется, то можете использовать класс defaultdict из стандартной библиотеки.

      Не скажите. В PHP мы привыкли, что порядок уже изначально есть. Мы можем без проблем туда засунуть некий набор пунктов меню и потом также по порядку его вывести. А вот в Python как-то приходится мозг ломать. И делать список отдельный для сохранения порядка. Но список тоже не так прост, так как в него элемент абы как не воткнешь. Если понадобится вдруг воткнуть элемент в середину списка, то придется делать новый список.
      Если есть нужда в словаре, который сохраняет порядок, то возьмите OrderedDict. Списки в Python изменяемые. Используйте срезы (slice):
      data = [3, 1, 4, 8, 2]
      data[3:3] = [1, 5] #Вставить два элемента после третьего элемента
      data[-2:-1] = [9] #Заменить предпоследний элемент на девятку
      


      Как Я советовал в своём комментарии выше, не пытайтесь перенести свои привычки из других языков. Python это не PHP и не Java. И если что-то работает не так, как вы привыкли, это не значит, что язык плохой. Просто он другой, он построен на немного других принципах. Но если вы попробуете проникнуться идеями, заложенными в Python, то, думаю, сможете увидеть его изящество, простоту и мощь.
      • +1
        Используйте срезы (slice):

        Как альтернативу можно использовать метод insert, при условии, что необходимо вставить один элемент:
        >>> data = [3, 1, 4, 8, 2]
        >>> data.insert(3, 111)
        >>> data
        [3, 1, 4, 111, 8, 2]
        
      • +2
        Ну вы чего, епрст. Мы какие языки сравниваем? Мы сравниваем PHP, поэтому я привожу примеры из него и именно по тем сложностям, с которыми сам лично столкнулся. Я бы полгода назад очень обрадовался такому комментарию, когда проходил курс по программированию на Python.

        Весь мой комментарий написан с позиции PHP-разработчика. Это не плохо и не хорошо, а банальный факт.

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

        И если уж речь о привычках и вы опытный специалист, то может объясните мне в чем прикол при присваивании просто передавать ссылку на данные, а не делать сразу их копию? Как-то это используется на практике?
        • 0
          Как позал пример Rust — копирование редкая операция. Обычно или ссылка, или перемещение. Создание второй ссылки вместо полного копирования это просто особенность. И, честно говоря, пока ни разу за свою практику не пользовался deepcopy и не нарывался на непредвиденное поведение. Хотя на PHP писал одно время.
          • 0
            Если знать про эту особенность, то да, скорее всего это не будет вызывать сложностей с некоторой практикой.
        • +1
          А насколько глубоко делать копию? Наверное, копировать только один уровень — это тоже нелогично, да? Значит, копируем все рекурсивно. Стоп, а что делать с циклическими ссылками?

          А что делать, если на некоторой глубине встретится объект-синглтон? Его, наверное, нельзя копировать…

          В итоге и приходим к тому, что объекты проще всегда копировать по ссылке. Это — общее правило для всех популярных динамически типизированных языков за исключением PHP.
          • 0
            В идеале делать нужно ссылку, а в случае модификации — копию данных.
            А если все копировать всегда рекурсивно, то откуда вообще могут взяться циклические ссылки?

            Объект-синглтон где-то в глубине — это тоже меня озадачивает, тем более, что это не тип данных. И по логике в этом случае должна быть ошибка, раз мы пытаемся скопировать то, что нельзя скопировать.

            Но да ладно. Ссылки — это тоже хорошо в принципе, если точно о них знаешь.
            • 0
              А если все копировать всегда рекурсивно, то откуда вообще могут взяться циклические ссылки?
              Потому что копирование ссылки тоже нужно, без него в ООП сложно. А циклические ссылки возникают естественным образом, к примеру, в MVC.
              • 0
                Я про то, что если мы все копируем, то ссылки, по идее, вообще не используются. Значит и цикла возникнуть не может. Если не рассматривать проблему переполнения памяти копиями, то в целом все должно работать без проблем. Ну да ладно.

                Но в работе со ссылками нужно просто привыкнуть оперировать конечными данными, а промежуточные расчеты делать отдельно. Мне даже нравится такой подход.
                • 0
                  Не бывает так, что «мы все копируем». Зачастую объекты, ссылающиеся друг на друга, попросту нужны.
    • 0
      Ответ: Петр.
      Странно, да?


      Разумеется, странно, если вы не читали документацию. В питоне все типы делятся на два — mutable, immutable (числа, строки, таплы, фрозенсеты). Причем операция присваивания всегда создает ссылку, независимо от типа. Различия проявляются потом, когда вы явно пытаетесь изменить переменную.

      a = 1234567
      b = a
      
      a == b # True
      a is b # True - ссылаются на один и тот же объект
      
      b = 1234567
      a == b # True
      a is b # False - ссылаются на разные объекты
      
      

      Числа/строки/таплы/фрозенсеты нельзя менять непосредственно. Никак. Строки поддерживают выборку по индексу, но изменить себя не дадут:

      s = 'Hello'
      s[1] # e
      s[1] = 't' # TypeError: 'str' object does not support item assignment
      

      С другой стороны, списки, словари и оставшиеся объекты — mutable. И т.к. операция присваивания в питоне работает везде одинаково (она просто создает ссылку на объект) — вы получаете то, что получаете.
      • +6
        В порядке граммар-нацизма: может быть, вместо новодельной транслитерации tuple = «тапл» использовать традиционное «кортеж»? В русской информатике и математике этот термин уже полвека есть, если не больше.
    • 0
      В питоне есть разделение на типы — изменяемые объекты (подавляющее большинство) и неизменяемые значения (меньшинство).
      Значения — числа, строки, кортежи.
      Объекты всегда передаются по ссылке. На самом деле, значения тоже, но операции изменения значений (оператор += и т.п.) реализованы как присваивание нового значения, а старое остаётся старым.

      Это добавляет головную боль в 3 местах:
      — умножение списков: [ Foo(), Bar() ] * 3 создаёт список из 6 ссылок на два объекта
      — дефолтные аргументы функций:
      def foo(bar = Bar()) :
        bar.update() 
      

      в функцию foo() будет попадать не новый экземпляр, а один и тот же, чьё состояние сохранится между вызовами
      — статические члены-данные классов:
      class Foo :
        bar = Bar()
        xyz = 123
      
      f = Foo() # f.xyz = 123, f.bar = Foo.bar
      g = Foo() # g.xyz = 123, g.bar = Foo.bar
      Foo.bar.update() # ой
      

      Это не только питонов косяк, просто в питоне с операцией клонирующего присваивания сложности (есть модуль pickle и в нём функции поверхностного и глубокого копирования типов, причём настраиваемые).
      • +1
        Зачем сразу pickle — есть copy. docs.python.org/3/library/copy.html#module-copy
        • 0
          Да, с пиклем я погорячился. Обычно просто не наступаю на эти грабли, поскольку хорошо изучил их наличие. А вот правильно решать задачу копирования — навскидку и не вспомнил. Конечно же, copy() и deppcopy().
      • 0
        Да, спасибо, я разобрался с этим потом. Я написал для тех, кто еще не прикасался к этому, чтобы знали куда смотреть.
        Хотя такие приколы со ссылками мне до сих пор не нравятся. Я даже не знаю точно в итоге где получу ссылку, а где копию данных.
    • 0
      Но список тоже не так прост, так как в него элемент абы как не воткнешь. Если понадобится вдруг воткнуть элемент в середину списка, то придется делать новый список.

      Элемент в список можно вставить в любом месте:
      >>> list=[1, 2, 3, 4, 5]
      >>> list.insert(2, 123)
      >>> list
      [1, 2, 123, 3, 4, 5]
      
      • 0
        Спасибо! Буду в курсе. Проглядел такую возможность.
  • 0
    deleted
  • 0
    Со строгой типизацией все совсем неоднозначно (даже помимо булевых констант), например:

    >>> print '25' * 5
    2525252525

    • +4
      Вполне однозначно, и типизация тут ни при чем:

      The * (multiplication) operator yields the product of its arguments. The arguments must either both be numbers, or one argument must be an integer (plain or long) and the other must be a sequence. In the former case, the numbers are converted to a common type and then multiplied together. In the latter case, sequence repetition is performed; a negative repetition factor yields an empty sequence.
    • 0
      А что вам кажется неодназначным? Оператор * для строк — это повторение. Что вы запросили у интерпретатора (повтори мне эту строку 5 раз) — то и получили.
      • +1
        Неоднозначным мне кажется то, что в других языках со строгой типизацией этот код вызовет закономерную ошибку, а в питоне это очередной «специальный случай», который нужно иметь ввиду и TypeError'om его не поймать.
        • 0
          Выше вам уже ответили. Для любых последовательностей (коими являются и строки, и списки) оператор * означает повторение. Это не «специальный случай», а задокументированная особенность ЛЮБЫХ последовательностей. Я, однако, не вижу ей особого применения.
          А вот оператор + в вашем примере уже вызовет ошибку.
        • 0
          В том же C++ никто не мешает перегрузить оператор * для std::string… И если это не сделано в STL по умолчанию — это еще не означает, что оператора * в строго типизированном языке не может существовать.
    • +1
      Тут я соглашусь, что все довольно логично. По сути значение строки «25» оказалось таким случайно.

      >>> «Привет! » * 2
      Привет! Привет!

      Это весьма ожидаемо.
  • +6
    Хочу поделиться впечатлениями о переходах. Я прошел путь Perl > PHP > Python > Scala > Go > Haskell. На каждом из языков писал серьезные проекты. После проекта на Scala и обчитавшись про DDD, я вообще не понимал, как же я раньше писал без immutability и сильной системы типов.

    Попробуйте Haskell, это мощный, красивый и лаконичный язык. С ним не так сложно начать, экосистема (библиотеки, утилиты, пакеты), в том числе для web разработки уже есть. Сообщество хаскелистов хоть и не многочисленно, но сильное и активное.
    • 0
      Haskell хорошо, но по-моему совершенно не пригоден для промышленного программирования. В этом направлении если и отдавать преимущество функциональщине, то тогда Scala.
      Забавный у вас переход с Python-а в функциональщину, потом в Go и возврат к FP :)
      • 0
        Заказчик выбирал почти всегда выбирал на чем писать. С Haskell — предоставился шанс начать новый проект.
        Как по мне — Scala очень хороша, но:
        • многословнее
        • требует JVM
        • компилируется медленнее
        • с существующими IDE у меня не заладилось, либо тормозят, либо убоги как Eclipse

        Haskell в этом плане имеет все преимущества перед Scala :). Конечно-же есть и небольшие недостатки типа импортов, но я их не замечаю.
        • 0
          Glueon, Позвольте поинтересоваться, «промышленное программирование» это какое? К чему Haskell не пригоден? :)
          • 0
            Просто Haskell менее популярен чем Java, поэтому возможно заказчик будет его избегать, так как систему написанную на таком языке мало кто сможет поддерживать, в отличии от системы написаной там… на PHP :(
            Новорят же «в промышленных масштабах». Поэтому промышленное программирования для меня — это поставленная на поток разработка для разных заказчиков. Свой продукт можете и на Haskell-е писать, а вот разработка «на сторону» на таком языке может быть неудобством для заказчика, не смотря на все его прелести.
            Сам пока пишу для себя на Scala, а Java не люблю из-за многословности, поэтому Scala немного начинает мутить.
            • 0
              Haskell, конечно же, не самый популярный, но интерес к нему растет. Люди пишут серьезные фреймворки, создают компании, выпускают продукты (http://fpcomplete.com, yesodweb.com, github.com/scotty-web/scotty). Сообщество растет.

              ИМХО, на сторону тоже можно вести разработку. Есть популярные фреймворки и библиотеки. Освоить их не так сложно. Знаю компанию которая решилась на переход и переучивание с PHP на Haskell :) (http://engineering.imvu.com/2014/03/24/what-its-like-to-use-haskell/).

              С одной стороны на Haskell не так много работы, а значит есть из кого выбирать. С другой — Haskell хороший фильтр качественных кадров.
  • +5
    В питоне есть одни интересные грабли, которых я не встречал в других языках: выражения x = x + y и x += y могут быть неидентичны. Пример:

    def func1(l):
        l = l + [None]
        return l
    
    def func2(l):
        l += [None]
        return l
    
    my_list = [1, 2, 3]
    
    # Казалось бы, две идентичные функции
    L1 = func1(my_list)
    L2 = func2(my_list)
    
    print(L1 == L2)  # True
    # И даже результаты равны. А подвох в том, что
    print(my_list)  # [1, 2, 3, None]
    

    Проблема в том, что оператор += для списка неявно обрабатывается как list.extend(), который, в свою очередь, изменяет текущий список, а не создает новый. Это происходит из-за того, что питон позволяет перегружать не только оператор + (__add__), но и оператор += в отдельности (__iadd__). Для списков это сделано из-за скорости — extend работает быстрее. Разумеется, это есть в документации. Но наступить на эти грабли крайне легко.
    • 0
      Честно говоря — не понял в чем подвох… Вывел L1, L2, my_list — имеют одно и то-же значение… Что не так, Core2Duo? P.S.: я не волшебник, я только учусь…
      • 0
        Подвох в том, что func1 не имеет побочных эфектов(my_list остается нетронутым), а func2 имеет(дописывает в my_list None). Ну и, соответственно, func1 возвращает новый список, а func2 возвращает измененную версию my_list(L2 и my_list это два имени одного списка).
        • 0
          О! Только это заметил. Спасибо!
          • 0
            Если что, то для «визуальной» проверки «это один объект или нет» можно использовать id:
            def func1(l):
                l = l + [None]
                return l
            
            def func2(l):
                l += [None]
                return l
            
            my_list = [1, 2, 3]
            print(id(my_list))
            
            # Казалось бы, две идентичные функции
            L1 = func1(my_list)
            print(id(L1))  # != id(my_list)
            L2 = func2(my_list)
            print(id(L2))  # == id(my_list)
            </code>
            
            Для программной больше подходит оператор ́<code>is</code>:<source lang="Python">
            <…>
            
            print(L1 is my_list)  # False
            print(L2 is my_list)  # True
            


            : он выдаёт True только если сравниваемые объекты находятся по одному адресу (== сравниваемые ссылки ссылаются на один объект: в Python все объекты всё равно храняться по ссылкам).

            Собственно, функция id печатает адрес объекта, а L1 is my_list — то же, что и id(L1) == id(my_list).
  • +2
    Оба языка хороши
  • +2
    То есть как это «нет абстрактных классов»? Вот же.

    import abc
    
    class MyABC(metaclass=abc.ABCMeta):
    
        @abc.abstractmethod
        def myfunc(self):
            pass
    


    И да, как уже написали выше, совершенно не раскрыта тема удивительного мира декораторов. И генераторов (yield).
    • +1
      Обновил статью. Но про генераторы не писал, ибо в PHP 5.5 они есть. И примерно понятно откуда они слизаны.
      • 0
        Вот тут есть источники вдохновения.
  • 0
    А почему про Werkzeug не упомянули? Один из самых клёвых веб-фреймворков для питона же, со всеми нужными батарейками (особенно отладчик там кайфовый, который даёт REPL прямо в браузере).
  • +2
    Хотелось бы такую же статью про Ruby с PHP.
  • 0
    Отступы вместо операторных скобок по началу принять трудно, но привыкаешь быстро.
  • 0
    Когда меня спрашивают что лучше php/python (в рамках веб программирования) я всегда овтечаю это дело вкуса, либо конкретного выбора карьерного роста. А если это не важно, то лучше писатьна чем пишешь(допустим php), и спокойно развиваться. Сверх преимуществ от перехода на python конечно же нет, а тех кто реально хочет заморочится новым, интересным, мощным я советую go или hack(тут вобще легко для php ника).
    PS это не значит что статья не нужно, еще как нужна. Ведь каждый день кто-то хочет попробовать, тут отличный первый шажочек описан.
    • 0
      Если вы работаете на себя то конечно не важно. Но если вы хотите занять конкретное место в глоьальном рынке, то очень даже существенное. Например Google и Yandex на PHP не пишут, а на Python пишут и вероятность попасть к ним на работу резко снижается. Да, Facebook и Badoo пишут на PHP, но на Python пишут гораздо большее число разных известных компаний. Ну и к тому же на питоне пишут не только web, взять например OpenStack.
      • +1
        Так я же о том и написал, что если есть желание перейти на работу в определенные компании, делать себе карьеру, то да. Но и с php не останешься без работы, ну и без денег.
        Новые вакансии есть и там и там.
        Короче говоря, ваш комментарий не спорит с моим, просто чуть раскрыл тему по карьере в «компаниях мечты».
        Лично мен Python нравится, может даже в чем то немного больше. Но php удобнее, пока не вижу смысла переходить с него(лично для себя). Гугл мне не интересен, как и в целом работа программистом в большущих компаниях. А если стукнеть желания поработать в стартапе, то их на php тоже достаточно.
        А из новых и интересных технологий, как отмечал ранее, я смотрю на hack и go, еще балуюсь с io.js, тоже приятная штука.
        PS а срач что круче php или python считаю глупым, ± они равны в целом и общем, а все зависит от конкретного выбора конкретного программиста.
      • 0
        Яндекс на PHP пишет — https://yandex.ru/jobs/vacancies/dev/phpdev_market/.

        Думаю, и тот и тот язык имеет свой рынок, и, как отметил neuotq, работа есть для всех.
        Другой вопрос, что у каждого языка своя область применения.
  • +1
    (кстати, PHP унаследовал это от Perl, а тот — от баш)

    В Perl $ используется, как обозначение скаляра, по тому, что похоже на s (scalar). По аналогии с @, который похож на a (array) или % для хэшей, который похож на пару «ключ — значение».

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

Самое читаемое Разработка