Большую часть различий между Ruby и Python можно увидеть в цикле for.
В Python есть оператор for. Объект сообщает, как взаимодействовать, а тело цикла for обрабатывает то, что возвращает объект.
Руби наоборот. В Ruby для себя (через каждого) есть метод объекта. Вызывающий объект передает тело цикла for этому методу.
В идиоме языка Python объектная модель подвержена циклам for. В Ruby циклы for подчиняются объектной модели.
То есть в Python, если вы хотите настроить процесс итерации, вы можете позволить объекту сообщить интерпретатору, как выполнять итерацию:
class Stuff:
def __init__(self):
self.a_list = [1,2,3,4]
self.position = 0
def __next__(self):
try:
value = self.a_list[self.position]
self.position += 1
return value
except IndexError:
self.position = 0
raise StopIteration
def __iter__(self):
return self
Здесь Stuff используетnextиiterМагический метод делает себя итерируемым (становится итерируемым объектом).
for data in Stuff():
print(data)
Однако при использовании Ruby вы делаете прямо противоположное. Вы создаете for как метод, который получает код (тело) для запуска. Ruby помещает процедурный код в блоки кода, чтобы их можно было использовать для передачи.
Затем в каждом методе используйте yield для взаимодействия с блоком кода, передавая значение в блок кода, чтобы сделать то, что вам нужно (блок кода является неявным параметром для любого метода).
Если мы перепишем приведенный выше код, он будет выглядеть так:
class Stuff
def initialize
@a_list = [1, 2, 3, 4]
end
def each
for item in @a_list
yield item
end
end
end
Используйте каждый для повторения:
Stuff.new().each do |item|
puts item
end
Вместо передачи данных в цикл for (Python) передайте код цикла в данные (Ruby).
Но разница гораздо больше:
Python создает for-like конструкции для всех видов обработки, Ruby помещает обработку данных в методы.
Хороший код Python реализует отображение и фильтрацию с использованием списков и словарей, которые по своей сути имеют ту же семантику, что и for/iteration.
In [2]: [item for item in Stuff()]
Out[2]: [1, 2, 3, 4]
In [3]: [item for item in Stuff() if item % 2 == 0]
Out[3]: [2, 4]
Ruby продолжает использовать метод «сначала метод», и в дополнение к каждому методу существует ряд новых методов, обычно используемых для работы с коллекциями, а именно:
class Stuff
...
def select
out = []
each do |e|
# If block returns truthy on e, append to out
if yield(e)
out << e
end
end
out
end
def map
out = []
# One line block syntax, append output of block processed on e to out
each {|e| out << yield(e) }
out
end
puts Stuff.new().map {|item| item}
puts Stuff.new().select{|item| item.even?}
Python говорит: «Вы говорите нам, как перебирать ваши экземпляры, а мы решим, что делать с вашими данными». правильный код тела цикла for (или выражения).
Ruby меняет сценарий, предоставляя объектам более глубокий уровень настраиваемости. Да, в некоторых случаях мы можем добавить больше потока управления внутри блока кода. Да, мы также можем использовать метод each в качестве карты. Но Ruby позволяет объектам реализовывать карту и каждый по-разному (использование реализации «каждого» вместо «карты» может быть очень неоптимальным или даже небезопасным). Объекты Ruby имеют лучший способ обработки своих данных.
В Ruby объекты управляют функциональной видимостью. В Python это синтаксис, который управляет.
Аутентичный Python имеет твердый взгляд на обработку данных. Python говорит: «Послушай, 90% твоего кода прекрасно соответствует этим идеям, просто следуй ему и делай свою работу».
Тем не менее, Ruby говорит: «В некоторых важных случаях мы не хотим давать вызывающему объекту слишком много полномочий». Ruby не так силен в обработке данных.
Python — это скорее расширение «объектно-ориентированного» программирования на языке C. В объектно-ориентированном программном обеспечении на основе C, подобно файловым дескрипторам posix или дескрипторам окон Win32, язык не привязывает «методы» к самим объектам. Вместо этого привязки объекта к методу просто основаны на соглашении.
Python считает, что этот мир процессов может развиваться — он совершенствует этот способ мышления, чтобы сделать его более безопасным. Существуют бесплатные функции (примечание Python cat: следует относиться к встроенным функциям, которые являются «бесплатными», поскольку они не зависят ни от какого объекта класса), и действительно часто предпочтительнее, чем методы объекта. Объект есть, но относительно нерешительно.
Класс метод получения «самости» в качестве своего первого аргумента, обрабатывается почти так же, как в функции Win32 или POSIX API, принимает C. Когда функция передается, они почти в зависимости от Contace Contacter.
Python считает, что процедурная парадигма является самой важной, она является ключевой основой всего, а над ней находится объектно-ориентированный семантический слой.
Однако Руби меняет это. Ruby использует объектную ориентацию как основу пирамиды. Ruby включает в себя беспорядочный мир процедур в блоках кода, позволяя объектам использовать эти блоки процедур.
Вместо того, чтобы уничтожать объекты, чтобы следовать процедурным основам языка, Ruby адаптирует процедурный код к мировоззрению объекта. Ruby имеет действительно частные методы, в отличие от частных методов/параметров Python, просто по соглашению.
Нет никаких сомнений в том, что когда я подошел к Python с точки зрения системного программирования, это казалось мне естественным. С возможностью писать на C, когда это необходимо, он эволюционировал, чтобы сделать этот мир более безопасным. Возможно, именно поэтому он нашел место в области численных вычислений, где системные ресурсы интенсивны.
Неудивительно, что Ruby отлично подходит для разработчиков, создающих более плавные и, возможно, более безопасные API и DSL. Ruby предполагает, что программист будет моделировать предметную область, а не среду программирования, что кажется правильным подходом для многих задач.