Изучение Python из Ruby; Различия и сходства
Я очень хорошо знаю Руби. Я считаю, что мне, возможно, сейчас придется изучать Python. Для тех, кто знает обоим, какие понятия похожи между двумя, а какие разные?
Я ищу список, подобный праймеру, который я написал для Learning Lua для JavaScript-пользователей: простые вещи, такие как простейшие значения и конструкции цикла; имя nil
в Python, и какие значения считаются "правдивыми"; идиоматично использовать эквивалент map
и each
, или mumble somethingaboutlistcomprehensions mumble the norm?
Если я получаю множество ответов, я с удовольствием объединяю их в вики сообщества. Или вы все можете сражаться и грести друг от друга, чтобы попытаться создать один полный список.
Изменить. Чтобы быть ясным, моя цель - "правильный" и идиоматический Python. Если есть эквивалент Python inject
, но никто не использует его, потому что есть лучший/другой способ достижения общей функциональности итерации списка и накопления результата на этом пути, я хочу знать, как вы это делаете. Возможно, я обновлю этот вопрос со списком общих целей, как вы их достигнете в Ruby и спросите, что эквивалентно в Python.
Ответы
Ответ 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 переменные экземпляра являются закрытыми по умолчанию.