Подтвердить что ты не робот

Изучение Python из Ruby; Различия и сходства

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

Я ищу список, подобный праймеру, который я написал для Learning Lua для JavaScript-пользователей: простые вещи, такие как простейшие значения и конструкции цикла; имя nil в Python, и какие значения считаются "правдивыми"; идиоматично использовать эквивалент map и each, или mumble somethingaboutlistcomprehensions mumble the norm?

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

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

4b9b3361

Ответ 1

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

  • У Ruby есть блоки; Python не делает.

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

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

  • У 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 также предоставляет аналогичные карты.

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

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

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

  • Ruby поддерживает только одно наследование. Если вам нужно имитировать множественное наследование, вы можете определить модули и использовать mix-ins, чтобы вытащить методы модуля в классы. Python поддерживает множественное наследование, а не модули-модули.

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

    collection.each do |value|
      ...
    end
    

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

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

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

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

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

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

Ответ 2

Я только что провел пару месяцев, изучая Python после 6 лет Ruby. На самом деле не было большого сравнения для этих двух языков, поэтому я решил сам написать и написать. Теперь речь идет главным образом о функциональном программировании, но поскольку вы упоминаете метод 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(), которая возвращает true для палиндромов), вам нужно всего лишь одно понимание списка:

    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])]
    

Ответ 3

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

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

Ответ 4

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

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

Что касается цикла: у вас есть for, который работает с итерируемым (! no счетом) и while, что делает то, что вы ожидаете. Theer намного мощнее благодаря обширной поддержке итераторов. Не только почти все, что может быть итератором вместо списка, является итератором (по крайней мере, в Python 3 - в Python 2, у вас есть оба, а по умолчанию - список, к сожалению). Множество инструментов для работы с итераторами - zip повторяет любое количество итераций параллельно, enumerate дает вам (index, item) (на любом итеративном, а не только на списках), даже нарезая abritary (возможно, большие или бесконечные) итерации! Я обнаружил, что они делают намного больше циклов, намного проще. Разумеется, они прекрасно интегрируются со списком, выражениями генератора и т.д.

Ответ 5

В 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 переменные экземпляра являются закрытыми по умолчанию.