Існує багато дискусій про Python vs Ruby, і всі вони вважають їх абсолютно непосидними, тому що всі вони обертаються, чому функція X відмовляє в мові Y, або у тому, що мова претензії Y не має X, хоча насправді це так і є. Я також точно знаю, чому я віддаю перевагу Python, але це теж суб'єктивно, і нікому не допоможе вибрати, оскільки вони можуть не мати ті самі смаки в розвитку, як я.
Тому було б цікаво перелічити відмінності об’єктивно. Тож жодна «лямбда Пітона не смокче». Натомість поясніть, що можуть зробити лямбди Рубі, які не можуть Python. Без суб'єктивності. Приклад код хороший!
Не майте декількох відмінностей в одній відповіді, будь ласка. І проголосуйте за те, що ви знаєте, що вони правильні, а ті, кого ви знаєте, неправильні (або є суб'єктивними). Також відмінності в синтаксисі не цікаві. Ми знаємо, що Python робить з відступом, що робить Ruby з дужками і кінцями, і що @ називається self у Python.
ОНОВЛЕННЯ: Зараз це вікі спільноти, тому ми можемо додати тут великих відмінностей.
Рубі має посилання на клас в тілі класу
У Ruby у вас є посилання на клас (self), який вже знаходиться в тілі класу. У Python ви не маєте посилання на клас до закінчення побудови класу.
Приклад:
class Kaka
puts self
end
self у цьому випадку є класом, і цей код видав би "Kaka". Немає можливості роздрукувати ім’я класу або іншим способом отримати доступ до класу з тіла визначення класу в Python (зовнішні визначення методів).
Усі класи в Рубі змінні
Це дозволяє розробляти розширення до основних класів. Ось приклад розширення рейок:
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
.
У Рубі є сценарії, подібні до Perl
Ruby має першокласні regexps, $ -variables, рядок awk / perl за рядком введення рядка та інші функції, які роблять його більш придатним для написання невеликих скриптів оболонки, які об'єднують текстові файли або виконують роль клейкого коду для інших програм.
Рубі має продовження першого класу
Завдяки заяві callcc. У Python ви можете створювати продовження різними техніками, але немає підтримки, вбудованої в мову.
У Рубі є блоки
За допомогою оператора "do" ви можете створити багаторядову анонімну функцію в Ruby, яка буде передана як аргумент методу перед do, і викликається звідти. У Python ви б замість цього зробили або пропустивши метод, або з генераторами.
Ruby:
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 для виклику блоку називається "дохідність", яка в Python створить генератор.
Ruby:
def themethod
yield 5
end
themethod do |foo|
puts foo
end
Пітон:
def themethod():
yield 5
for foo in themethod():
print foo
Хоча принципи різні, результат вражаюче схожий.
Ruby легше підтримує програмування в функціональному стилі (у вигляді труб)
myList.map(&:description).reject(&:empty?).join("\n")
Пітон:
descriptions = (f.description() for f in mylist)
"\n".join(filter(len, descriptions))
Python має вбудовані генератори (які використовуються як блоки Ruby, як зазначено вище)
У Python є підтримка генераторів на мові. У Ruby 1.8 ви можете використовувати генераторний модуль, який використовує продовження для створення генератора з блоку. Або ви можете просто використовувати блок / proc / lambda! Більше того, у волокнах Ruby 1.9 волокна є і можуть використовуватися як генератори, а клас 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, і розташований над методом замість нього. Їх можна отримати під час виконання з файлів, використовуючи приклад використання методу 1.9 з використанням # source_location
Пітон має багаторазове успадкування
Рубі не ("спеціально" - дивіться веб-сайт Ruby, дивіться тут, як це робиться в Ruby ). Він повторно використовує концепцію модуля як тип абстрактних класів.
Python має розуміння списку / вивідок
Пітон:
res = [x*x for x in range(1, 10)]
Ruby:
res = (0..9).map { |x| x * x }
Пітон:
>>> (x*x for x in range(10))
<generator object <genexpr> at 0xb7c1ccd4>
>>> list(_)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Ruby:
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'}
Ruby:
>> 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