Изучение Python из Ruby;Различия и сходства - PullRequest
127 голосов
/ 22 января 2011

Я очень хорошо знаю Руби.Я считаю, что мне, возможно, придется изучать Python в настоящее время.Для тех, кто знает и то, и другое, какие понятия похожи между ними и чем отличаются?

Я ищу список, похожий на учебник, который я написал для Изучение Lua для JavaScripters :простые вещи, такие как значение пробелов и циклические конструкции;имя nil в Python и какие значения считаются «правдивыми»;идиоматично ли использовать эквивалент map и each, или бормотать что-то о списке компромиссов бормотать норма?

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

Редактировать : Чтобы быть ясным, моя цель - «правильный» и идиоматический Python.Если есть Python-эквивалент inject, но никто не использует его, потому что есть лучший / иной способ достижения общей функциональности итерации списка и накопления результата по пути, я хочу знать, как вы делаете вещи.Возможно, я обновлю этот вопрос списком общих целей, как вы их достигнете в Ruby, и задам вопрос, каков эквивалент в Python.

Ответы [ 5 ]

150 голосов
/ 22 января 2011

Вот некоторые ключевые отличия для меня:

  1. В Ruby есть блоки;Python не.

  2. Python имеет функции;Руби нет.В Python вы можете взять любую функцию или метод и передать их другой функции.В Ruby все является методом, и методы не могут быть переданы напрямую.Вместо этого вам нужно обернуть их в Proc's, чтобы передать их.

  3. Оба Ruby и Python поддерживают замыкания, но по-разному.В Python вы можете определить функцию внутри другой функции.Внутренняя функция имеет доступ для чтения к переменным из внешней функции, но не для записи.В Ruby вы определяете замыкания, используя блоки.Замыкания имеют полный доступ для чтения и записи к переменным из внешней области видимости.

  4. В Python есть списочные выражения, которые довольно выразительны.Например, если у вас есть список чисел, вы можете написать

    [x*x for x in values if x > 15]
    

    , чтобы получить новый список квадратов со всеми значениями, превышающими 15. В Ruby вам нужно написать следующее:

    values.select {|v| v > 15}.map {|v| v * v}
    

    Код Ruby не выглядит таким компактным.Это также не так эффективно, поскольку сначала он преобразует массив значений в более короткий промежуточный массив, содержащий значения больше 15. Затем он берет промежуточный массив и генерирует окончательный массив, содержащий квадраты промежуточных элементов.Промежуточный массив затем выбрасывается.Таким образом, Ruby в процессе вычисления имеет 3 массива в памяти;Python нуждается только во входном списке и результирующем списке.

    Python также предоставляет аналогичные описания карт.

  5. Python поддерживает кортежи;Руби нет.В Ruby вы должны использовать массивы для имитации кортежей.

  6. Ruby поддерживает операторы switch / case;Python не поддерживает.

  7. Ruby поддерживает стандартный троичный оператор expr ? val1 : val2;Python не поддерживает.

  8. Ruby поддерживает только одно наследование.Если вам нужно имитировать множественное наследование, вы можете определить модули и использовать дополнения для переноса методов модуля в классы.Python поддерживает множественное наследование, а не смешивание модулей.

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

    collection.each do |value|
      ...
    end
    

    Блок работает очень похоже на функцию, передаваемую в collection.each.Если бы вы делали то же самое в Python, вам нужно было бы определить именованную внутреннюю функцию и затем передать ее в коллекцию каждому методу (если список поддерживал этот метод):

    def some_operation(value):
      ...
    
    collection.each(some_operation)
    

    That not 'Течет очень хорошо.Таким образом, обычно в Python используется следующий нефункциональный подход:

    for value in collection:
      ...
    
  10. Безопасное использование ресурсов между двумя языками весьма различно.Здесь проблема заключается в том, что вы хотите выделить некоторый ресурс (открыть файл, получить курсор в базе данных и т. Д.), Выполнить некоторую произвольную операцию с ним, а затем закрыть его безопасным способом, даже если возникает исключение.

    В Ruby, поскольку блоки очень просты в использовании (см. # 9), вы обычно кодируете этот шаблон как метод, который принимает блок для произвольной операции над ресурсом.

    В Python,передача функции для произвольного действия немного сложнее, поскольку вы должны написать именованную внутреннюю функцию (см. # 9).Вместо этого Python использует оператор with для безопасной обработки ресурсов.См. Как правильно очистить объект Python? для получения более подробной информации.

27 голосов
/ 22 января 2011

Я только пару месяцев изучал Python после 6 лет работы с Ruby.Там действительно не было большого сравнения для этих двух языков, поэтому я решил придумать и написать один сам.Теперь в основном касается функционального программирования, но, поскольку вы упоминаете метод inject Руби, я предполагаю, что мы находимся на одной волне.

Надеюсь, это поможет: Уродство Python

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

  • Всефункциональные возможности программирования, которые вы используете в Ruby, есть в Python, и это даже проще.Например, вы можете отобразить функции точно так, как вы ожидаете:

    def f(x):
        return x + 1
    
    map(f, [1, 2, 3]) # => [2, 3, 4]
    
  • В Python нет метода, который действует как each.Поскольку вы используете each только для побочных эффектов, в Python эквивалентом является цикл for:

    for n in [1, 2, 3]:
        print n
    
  • Понимание списка отлично, когда а) вам приходится иметь дело с функциями и объектомколлекции вместе и б) когда вам нужно перебрать, используя несколько индексов.Например, чтобы найти все палиндромы в строке (при условии, что у вас есть функция p(), которая возвращает истину для палиндромов), все, что вам нужно, это понимание одного списка:

    s = 'string-with-palindromes-like-abbalabba'
    l = len(s)
    [s[x:y] for x in range(l) for y in range(x,l+1) if p(s[x:y])]
    
10 голосов
/ 22 января 2011

Мое предложение: не пытайтесь изучать различия.Узнайте, как подойти к проблеме в Python.Так же, как есть подход Ruby к каждой проблеме (который работает очень хорошо, учитывая ограничения и сильные стороны языка), есть подход Python к этой проблеме.они оба разные.Чтобы извлечь максимальную пользу из каждого языка, вы действительно должны выучить сам язык, а не только «перевод» с одного на другой.

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

8 голосов
/ 22 января 2011

Я знаю немного Ruby, но вот несколько пунктов о том, что вы упомянули:

  • nil, значение, указывающее на отсутствие значения, будет None (обратите внимание, чтовы проверяете это как x is None или x is not None, а не с == - или путем принуждения к логическому значению, см. следующий пункт).
  • None, числа нулевого esque (0, 0.0, 0j (комплексное число)) и пустые коллекции ([], {}, set(), пустая строка "" и т. Д.) Считаются ложными, все остальное считается правдивым.
  • Для побочных эффектов, (for -) явно зацикливается.Для генерации новой связки без побочных эффектов используйте списки (или их родственники - выражения генераторов для ленивых одноразовых итераторов, определения типа dict / set для указанных коллекций).

Относительно зацикливания: У вас есть for, который работает с итерацией (! Без подсчета), и while, который делает то, что вы ожидаете.Фромер гораздо более мощный, благодаря обширной поддержке итераторов.Не только почти все, что может быть итератором, а не списком, является итератором (по крайней мере, в Python 3 - в Python 2 у вас есть оба, и, к сожалению, по умолчанию это список).Существует множество инструментов для работы с итераторами - zip выполняет итерацию любого количества параллельных элементов, enumerate дает вам (index, item) (для любой итеративный, а не только для списков), даже вырезая абритарию (возможнобольшие или бесконечные) итерируемые!Я обнаружил, что это значительно упрощает многие циклические задачи.Излишне говорить, что они прекрасно интегрируются со списками, генераторами выражений и т. Д.

6 голосов
/ 22 января 2011

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

В Python методы - это просто особый класс атрибута: исполняемый.

Так, например:

>>> class foo:
...     x = 5
...     def y(): pass
... 
>>> f = foo()
>>> type(f.x)
<type 'int'>
>>> type(f.y)
<type 'instancemethod'>

Это различие имеет много последствий, как, например, то, что ссылка на f.x относится к объекту метода, а не к его вызову. Кроме того, как вы можете видеть, по умолчанию f.x является общедоступным, тогда как в Ruby переменные экземпляра по умолчанию являются частными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...