Существует много дискуссий о Python против Ruby, и я все нахожу их совершенно бесполезными, потому что все они оборачиваются тем, почему функция X отстой в языке Y, или в том, что язык Y не имеет X, хотя на самом деле это так. Я также точно знаю, почему я предпочитаю Python, но это тоже субъективно, и не поможет никому выбрать, так как у них могут не быть те же вкусы в разработке, что и у меня.
Поэтому было бы интересно перечислить различия объективно. Так что нет "лямбды Питона отстой". Вместо этого объясните, что могут делать лямбды в Ruby, а Python - нет. Нет субъективности. Пример кода это хорошо!
У меня нет нескольких различий в одном ответе. И проголосуйте за тех, кого вы знаете, правильно, и за тех, кого вы знаете неправильно (или субъективно). Также различия в синтаксисе не интересны. Мы знаем, что Python делает с отступом то, что Ruby делает с скобками и концами, и что в Python @ называется self.
ОБНОВЛЕНИЕ: Теперь это вики сообщества, поэтому мы можем добавить большие различия здесь.
У Ruby есть ссылка на класс в теле класса
В Ruby у вас есть ссылка на класс (self) уже в теле класса. В Python у вас нет ссылки на класс, пока не закончится построение класса.
Пример:
class Kaka
puts self
end
self в этом случае является классом, и этот код будет выводить «Kaka». Невозможно распечатать имя класса или каким-либо другим способом получить доступ к классу из тела определения класса в Python (вне определения метода).
Все классы изменчивы в Ruby
Это позволяет вам разрабатывать расширения для основных классов. Вот пример расширения рельсов:
class String
def starts_with?(other)
head = self[0, other.length]
head == other
end
end
Python (представьте, что не было никакого ''.startswith
метода):
def starts_with(s, prefix):
return s[:len(prefix)] == prefix
Вы можете использовать его в любой последовательности (не только в строках). Для того , чтобы использовать его , вы должны импортировать его в явном виде , например, from some_module import starts_with
.
Ruby имеет Perl-подобные функции сценариев
В Ruby есть регулярные выражения первого класса, переменные $, переменные циклические строки ввода awk / perl и другие функции, которые делают его более подходящим для написания небольших сценариев оболочки, которые разбирают текстовые файлы или действуют как связующий код для других программ.
Руби имеет продолжение первого класса
Благодаря заявлению callcc. В Python вы можете создавать продолжения различными способами, но в язык не встроена поддержка.
Рубин имеет блоки
С помощью оператора "do" вы можете создать многострочную анонимную функцию в Ruby, которая будет передана в качестве аргумента в метод перед do и будет вызываться оттуда. В Python вы бы вместо этого делали это, передавая метод или используя генераторы.
Рубин:
amethod { |here|
many=lines+of+code
goes(here)
}
Python (блоки Ruby соответствуют различным конструкциям в Python):
with amethod() as here: # `amethod() is a context manager
many=lines+of+code
goes(here)
Или
for here in amethod(): # `amethod()` is an iterable
many=lines+of+code
goes(here)
Или
def function(here):
many=lines+of+code
goes(here)
amethod(function) # `function` is a callback
Интересно, что в Ruby оператор удобства для вызова блока называется «yield», который в Python создаст генератор.
Рубин:
def themethod
yield 5
end
themethod do |foo|
puts foo
end
Python:
def themethod():
yield 5
for foo in themethod():
print foo
Хотя принципы разные, результат поразительно похож.
Ruby легче поддерживает функциональный стиль (труба)
myList.map(&:description).reject(&:empty?).join("\n")
Python:
descriptions = (f.description() for f in mylist)
"\n".join(filter(len, descriptions))
Python имеет встроенные генераторы (которые используются как блоки Ruby, как отмечено выше)
Python имеет поддержку генераторов на языке. В Ruby 1.8 вы можете использовать модуль генератора, который использует продолжения для создания генератора из блока. Или вы можете просто использовать блок / proc / lambda! Более того, в Ruby 1.9 Fibres являются и могут использоваться как генераторы, а класс Enumerator является встроенным генератором 4
docs.python.org имеет этот пример генератора:
def reverse(data):
for index in range(len(data)-1, -1, -1):
yield data[index]
Сравните это с приведенными выше примерами блоков.
Python имеет гибкую обработку пространства имен
В Ruby, когда вы импортируете файл с помощью require
, все вещи, определенные в этом файле, окажутся в вашем глобальном пространстве имен. Это вызывает загрязнение пространства имен. Решением для этого являются модули Rubys. Но если вы создаете пространство имен с модулем, то вы должны использовать это пространство имен для доступа к содержащимся классам.
В Python файл является модулем, и вы можете импортировать содержащиеся в нем имена с помощью from themodule import *
, тем самым загрязняя пространство имен, если хотите. Но вы также можете импортировать только выбранные имена с помощью from themodule import aname, another
или вы можете просто import themodule
и затем получить доступ к именам с помощью themodule.aname
. Если вам нужно больше уровней в вашем пространстве имен, вы можете иметь пакеты, которые являются каталогами с модулями и __init__.py
файлом.
Python имеет строки документации
Строки документации - это строки, которые присоединяются к модулям, функциям и методам и могут быть проанализированы во время выполнения. Это помогает создавать такие вещи, как команда справки и автоматическое документирование.
def frobnicate(bar):
"""frobnicate takes a bar and frobnicates it
>>> bar = Bar()
>>> bar.is_frobnicated()
False
>>> frobnicate(bar)
>>> bar.is_frobnicated()
True
"""
Эквивалент Ruby похож на javadocs и расположен над методом, а не внутри него. Они могут быть извлечены во время выполнения из файлов, используя пример метода Method # source_location 1.9
Python имеет множественное наследование
Ruby этого не делает («специально» - см. Веб-сайт Ruby, смотрите здесь, как это делается в Ruby ). Он повторно использует концепцию модуля как тип абстрактных классов.
У Python есть списки / дикты
Python:
res = [x*x for x in range(1, 10)]
Рубин:
res = (0..9).map { |x| x * x }
Python:
>>> (x*x for x in range(10))
<generator object <genexpr> at 0xb7c1ccd4>
>>> list(_)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Рубин:
p = proc { |x| x * x }
(0..9).map(&p)
Python 2.7+ :
>>> {x:str(y*y) for x,y in {1:2, 3:4}.items()}
{1: '4', 3: '16'}
Рубин:
>> Hash[{1=>2, 3=>4}.map{|x,y| [x,(y*y).to_s]}]
=> {1=>"4", 3=>"16"}
Python имеет декораторы
В Ruby также можно создавать вещи, похожие на декораторы, и можно также утверждать, что они не так необходимы, как в Python.
Синтаксические различия
Ruby требует "end" или "}", чтобы закрыть все свои области, в то время как Python использует только пробелы. В Ruby недавно предпринимались попытки разрешить отступы только в пробелах http://github.com/michaeledgar/seamless