Co ma Ruby, czego nie ma w Pythonie i odwrotnie?

263

Jest wiele dyskusji na temat Pythona kontra Ruby i wszyscy uważam je za całkowicie nieprzydatne, ponieważ wszyscy odwracają się, dlaczego funkcja X jest do kitu w języku Y lub ten język twierdzi, że język Y nie ma X, chociaż w rzeczywistości tak jest. Wiem też dokładnie, dlaczego wolę Python, ale jest to również subiektywne i nie pomogłoby każdemu wybrać, ponieważ mogą nie mieć takich samych upodobań rozwojowych jak ja.

Interesujące byłoby zatem obiektywnie wymienić różnice. Więc nie ma „lambdów Pythona do bani”. Zamiast tego wyjaśnij, co potrafią zrobić jagnięta Ruby, czego nie potrafią Python. Bez podmiotowości. Przykładowy kod jest dobry!

Proszę nie mieć kilku różnic w jednej odpowiedzi. I głosuj w górę na te, o których wiesz, że są poprawne, a na głos, o których wiesz, że są niepoprawne (lub są subiektywne). Również różnice w składni nie są interesujące. Wiemy, że Python robi z wcięciami to, co Ruby robi z nawiasami i końcami, i że @ w Pythonie nazywa się self.

AKTUALIZACJA: To jest teraz wiki społeczności, więc możemy tutaj dodać duże różnice.

Ruby ma odwołanie do klasy w treści klasy

W Ruby masz odniesienie do klasy (ja) już w treści klasy. W Pythonie nie ma odniesienia do klasy, dopóki jej budowa nie zostanie zakończona.

Przykład:

class Kaka
  puts self
end

self w tym przypadku jest klasą, a ten kod wypisuje „Kaka”. Nie ma sposobu, aby wydrukować nazwę klasy lub w inny sposób uzyskać dostęp do klasy z treści definicji klasy w Pythonie (poza definicjami metod).

Wszystkie klasy można modyfikować w Ruby

Pozwala to opracowywać rozszerzenia klas podstawowych. Oto przykład rozszerzenia szyny:

class String
  def starts_with?(other)
    head = self[0, other.length]
    head == other
  end
end

Python (wyobraź sobie, że nie ma ''.startswithmetody):

def starts_with(s, prefix):
    return s[:len(prefix)] == prefix

Możesz użyć go w dowolnej sekwencji (nie tylko w łańcuchach). Aby go użyć, należy go zaimportować jawnie, np from some_module import starts_with.

Ruby ma funkcje skryptowe podobne do Perla

Ruby ma najwyższej klasy wyrażenia regularne, zmienne $, awk / perl wiersz po wierszu i inne funkcje, które sprawiają, że jest bardziej odpowiedni do pisania małych skryptów powłoki, które wyciszają pliki tekstowe lub działają jako kod kleju dla innych programów.

Ruby ma kontynuacje pierwszej klasy

Dzięki instrukcji callcc. W Pythonie możesz tworzyć kontynuacje za pomocą różnych technik, ale nie ma wbudowanej obsługi języka.

Ruby ma bloki

Za pomocą instrukcji „do” możesz utworzyć wieloliniową anonimową funkcję w Ruby, która zostanie przekazana jako argument do metody przed do i wywołana stamtąd. W Pythonie należy to zrobić albo przez przekazanie metody, albo za pomocą generatorów.

Rubin:

amethod { |here|
    many=lines+of+code
    goes(here)
}

Python (bloki Ruby odpowiadają różnym konstrukcjom w Pythonie):

with amethod() as here: # `amethod() is a context manager
    many=lines+of+code
    goes(here)

Lub

for here in amethod(): # `amethod()` is an iterable
    many=lines+of+code
    goes(here)

Lub

def function(here):
    many=lines+of+code
    goes(here)

amethod(function)     # `function` is a callback

Co ciekawe, instrukcja wygody w języku Ruby do wywoływania bloku nazywa się „wydajnością”, która w Pythonie utworzy generator.

Rubin:

def themethod
    yield 5
end

themethod do |foo|
    puts foo
end

Pyton:

def themethod():
    yield 5

for foo in themethod():
    print foo

Chociaż zasady są różne, wynik jest uderzająco podobny.

Ruby ułatwia programowanie w stylu funkcjonalnym (przypominającym potok)

myList.map(&:description).reject(&:empty?).join("\n")

Pyton:

descriptions = (f.description() for f in mylist)
"\n".join(filter(len, descriptions))

Python ma wbudowane generatory (które są używane jak bloki Ruby, jak wspomniano powyżej)

Python obsługuje generatory w tym języku. W Ruby 1.8 możesz użyć modułu generatora, który używa kontynuacji do utworzenia generatora z bloku. Lub możesz po prostu użyć bloku / proc / lambda! Co więcej, w Ruby 1.9 Fibres są i mogą być używane jako generatory, a klasa Enumerator jest wbudowanym generatorem 4

docs.python.org ma ten przykład generatora:

def reverse(data):
    for index in range(len(data)-1, -1, -1):
        yield data[index]

Porównaj to z powyższymi przykładami bloków.

Python ma elastyczną obsługę przestrzeni nazw

W Ruby, gdy importujesz plik require, wszystkie elementy zdefiniowane w tym pliku znajdą się w twojej globalnej przestrzeni nazw. Powoduje to zanieczyszczenie przestrzeni nazw. Rozwiązaniem tego są moduły Rubys. Ale jeśli utworzysz przestrzeń nazw z modułem, musisz użyć tej przestrzeni nazw, aby uzyskać dostęp do zawartych klas.

W Pythonie plik jest modułem i możesz zaimportować zawarte w nim nazwy from themodule import *, w ten sposób zanieczyszczając przestrzeń nazw, jeśli chcesz. Ale możesz również zaimportować wybrane nazwy za pomocą from themodule import aname, anotherlub możesz po prostu, import themodulea następnie uzyskać dostęp do nazw za pomocą themodule.aname. Jeśli chcesz mieć więcej poziomów w swojej przestrzeni nazw, możesz mieć pakiety, które są katalogami z modułami i __init__.pyplikiem.

Python ma dokumenty

Dokumenty są łańcuchami, które są dołączone do modułów, funkcji i metod i mogą być introspektywne w czasie wykonywania. Pomaga to w tworzeniu takich rzeczy, jak polecenie pomocy i automatyczna dokumentacja.

def frobnicate(bar):
    """frobnicate takes a bar and frobnicates it

       >>> bar = Bar()
       >>> bar.is_frobnicated()
       False
       >>> frobnicate(bar)
       >>> bar.is_frobnicated()
       True
    """

Odpowiedniki Ruby są podobne do javadocs i znajdują się nad metodą zamiast w niej. Można je odzyskać w czasie wykonywania z plików przy użyciu metody 1.9 # przykład użycia source_location

Python ma wiele elementów dziedziczenia

Ruby nie robi tego („celowo” - patrz strona internetowa Ruby, zobacz tutaj, jak to się robi w Ruby ). Ponownie wykorzystuje koncepcję modułu jako rodzaj klas abstrakcyjnych.

Python ma rozumienie list / nagrań

Pyton:

res = [x*x for x in range(1, 10)]

Rubin:

res = (0..9).map { |x| x * x }

Pyton:

>>> (x*x for x in range(10))
<generator object <genexpr> at 0xb7c1ccd4>
>>> list(_)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Rubin:

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'}

Rubin:

>> Hash[{1=>2, 3=>4}.map{|x,y| [x,(y*y).to_s]}]
=> {1=>"4", 3=>"16"}

Python ma dekoratorów

Rzeczy podobne do dekoratorów można również tworzyć w Ruby i można również argumentować, że nie są tak potrzebne jak w Pythonie.

Różnice w składni

Ruby wymaga „end” lub „}”, aby zamknąć wszystkie swoje zakresy, podczas gdy Python używa tylko białych znaków. Ostatnio podjęto w Ruby próby dopuszczenia wcięć tylko w białych znakach http://github.com/michaeledgar/seamless

Lennart Regebro
źródło
2
W odniesieniu do wielokrotnego dziedziczenia, powiedzenie „Ruby nie robi” jest nieuczciwe. Nie mogę wymyślić niczego, co można zrobić w Pythonie z wielokrotnym dziedziczeniem, czego nie można zrobić w Ruby z modułami / „dziedziczeniem mixin”. (Można nawet argumentować, że włączenie zwykłych modułów jest wielokrotnym dziedzictwem.)
Logan Capaldo
2
To, że możesz zrobić to samo w inny sposób, nie jest argumentem. Możesz zrobić wszystko tutaj w inny sposób. A ponieważ moduły nie są klasami, nie jest to wielokrotne dziedziczenie. Możesz podać przykłady kodu, jak to się robi w Pythons wielokrotne dziedziczenie w porównaniu z modułami Rubys.
Lennart Regebro,
3
Moduły nie są klasami, ale klasy są modułami. % ruby ​​-e 'p Klasa <Moduł' true
Logan Capaldo
8
-1 Niestety, pytanie to nie spełnia swojego celu, a większość rzekomych różnic w ogóle nie jest różnicami, a dezinformacja jest obfita!
stronniczość
2
Moduł zawiera w rzeczywistości wielokrotne dziedziczenie, nie tylko w koncepcji, ale w rzeczywistej implementacji w interpretera Ruby. Gdy dołączony jest moduł Ruby, jest on wstrzykiwany do łańcucha dziedziczenia dokładnie tak samo, jak w przypadku superklas. Rozdzielczość metody jest taka sama. W Rubim wiele modułów obejmuje wielokrotne dziedziczenie. Każdy, kto chce zakwestionować to jako semantycznie „nie to samo” jako wielokrotne dziedzictwo, jest po prostu pedantyczny. Jaki jest sens czegoś, co nie jest „tym samym”, jeśli efekt jest identyczny i równie łatwy do osiągnięcia? Różnica bez różnicy.
Dave Sims,

Odpowiedzi:

34

Ruby ma pojęcia bloków , które są zasadniczo składniowym cukrem wokół części kodu; są sposobem na tworzenie zamknięć i przekazywanie ich do innej metody, która może, ale nie musi, używać bloku. Blok można później wywołać za pomocą yieldinstrukcji.

Na przykład prosta definicja eachmetody Arraymoże być następująca:

class Array
  def each
    for i in self  
      yield(i)     # If a block has been passed, control will be passed here.
    end  
  end  
end  

Następnie możesz wywołać to w następujący sposób:

# Add five to each element.
[1, 2, 3, 4].each{ |e| puts e + 5 }
> [6, 7, 8, 9]

Python ma anonimowe funkcje / zamknięcia / lambdas, ale nie ma całkiem bloków, ponieważ brakuje niektórych przydatnych cukru syntaktycznego. Istnieje jednak co najmniej jeden sposób, aby uzyskać go w sposób ad hoc. Zobacz na przykład tutaj .

John Feminella
źródło
6
@ Lennart: prócz okropnego przykładu, jest on również błędny składniowo.
2
@unbeknow: A, racja. Ale gdyby to była funkcja zamiast wydruku, działałaby. W Pythonie 3 działa to: [print (e + 5) dla e w [1,2,3,4]] A jeśli chodzi o horrorlenity, myślę, że powyższy kod ruby ​​jest okropny, więc jest to wyraźnie subiektywne i dlatego nie jest część tego pytania. @John Nie mówię, że jest to równoważne, mówię, że nie jest oczywiste, jaka jest różnica z twojego przykładu. @ Bastien, nie, ale to, że możesz robić podobne rzeczy, nie oznacza, że ​​są takie same. Różnice należy wymienić tutaj, nawet jeśli istnieją inne sposoby, aby to zrobić.
Lennart Regebro,
22
Jestem programistą Python. Chciałbym zobaczyć przykład, w jaki sposób bloki Ruby pomagają pisać coś bardziej zwięzłego lub piękniejszego niż w Pythonie, ponieważ nie ma bloków. Twój przykład można zapisać: dla i w [1, 2, 3, 4]: wydrukuj (i + 5). Nie używa bloków, ale jest zwięzły i piękny, a także rubinowy każdy przykład.
Manuel Ceron
10
@Manuel, procs są przydatne do dołączania funktorów do nietrywialnych struktur danych (drzew, wykresów ...), których nie można „zapętlić”, a zatem wymagają specjalnych iteratorów do przejścia poprzecznego. Bloki, które są anonimowymi procesami, pozwalają zaimplementować funktor w jednym wyrażeniu (zamiast zdefiniować, a następnie zaimplementować), co znacznie przyspiesza proces kodowania i wyjaśnia zamiary. Na przykład, jeśli tworzysz strukturę danych wykresu, możesz zdefiniować jeden „każdy” iterator, a następnie miksować Enumerable, który natychmiast dałby ci dostęp do kilkudziesięciu iteratorów (sortuj, wszystkie ?, dowolne?, Grep). Teraz wywołujesz blok ...
uprzedzenie
4
@RommeDeSerieux, ponieważ potrzebuje nazwy w języku! Co więcej, jest to obiekt funkcji, a nie funkcja. Spójrzmy na Ruby Docs: „Obiekty Proc to bloki kodu, które zostały powiązane z zestawem zmiennych lokalnych”, więc anonimowy Proc to tylko blok, a na pewno nie tylko funkcja!
stronniczość
28

Przykład Python

Funkcje są pierwszorzędnymi zmiennymi w Pythonie. Możesz zadeklarować funkcję, przekazać ją jako obiekt i zastąpić:

def func(): print "hello"
def another_func(f): f()
another_func(func)

def func2(): print "goodbye"
func = func2

Jest to podstawowa cecha współczesnych języków skryptowych. JavaScript i Lua też to robią. Ruby nie traktuje funkcji w ten sposób; nazywanie funkcji wywołuje ją.

Oczywiście istnieją sposoby na robienie tych rzeczy w Ruby, ale nie są to operacje pierwszej klasy. Na przykład możesz zawinąć funkcję w Proc.new, aby traktować ją jako zmienną - ale wtedy nie jest to już funkcja; jest to obiekt z metodą „wywołania”.

Funkcje Ruby nie są obiektami pierwszej klasy

Funkcje Ruby nie są obiektami pierwszej klasy. Funkcje muszą być zawinięte w obiekt, aby je rozdzielić; wynikowy obiekt nie może być traktowany jak funkcja. Funkcje nie mogą być przypisywane w sposób pierwszej klasy; zamiast tego należy wywołać funkcję w obiekcie kontenera, aby je zmodyfikować.

def func; p "Hello" end
def another_func(f); method(f)[] end
another_func(:func)      # => "Hello"

def func2; print "Goodbye!"
self.class.send(:define_method, :func, method(:func2))
func                     # => "Goodbye!"

method(:func).owner      # => Object
func                     # => "Goodbye!"
self.func                # => "Goodbye!"    
stronniczości
źródło
8
Jesteś bardzo zdezorientowany. Pierwszorzędne obiekty są przypisywane poprzez przypisanie: a x = ynie przez wywołanie self.class.send(:define_method, :func, method(:func2)). Twój „kontrprzykład” pokazuje, że funkcje Ruby nie są najwyższej klasy. Jeśli się nie zgadzasz, możesz opublikować własną odpowiedź; nie wtrącaj zamieszania w moje.
Glenn Maynard
7
Rzeczy zdefiniowane przez def ... endruby nie są funkcjami. Są to metody (sposób, w jaki je zdefiniowałeś Kernel). Metody mogą być niezwiązane (przy użyciu #methodmetody), które następnie są obiektami. Ruby najbardziej zbliżone do funkcji to Procinstancje, które są również obiektami i można je przekazywać lub wywoływać. Ma również specjalną składnię do przekazywania pojedynczego wywołania zwrotnego Procdo metody, co omawia John Feminella w swojej odpowiedzi .
rampion
4
@Glenn: Rozumiem, co mówisz, ale spieram się z twierdzeniem, że redefiniujące funkcje Ruby - metody to osobna koncepcja semantyczna. Jeśli chcesz zagrać w grę z definicjami, najbardziej koniecznym kodem są procedury, a nie funkcje. Nie staram się być trudny, po prostu uważam, że definicje i dokładność są ważne. Zgadzam się, że manipulowanie UnboundMethodmoże być PITA, tho.
rampion
5
@Glenn: Piękno jest w oku patrzącego. Niemniej jednak metody są obiektami najwyższej klasy, ponieważ spełniają definicję (w tym przypadku odnoszę się do definicji z Wikipedii). Może masz inną definicję pierwszej klasy? Czy potrzebują Platinum Frequent Flier Card, aby dostać się do pierwszej klasy?
stronniczość
4
@Glenn Sprawdź sekcję SO FAQ „Inne osoby mogą edytować moje rzeczy ?!” - to jest Wiki Wiki.
stronniczość
26

Ostatecznie wszystkie odpowiedzi będą na pewnym poziomie subiektywne, a dotychczasowe odpowiedzi w zasadzie dowodzą, że nie można wskazać żadnej funkcji, która nie byłaby możliwa w innym języku w równie miły (jeśli nie podobny) sposób , ponieważ oba języki są bardzo zwięzłe i wyraziste.

Lubię składnię Pythona. Musisz jednak zagłębić się nieco głębiej niż składnia, aby znaleźć prawdziwe piękno Ruby. W konsystencji Ruby jest piękno podobne do zen. Chociaż żaden trywialny przykład nie jest w stanie tego całkowicie wyjaśnić, postaram się tu znaleźć taki, aby wyjaśnić, co mam na myśli.

Odwróć słowa w tym ciągu:

sentence = "backwards is sentence This"

Gdy zastanawiasz się, jak to zrobić, wykonaj następujące czynności:

  1. Podziel zdanie na słowa
  2. Odwróć słowa
  3. Ponownie połącz słowa z powrotem w ciąg

W Ruby zrobiłbyś to:

sentence.split.reverse.join ' '

Dokładnie tak, jak myślisz o tym, w tej samej sekwencji, jedno wywołanie metody po drugim.

W Pythonie wyglądałoby to bardziej tak:

" ".join(reversed(sentence.split()))

Nie jest trudno to zrozumieć, ale nie ma takiego samego przepływu. Temat (zdanie) jest pochowany w środku. Operacje są mieszanką funkcji i metod obiektowych. To jest trywialny przykład, ale odkrywa się wiele różnych przykładów, kiedy naprawdę pracujesz z Ruby i rozumiesz go, szczególnie w przypadku nie trywialnych zadań.

Mark Mark Thomas
źródło
1
Zgadzam się. Ruby wydaje się płynąć naturalnie, kiedy to piszę, więc „zenlike” to dobry termin.
Tin Man,
18

Python ma mentalność „wszyscy tu jesteśmy dorośli”. Zatem przekonasz się, że Ruby ma takie rzeczy jak stałe, podczas gdy Python nie (chociaż stałe Ruby wywołują tylko ostrzeżenie). Myślenie w języku Python polega na tym, że jeśli chcesz uczynić coś stałym, powinieneś wstawiać nazwy zmiennych do wszystkich wielkich liter i nie zmieniać ich.

Na przykład Ruby:

>> PI = 3.14
=> 3.14
>> PI += 1
(irb):2: warning: already initialized constant PI
=> 4.14

Pyton:

>>> PI = 3.14
>>> PI += 1
>>> PI
4.1400000000000006
Jason Baker
źródło
19
Ha .. to tylko przypomina mi, że przynajmniej w Pythonie 2. *, byłeś w stanie zrobić „Prawda, fałsz = fałsz, prawda” ... Wierzę, że poprawnie to naprawili w python 3.0 ... to jest coś, co powinieneś nie można tego zrobić.
Tom
11
Osobiście lubię surowe wytyczne egzekwowane przez język, ponieważ zapewnia spójność całego kodu napisanego w tym języku. To zmusza cię do wskazówek, a deweloperzy odczyt kodu można powiedzieć w skrócie, co jest co. Podczas gdy większość programistów Pythona używa tego samego ogólnego „stylu”, zauważyłem dość duże niespójności, które nie byłyby możliwe w Ruby.
Sasha Chedygov
8
@bias - Nie jestem pewien, dlaczego oddajesz mi głos. Ta odpowiedź nie zgadza się ani nie zgadza z pythonowym sposobem działania. To tylko stwierdzenie faktu.
Jason Baker
13
@Jason „jesteśmy tu wszyscy dorośli” to stwierdzenie faktu? Chciałbym nazwać to opinią owiniętą wokół obiektu, stąd głosowanie negatywne.
stronniczość
7
@bias - Powiedzenie „wszyscy tu jesteśmy dorośli” nie miało być lekceważące. To nieoficjalne motto Pythona, które moim zdaniem najlepiej wyjaśnić tutaj: mail.python.org/pipermail/tutor/2003-October/025932.html
Evan Porter
18

Możesz importować tylko określone funkcje z modułu w Pythonie. W Ruby importujesz całą listę metod. Możesz „nieimportować” ich w Ruby, ale nie o to chodzi.

EDYTOWAĆ:

weźmy ten moduł Ruby:


module Whatever
  def method1
  end

  def method2
  end
end

jeśli umieścisz to w swoim kodzie:


include Whatever

zobaczysz, że zarówno method1 i Method2 został dodany do nazw. Nie można zaimportować tylko metody 1 . Albo je importujesz, albo wcale. W Pythonie możesz importować tylko wybrane metody. Jeśli miałoby to nazwę, może to się nazywa selektywne importowanie?

Tempus
źródło
2
Och, racja! Python lubi przestrzenie nazw. Czy nie jest tak w Ruby? Nie jesteś import bla; bla.foo()w Ruby?
Lennart Regebro,
2
Możesz zaimportować tylko funkcję a, a nie wszystkie funkcje w środku. Jeśli na przykład załączysz moduł Ruby, który deklaruje 3 funkcje niestatyczne, uzyskasz je wszystkie w swojej przestrzeni nazw. W pythonie będziesz musiał pisać z modułu importu *.
Geo
6
Czy to nie prowadzi do bałaganu w przestrzeni nazw?
Lennart Regebro,
1
Myślę, że tak. Tego właśnie nie lubię w modułach Ruby.
Geo
8
Ruby tak naprawdę nie ma systemu modułów w tym samym sensie co python. wymagają prac w zasadzie jako włączenia tekstowego, z pewnymi sprawdzeniami wstawienia duplikatu. Możesz (ab) używać modułów jako przestrzeni nazw, ale w modulerzeczywistości jest to trochę mylące. Moduły są zasadniczo klasy sans new, allocatemetody. Działają najlepiej jako sposób udostępniania kodu dla poszczególnych klas / obiektów, a nie jako mechanizm partycjonowania bibliotek lub dzielenia kodu między programami.
Logan Capaldo
16

Od Ruby stronie :

Podobieństwa Jak w Pythonie, w Ruby, ...

  • Jest interaktywny monit (zwany irb).
  • Dokumenty możesz czytać w wierszu poleceń (za pomocą polecenia ri zamiast pydoc).
  • Nie ma specjalnych terminatorów linii (oprócz zwykłej nowej linii).
  • Literały łańcuchowe mogą obejmować wiele wierszy, takich jak potrójne ciągi znaków w Pythonie.
  • Nawiasy klamrowe służą do list, a nawiasy klamrowe do nagrań (które w języku Ruby nazywane są „skrótami”).
  • Tablice działają tak samo (ich dodanie tworzy jedną długą tablicę, ale ich skomponowanie w ten sposób a3 = [ a1, a2 ]daje tablicę tablic).
  • Obiekty są silnie i dynamicznie typowane.
  • Wszystko jest przedmiotem, a zmienne są tylko odniesieniami do obiektów.
  • Chociaż słowa kluczowe są nieco inne, wyjątki działają mniej więcej tak samo.
  • Masz osadzone narzędzia doc (Ruby's nazywa się rdoc).

Różnice W przeciwieństwie do Pythona, w Ruby, ...

  • Ciągi są zmienne.
  • Możesz tworzyć stałe (zmienne, których wartości nie zamierzasz zmieniać).
  • Istnieje kilka wymuszonych konwencji wielkości liter (np. Nazwy klas zaczynają się od dużej litery, zmienne zaczynają się od małej litery).
  • Istnieje tylko jeden rodzaj kontenera list (tablica) i można go modyfikować.
  • Ciągi podwójnie cytowane pozwalają na sekwencje specjalne (jak \ t) i specjalną składnię „podstawiania wyrażeń” (która pozwala wstawiać wyniki wyrażeń Ruby bezpośrednio do innych ciągów bez konieczności „dodawania” + „ciągów” + „razem”) . Ciągi pojedynczego cudzysłowu są jak „surowe ciągi” Pythona.
  • Nie ma zajęć w „nowym stylu” i „starym stylu”. Tylko jeden rodzaj.
  • Nigdy nie masz bezpośredniego dostępu do atrybutów. W Ruby wszystkie wywołania metod.
  • Nawiasy dla wywołań metod są zwykle opcjonalne.
  • Istnieją publiczne, prywatne i chronione w celu wymuszenia dostępu zamiast Pythona _voluntary_ underscore __convention__.
  • „Wielokrotne” są używane zamiast wielokrotnego dziedziczenia.
  • Możesz dodawać lub modyfikować metody klas wbudowanych. Oba języki umożliwiają otwieranie i modyfikowanie klas w dowolnym momencie, ale Python zapobiega modyfikacji wbudowanych - Ruby nie.
  • Masz prawdę i fałsz zamiast prawdy i fałszu (i zero zamiast żadnego).
  • Podczas testowania prawdy tylko fałsz i zero mają wartość fałszywą. Wszystko inne jest prawdą (w tym 0, 0,0, „” i []).
  • To elsif zamiast elif.
  • Wymaga zamiast importu. W przeciwnym razie użycie jest takie samo.
  • Do generowania dokumentów używane są zwykłe komentarze do linii nad rzeczami (zamiast ciągów pod nimi).
  • Istnieje wiele skrótów, które chociaż dają więcej do zapamiętania, szybko się uczysz. Zazwyczaj sprawiają, że Ruby jest zabawna i bardzo produktywna.
kruczkowski
źródło
2
„To wymaga zamiast importowania. W przeciwnym razie użycie jest takie samo.” Wydaje się być całkowicie niedokładny.
Glenjamin
Istnieją również zestawy w Rubim, z których ludzie rzadko korzystają, ale są wbudowane. Więc mogę powiedzieć, stuff_in_backpack = Set.new; stuff_in_backpack << „komputer”; stuff_in_backpack << „buty”; #, a zestaw zachowa wszystkie wartości bez gwarancji kolejności.
zachaysan
12

To, co Ruby ma nad Pythonem, to jego możliwości języka skryptowego. Język skryptowy w tym kontekście oznacza, że ​​należy go używać do „kodu kleju” w skryptach powłoki i ogólnej manipulacji tekstem.

Są one najczęściej udostępniane Perlowi. Pierwszej klasy wbudowane wyrażenia regularne, $ -Variables, przydatne opcje wiersza poleceń, takie jak Perl (-a, -e) itp.

Wraz ze zwięzłą, ale epxresywną składnią jest idealny do tego rodzaju zadań.

Python jest dla mnie bardziej dynamicznym typem języka biznesowego, który jest bardzo łatwy do nauczenia i ma zgrabną składnię. Nie tak „fajny” jak Ruby, ale schludny. To, co Python ma dla mnie w Ruby, to ogromna liczba powiązań dla innych bibliotek. Powiązania z bibliotekami Qt i innymi bibliotekami GUI, wiele bibliotek obsługi gier oraz i. Ruby ma znacznie mniej. Chociaż często używane powiązania, np. Do baz danych, są dobrej jakości, znalazłem niszowe biblioteki, które są lepiej obsługiwane w Pythonie, nawet jeśli dla tej samej biblioteki istnieje również powiązanie Ruby.

Powiedziałbym więc, że oba języki mają swoje zastosowanie i to zadanie określa, którego z nich użyć. Oba są wystarczająco łatwe do nauczenia się. Używam ich obok siebie. Ruby do skryptów i Python do samodzielnych aplikacji.

haffax
źródło
1
Pytanie od kogoś, kto jeszcze nie zna Ruby: Co rozumiesz przez „$ -Variables”? Masz na myśli zmienne globalne? Jeśli tak, w Pythonie zmienna zdefiniowana w module poza klasą lub funkcją jest globalna. Jeśli nie - jakie jest to rozróżnienie?
Anon,
1
Anon: jeśli zadeklarujesz zmienną $ w dowolnym miejscu w kodzie, jest ona globalna z powodu prefiksu. Dlatego nie ma znaczenia, gdzie jest zdefiniowane, zawsze ma charakter globalny i zawsze jest znany jako taki.
Robert K,
8
Nie do końca, właściwie miałem na myśli predefiniowane zmienne, takie jak $ _, $ 1 itd. Są one automatycznie wypełniane wartościami przez sam ruby. $ _ to ostatni odczytany wiersz. 1 USD, 2 USD itp. Są dopasowaniami wyrażeń regularnych z ostatniego dopasowania. Zobacz pełną listę tutaj: zenspider.com/Languages/Ruby/QuickRef.html#17 Zasadniczo jest to hack dla kompaktowych skryptów. Możesz również uzyskać wszystkie informacje poprzez wywołania API, ale używając zmiennych $ to bardziej zwięźle. Tego rodzaju zmienne po prostu nie pasują do stylu Pythona, celowo je pominięto.
haffax
Dzięki za ten link zenspider - szukałem czegoś takiego dla szybkiego (nie-instruktażowego) wyczucia Ruby.
Anon
12

Nie sądzę, że „Ruby ma X, a Python nie, podczas gdy Python ma Y, a Ruby nie” to najbardziej użyteczny sposób na to. Są to dość podobne języki, z wieloma wspólnymi umiejętnościami.

Różnica polega w dużej mierze na tym, że język czyni go eleganckim i czytelnym. Przywołując przywołany przykład, obaj teoretycznie mają lambdy, ale programiści Pythona zwykle ich unikają, a konstrukcje wykonane przy ich użyciu nie wyglądają tak czytelnie ani idiomatycznie jak w Rubim. Tak więc w Pythonie dobry programista będzie chciał wybrać inną ścieżkę rozwiązania problemu niż w Ruby, tylko dlatego, że jest to lepszy sposób na zrobienie tego.

Głaskanie pod brodę
źródło
5
Zgadzam się, że lambdy mają ograniczony zakres i w wielu przypadkach nie są przydatne. Nie sądzę jednak, aby można było powiedzieć, że programiści Pythona unikają ich jak zarazy.
Jason Baker,
1
Zgadzam się, że lambda są często używane w Pythonie - podobnie jak w przypadku map, filtrów, redukcji. Duża różnica wydaje się polegać na tym, że lambda Pythona są ograniczone do wyrażeń, podczas gdy bloki Ruby mogą być wielowierszowe i zawierać instrukcje. Moje ogólne wrażenie z tego, co przeczytałem o Ruby, jest takie, że ta funkcja w szczególności powoduje, że Rubyści wybierają podejście DSL, podczas gdy Pythoniści są bardziej skłonni do tworzenia interfejsów API. Moje informacje o Ruby są jednak nadal bardzo powierzchowne.
Anon,
2
@ Lennart: Bloki wielowierszowe są cały czas używane w Rubim - w rzeczywistości częściej niż widzę lambdy używane w idiomatycznym kodzie Pythona. Typowy przykład można znaleźć na stronie info.michael-simons.eu/2007/08/06/rails-respond_to-method .
Chuck,
1
@ Lennart: Nie, nie wykorzystuje wydajności. (Wydajność Ruby i tak jest zupełnie inna niż wydajność Pythona - nie zwraca generatora.) Pisanie nie miałoby sensu for format in respond_to(). respond_toMetoda nic nie znaczący powrót - po prostu reaguje bieżącego żądania HTTP. doW respond_to doto początek bloku. W tym bloku rozmawiamy z tymczasowym obiektem (oznaczonym formatw tym przykładzie), który implementuje bardzo podstawowy DSL do odpowiadania na żądanie HTTP.
Chuck,
3
Czy potrafisz „mieszać Enumerable” z generatorem i natychmiast uzyskać 30 nowych i wspaniałych iteratorów? Musisz zrozumieć cały język, zanim zrozumiesz, dlaczego bloki / procy są świetne.
stronniczość
12

Chciałbym zasugerować wariant pierwotnego pytania: „Co Ruby ma w Pythonie i na odwrót?” która przyznaje rozczarowującą odpowiedź: „Co możesz zrobić z Ruby lub Pythonem, czego nie można zrobić w Intercalu?” Nic na tym poziomie, ponieważ zarówno Python, jak i Ruby są częścią rozległej rodziny królewskiej siedzącej na tronie w przybliżeniu Turinga.

Ale co z tym:

Co można zrobić z wdziękiem i dobrze w Pythonie, czego nie można zrobić w Ruby przy takim pięknie i dobrej inżynierii lub odwrotnie?

To może być o wiele bardziej interesujące niż zwykłe porównanie funkcji.

Christos Hayward
źródło
co najwyżej komentarz. wciąż moja +1
nawfal
11

Python ma jawną, wbudowaną składnię dla list-comprehenions i generatorów, podczas gdy w Ruby używałbyś bloków map i kodu.

Porównać

list = [ x*x for x in range(1, 10) ]

do

res = (1..10).map{ |x| x*x }
Dario
źródło
jak rozumienia list nie są zwykłym Pythonem ? w Pythonie jest także funkcja mapy.
SilentGhost,
Ale w Ruby nie ma składni ze zrozumieniem listy
Dario,
Python: res = map (lambda x: x * x, range (1,10))
GogaRieger
Python:res=map(2 .__rpow__, range(1,10))
John La Rooy,
11

„Zmienne zaczynające się od dużej litery stają się stałymi i nie można ich modyfikować”

Źle. Mogą.

Otrzymasz ostrzeżenie tylko wtedy, gdy to zrobisz.

znak
źródło
2
Jeśli język ostrzega przed operacją, uważam, że bardzo dobrze możesz uznać operację za „niemożliwą”. Wszystko inne to szaleństwo.
porgarmingduod
11

Nieco więcej po stronie infrastruktury:

  • Python ma znacznie lepszą integrację z C ++ (poprzez rzeczy takie jak Boost.Python , SIP i Py ++ ) niż Ruby, gdzie opcje wydają się albo pisać bezpośrednio w interfejsie API interpretera Ruby (co można oczywiście również zrobić w Pythonie, ale w obu przypadkach jest to niski poziom, żmudne i podatne na błędy) lub użyj SWIG (który, choć działa i zdecydowanie jest świetny, jeśli chcesz obsługiwać wiele języków, nie jest tak przyjemny jak Boost.Python lub SIP, jeśli szczególnie chcesz powiązać C ++).

  • Python ma wiele środowisk aplikacji internetowych (Django, Pylons / Turbogears, web.py, prawdopodobnie co najmniej pół tuzina innych), podczas gdy Ruby (skutecznie) ma jedno: Railsy. (Inne frameworki Ruby istnieją, ale najwyraźniej mają trudności z uzyskaniem dużej przyczepności do Railsów). Czy ten aspekt jest dobry czy zły? Trudno powiedzieć i prawdopodobnie dość subiektywny; Mogę łatwo wyobrazić sobie argumenty, że sytuacja w Pythonie jest lepsza, a sytuacja w Ruby jest lepsza.

  • Pod względem kulturowym społeczności Python i Ruby wydają się nieco inne, ale mogę tylko to wskazać, ponieważ nie mam zbyt dużego doświadczenia w interakcji ze społecznością Ruby. Dodam to głównie w nadziei, że ktoś, kto ma duże doświadczenie z oboma, może wzmocnić (lub odrzucić) to stwierdzenie.

Jack Lloyd
źródło
7
Twój drugi punkt jest co najwyżej źle poinformowany. Powinieneś zacząć od spojrzenia na Racka i Sinatrę
Max Ogden
6
Wyraźnie zauważam, że istnieją inne stosy Railsów; Po prostu nie sądzę, żeby ktokolwiek z nich faktycznie korzystał. Sprawdzanie Sinatry i Racka nie zmieniło tego wrażenia. Czy naprawdę myślisz, powiedzmy, Sinatra (łącznie 94 pytania SO) lub Camping (łącznie 2 pytania SO), czy którykolwiek z innych, naprawdę ma prawdziwą bazę użytkowników / społeczność? O ile wiem, większość z nich nie ma nawet prawdziwych użytkowników. Porównaj z Django (4K +) lub Rails (7K +), a nawet web.py.
Jack Lloyd,
1
Sinatra jest właściwie popularna do różnych, lekkich zadań ze względu na DSL. Jest po prostu mniej używany, ponieważ MVC Rail zapewnia więcej. Szyny są zbudowane na stojaku - dzięki temu Phusion Passenger jest możliwy.
alternatywnie
11

Bezwstydnie skopiuj / wklej z: Alex Martelli odpowiedz na temat Co jest lepsze w Ruby niż Python z listy dyskusyjnej comp.lang.python .

18 sierpnia 2003, 10:50 Erik Max Francis napisał:

„Brandon J. Van Every” napisał:

Co jest lepszego w Ruby niż Python? Jestem pewien, że coś jest. Co to jest?

Czy nie byłoby rozsądniej zapytać o to ludzi Ruby, niż ludzi Python?

Może, ale nie musi, w zależności od celów - na przykład, jeśli do celów tych zalicza się „badanie socjologiczne” społeczności Python, zadawanie pytań tej społeczności może okazać się bardziej ujawniające informacje na ten temat, niż umieszczanie ich gdzie indziej :-).

Osobiście chętnie skorzystałem z okazji, aby w końcu wykonać jednodniowy samouczek Ruby'a Dave'a Thomasa w OSCON. Pod cienką okleiną różnic składniowych uważam, że Ruby i Python są niesamowicie podobne - gdybym obliczał minimalne drzewo rozpinające spośród niemal każdego zestawu języków, jestem prawie pewien, że Python i Ruby byłyby dwoma pierwszymi, które połączyłyby się w jedno węzeł pośredni :-).

Jasne, w języku Ruby mam już dość pisania głupiego „końca” na końcu każdego bloku (zamiast zwykłego cofania) - ale potem unikam wpisywania równie głupiego „:”, którego Python wymaga początek każdego bloku, więc to prawie pranie :-). Inne różnice w składni, takie jak „@foo” w porównaniu do „self.foo” lub wyższe znaczenie wielkości liter w Ruby vs. Python, są dla mnie tak samo nieistotne.

Inni bez wątpienia opierają swój wybór języków programowania na takich właśnie kwestiach i generują najgorętsze debaty - ale dla mnie to tylko przykład jednego z przepisów prawa Parkinsona w działaniu (kwota na debatę na temat jest odwrotnie proporcjonalna do kwestii faktyczne znaczenie).

Edycja (popr. 19.06.2010 11:45): jest to również znane jako „malowanie rowerów” (lub w skrócie „rowerów”) - ponownie nawiązanie do Northcote Parkinson, który prowadził „debaty” na temat tego, jaki kolor malować w rowerach ”jako typowy przykład„ gorących debat na trywialne tematy ”. (koniec edycji).

Jedną z różnic w składni, które uważam za ważne, i na korzyść Pythona - ale inni ludzie bez wątpienia będą myśleć odwrotnie - „jak wywołać funkcję, która nie przyjmuje parametrów”. W Pythonie (jak w C), aby wywołać funkcję, zawsze stosujesz „operator wywołania” - nawiasy końcowe tuż za wywoływanym obiektem (w tych nawiasach końcowych przechodzą argumenty przekazywane w wywołaniu - jeśli nie podajesz żadnych argumentów, wtedy nawiasy są puste). Pozostawia to jedynie wzmiankę o jakimkolwiekobiekt, bez udziału operatora, co oznacza jedynie odniesienie do obiektu - w dowolnym kontekście, bez specjalnych przypadków, wyjątków, reguł ad-hoc i tym podobnych. W Ruby (jak w Pascalu), aby wywołać funkcję Z argumentami przekazujesz argumenty (zwykle w nawiasach, choć nie jest to niezmiennie przypadek) - ALE jeśli funkcja nie przyjmuje argumentów, to po prostu wspominając o funkcji wywołuje ją niejawnie. Może to spełnić oczekiwania wielu osób (przynajmniej bez wątpienia tych, których jedyne wcześniejsze doświadczenie w programowaniu dotyczyło Pascala lub innych języków z podobnym „ukrytym wywołaniem”, takich jak Visual Basic) - ale dla mnie oznacza to sama wzmianka o obiekcie może ZAWSZE oznaczać odwołanie do obiektu LUB wywołanie obiektu, w zależności od typu obiektu - w tych przypadkach, w których mogę Aby uzyskać odniesienie do obiektu, po prostu wspominając o nim, będę musiał użyć wyraźnego „daj mi odniesienie do tego, NIE nazywaj go!” operatorzy, którzy w innym przypadku nie są potrzebni. Wydaje mi się, że wpływa to na „pierwszorzędność” funkcji (lub metod lub innych wywoływalnych obiektów) oraz na możliwość płynnej wymiany obiektów. Dlatego dla mnie ta konkretna różnica w składni jest poważnym czarnym znakiem przeciwko Ruby - ale rozumiem, dlaczego inni mieliby coś innego, nawet jeśli nie mogłem się z nimi bardziej zdecydowanie nie zgodzić :-). funkcji (lub metod lub innych wywoływalnych obiektów) oraz możliwość płynnej zamiany obiektów. Dlatego dla mnie ta konkretna różnica w składni jest poważnym czarnym znakiem przeciwko Ruby - ale rozumiem, dlaczego inni mieliby coś innego, nawet jeśli nie mogłem się z nimi bardziej zdecydowanie nie zgodzić :-). funkcji (lub metod lub innych wywoływalnych obiektów) oraz możliwość płynnej zamiany obiektów. Dlatego dla mnie ta konkretna różnica w składni jest poważnym czarnym znakiem przeciwko Ruby - ale rozumiem, dlaczego inni mieliby coś innego, nawet jeśli nie mogłem się z nimi bardziej zdecydowanie nie zgodzić :-).

Poniżej składni przechodzimy do kilku istotnych różnic w elementarnej semantyce - na przykład ciągi znaków w Rubim są obiektami podlegającymi modyfikacjom (jak w C ++), podczas gdy w Pythonie nie można ich modyfikować (jak w Javie lub, jak sądzę, C #). Znów ludzie, którzy oceniają przede wszystkim na podstawie tego, co już znają, mogą pomyśleć, że to plus dla Ruby (chyba że znają Javę lub C #, oczywiście :-). Ja myślę, że niezmienne łańcuchy są doskonałym pomysłem (i nie jestem zaskoczony, że Java, jak sądzę niezależnie, na nowo wymyślił ten pomysł, który był już w Pythonie), chociaż nie miałbym nic przeciwko posiadaniu typu „zmiennego bufora łańcuchów” (i najlepiej taki, który jest łatwiejszy w użyciu niż własne „bufory łańcuchów” Javy); i nie oceniam tego z powodu znajomości - przed studiowaniem Javy, wszystkie dane są niezmienne, wszystkie języki, które znałem, miały zmienne ciągi - ale kiedy po raz pierwszy zobaczyłem ideę ciągów niezmiennych w Javie (której nauczyłem się na długo zanim nauczyłem się Pythona), od razu uderzyło mnie to jako doskonałe, bardzo dobre dla semantyka referencyjna języka programowania wyższego poziomu (w przeciwieństwie do semantyki wartości, która najlepiej pasuje do języków bliższych maszynie i dalej od aplikacji, takich jak C), z łańcuchami jako pierwszorzędnej, wbudowanej (i ładnej) kluczowe) typ danych.

Ruby ma pewne zalety w elementarnej semantyce - na przykład usunięcie „list kontra krotki” Pythona niezwykle subtelnie rozróżnia. Ale przede wszystkim wynik (jak utrzymuję, z prostotą duży plus i subtelne, sprytne rozróżnienia zauważalny minus) jest przeciwny Ruby (np. Mając zarówno zamknięte, jak i półotwarte interwały, z notacjami a..b i .. .b [ktoś chce twierdzić, że to oczywiste, który jest który? -)], jest głupi - oczywiście IMHO!). Ponownie, ludzie, którzy rozważają posiadanie wielu podobnych, ale subtelnie różnych rzeczy w rdzeniu języka PLUS, a nie MINUS, oczywiście policzą te „na odwrót” od ich liczenia :-).

Nie daj się zwieść tym porównaniom, że oba języki są bardzo dobreinaczej, pamiętajcie. Nie są. Ale jeśli poproszę o porównanie „capelli d'angelo” do „spaghettini”, po wskazaniu, że te dwa rodzaje makaronów są prawie nie do odróżnienia dla nikogo i wymienne w każdym naczyniu, które chcesz przygotować, nieuchronnie miałbym przejść do badania mikroskopowego, w jaki sposób niedostrzegalnie różnią się długości i średnice, w jaki sposób końce pasm zwężają się w jednym przypadku, a nie w drugim itd. - próbując wyjaśnić, dlaczego osobiście wolałbym mieć capelli d „angelo jak makaron w jakimkolwiek bulionie, ale wolałby spaghetti jako pastasciutta niż odpowiednie sosy do tak długich cienkich form makaronu (oliwa z oliwek, mielony czosnek, mielona czerwona papryka i drobno mielone sardele, na przykład - ale jeśli pokroisz czosnek i paprykę zamiast je rozdrobnić, powinieneś wybrać bardziej dźwięczny korpus spaghetti niż cieńszą ulotność spaghetti i dobrze byłoby zrezygnować z achovies i zamiast tego dodać trochę świeżej wiosennej bazylii [ a nawet - jestem heretykiem ...! - lekka mięta ...] liście - w ostatniej chwili przed podaniem dania). Ups, przepraszam, to pokazuje, że podróżuję za granicę i chyba nie jadłem makaronu od jakiegoś czasu. Ale analogia jest nadal całkiem dobra! -) - lekka mięta ...] liście - w ostatniej chwili przed podaniem dania). Ups, przepraszam, to pokazuje, że podróżuję za granicę i chyba nie jadłem makaronu od jakiegoś czasu. Ale analogia jest nadal całkiem dobra! -) - lekka mięta ...] liście - w ostatniej chwili przed podaniem dania). Ups, przepraszam, to pokazuje, że podróżuję za granicę i chyba nie jadłem makaronu od jakiegoś czasu. Ale analogia jest nadal całkiem dobra! -)

Wracając do Pythona i Ruby, dochodzimy do dwóch wielkich (pod względem właściwego języka - pozostawienia bibliotek i innych ważnych pomocniczych narzędzi, takich jak narzędzia i środowiska, jak osadzić / rozszerzyć każdy język itp., Poza na razie - i tak nie miałyby zastosowania do wszystkich IMPLEMENTACJI każdego języka, np. Jython vs Classic Python są dwiema implementacjami języka Python!):

  1. Iteratory i kody kodu Ruby kontra iteratory i generatory Pythona;

  2. RAZEM Ruby, nieokiełznana „dynamika”, w tym możliwość
    „ponownego otwarcia” dowolnej istniejącej klasy, w tym wszystkich wbudowanych, i zmiany jej zachowania w czasie wykonywania - w porównaniu z ogromną, ale ograniczoną dynamiką Pythona , która nigdy nie zmienia zachowania istniejącej klasy wbudowane i ich instancje.

Osobiście uważam 1 za obmycie (różnice są tak głębokie, że z łatwością mogłem zobaczyć, jak ludzie nienawidzą albo zbliżają się i odwracają drugie, ale na MOICH osobistych skalach plusy i minusy prawie się zwiększają); i 2 kluczowy problem - taki, który sprawia, że ​​Ruby jest znacznie bardziej odpowiedni do „majsterkowania”, ALE Python równie odpowiedni do stosowania w dużych aplikacjach produkcyjnych. W pewnym sensie jest to zabawne, ponieważ oba języki są tak DUŻO bardziej dynamiczne niż większość innych, że ostatecznie kluczowa różnica między nimi w moim POV powinna się na tym opierać - że Ruby „idzie do jedenastu” pod tym względem (odniesienie tutaj jest oczywiście „Spinal Tap”). W RubyMOGĘ TO ZROBIĆ ! To znaczy, mogę dynamicznie zmieniać wbudowaną klasę ciągów, tak aby a = „Hello World” b = „hello world”, jeśli a == b wydrukuje „równy! \ N” w przeciwnym razie wydrukuje „inny! \ N” end WILL wydrukuje ” równy". W Pythonie nie ma możliwości, aby to zrobić. Do celów metaprogramowania, implementacji eksperymentalnych ram i tym podobnych, ta niesamowita dynamiczna zdolność Ruby jest niezwykle wysoka pociągający. ALE - jeśli mówimy o dużych aplikacjach, opracowanych przez wiele osób i utrzymywanych przez jeszcze więcej, w tym wszelkiego rodzaju bibliotek z różnych źródeł i potrzebujących wejść do produkcji na stronach klienckich ... no cóż, NIE CHCĘ język, który jest tak dynamiczny, dziękuję bardzo. Nienawidzę samego pomysłu, że niektóre biblioteki nieświadomie łamią inne, niepowiązane z sobą te, które polegają na tym, że te łańcuchy są różne - to rodzaj głęboko i głęboko ukrytego „kanału”, pomiędzy fragmentami kodu, które WYGLĄDAJĄ osobno i MUSZĄ BYĆ osobne, co oznacza śmierć programowanie na dużą skalę. Pozwalając dowolnemu modułowi wpływać na zachowanie innych „potajemnie”, możliwość mutowania semantyki typów wbudowanych to po prostu ZŁY pomysł na programowanie aplikacji produkcyjnych,

Gdybym musiał użyć Ruby do tak dużej aplikacji, starałbym się polegać na ograniczeniach w stylu kodowania, wielu testach (do ponownego uruchomienia, gdy COKOLWIEK się zmieni - nawet tego, co powinno być całkowicie niezwiązane ...) i tym podobnych, aby zabronić korzystania z tej funkcji języka. Ale moim zdaniem NIE posiadanie tej funkcji jest jeszcze lepsze - tak jak sam Python byłby jeszcze lepszym językiem do programowania aplikacji, gdyby pewna liczba wbudowanych elementów mogła zostać „przybita”, więc WIEDZIAŁEM, że , np. len („ciao”) to 4 (zamiast martwić się podświadomie, czy ktoś zmienił wiązanie nazwy „len” w module wbudowanym ...). Mam nadzieję, że ostatecznie Python „dopracuje” swoje wbudowane funkcje.

Problem jest jednak niewielki, ponieważ ponowne wiązanie wbudowanych poleceń jest dość przestarzałe, a także rzadką praktyką w Pythonie. W Ruby wydaje mi się to znaczące - podobnie jak zbyt potężne funkcje makro innych języków (takich jak, powiedzmy, Dylan), moim zdaniem, stwarzają podobne ryzyko (mam nadzieję, że Python nigdy nie otrzyma tak potężnego systemu makro, nie liczy się urok „pozwalania ludziom definiować własne, specyficzne dla domeny małe języki osadzone w samym języku” - to, IMHO, osłabiłoby wspaniałą przydatność Pythona w programowaniu aplikacji, prezentując „atrakcyjny uciążliwość” niedoszłemu majsterkowiczowi, który czai się w sercu każdego programisty ...).

Alex

OscarRyz
źródło
9

Niektóre inne z:

http://www.ruby-lang.org/en/documentation/ruby-from-other-languages/to-ruby-from-python/

(Jeśli błędnie zinterpretowałem coś lub którykolwiek z nich zmienił się po stronie Ruby od czasu aktualizacji tej strony, ktoś może edytować ...)

Ciągi można modyfikować w języku Ruby, a nie w języku Python (gdzie nowe ciągi są tworzone przez „zmiany”).

Ruby ma pewne wymuszone konwencje przypadków, Python nie.

Python ma zarówno listy, jak i krotki (listy niezmienne). Ruby ma tablice odpowiadające listom w języku Python, ale nie ma niezmiennego wariantu.

W Pythonie możesz bezpośrednio uzyskać dostęp do atrybutów obiektu. W Ruby zawsze odbywa się to metodami.

W Ruby nawiasy dla wywołań metod są zwykle opcjonalne, ale nie w Pythonie.

Ruby ma funkcje publiczne, prywatne i chronione w celu wymuszania dostępu, zamiast konwencji Pythona polegającej na stosowaniu podkreślenia i zniekształcaniu nazw.

Python ma wiele elementów dziedziczenia. Ruby ma „mixiny”.

I kolejny bardzo istotny link:

http://c2.com/cgi/wiki?PythonVsRuby

Który w szczególności prowadzi do innego dobrego autorstwa Alexa Martellego , który również publikuje tutaj wiele świetnych rzeczy na SO:

http://groups.google.com/group/comp.lang.python/msg/028422d707512283

Anon
źródło
1
W rubinie możesz po prostu zamrozić swoją tablicę, aby zmienić ją na coś niezmiennego
user163365
Doskonały post Alex Martelli :)
Skilldrick
8

Nie jestem tego pewien, dlatego najpierw dodaję odpowiedź.

Python traktuje niezwiązane metody jako funkcje

Oznacza to, że możesz wywołać metodę tak jak theobject.themethod()lub przez TheClass.themethod(anobject).

Edycja: Chociaż różnica między metodami i funkcjami jest niewielka w Pythonie, a nie istnieje w Pythonie 3, to również nie istnieje w Ruby, po prostu dlatego, że Ruby nie ma funkcji. Kiedy definiujesz funkcje, tak naprawdę definiujesz metody w Object.

Ale nadal nie możesz przyjąć metody jednej klasy i nazwać jej jako funkcji, musiałbyś ponownie powiązać ją z obiektem, do którego chcesz wywołać, co jest znacznie bardziej skomplikowane.

Lennart Regebro
źródło
Ruby w ogóle nie ma funkcji. To powiedziawszy, TheClass.instance_method(:themethod).bind(anobject).callbędzie równoważnym rubinem.
Logan Capaldo
O. Więc jest jakaś magiczna klasa główna, kiedy definiujesz funkcję, która nie jest w jawnej klasie?
Lennart Regebro,
Tak, metody zdefiniowane na najwyższym poziomie są prywatnymi metodami Object.
Logan Capaldo,
1
FWIW, wydaje się, że w Pythonie funkcje i metody są w rzeczywistości tego samego typu, a ich różne zachowanie pochodzi od deskryptorów: users.rcn.com/python/download/… .
Bastien Léonard,
1
Ale jeśli powiążesz go z obiektem, nie będzie on niezwiązany. Duh. :-) I to samo jest w Pythonie. Po prostu Ruby nie ma w rzeczywistości żadnych funkcji. A to oznacza, że ​​moje stwierdzenie jest poprawne. Możesz wywołać metodę niezwiązaną tak, jakby była funkcją w Pythonie. I to jest rzeczywiście przydatne, oznacza to na przykład, że możesz wywołać metodę zdefiniowaną w klasie na obiekcie, który nie ma tej klasy, co czasem jest przydatne.
Lennart Regebro
7

Chciałbym wspomnieć o interfejsie API deskryptora Pythona, który umożliwia dostosowanie komunikacji między obiektami. Warto również zauważyć, że w Pythonie można zaimplementować alternatywny protokół, zastępując domyślną podaną przez domyślną implementację __getattribute__metody. Pozwól, że podam więcej szczegółów na temat wyżej wymienionych. Deskryptory są regularne zajęcia z __get__, __set__i / lub __delete__metody. Gdy interpreter napotka coś podobnego anObj.anAttr, wykonywane są następujące czynności:

  • __getattribute__anObjwywoływana jest metoda
  • __getattribute__ pobiera obiekt AnAttr ze słownika klasy
  • sprawdza, czy obiekt abAttr ma __get__, __set__albo __delete__wywoływalne obiekty
  • kontekst (tj. obiekt lub klasa obiektu wywołującego i wartość zamiast tego drugiego, jeśli mamy setter) jest przekazywany do obiektu na żądanie
  • wynik jest zwracany.

Jak wspomniano, jest to zachowanie domyślne. Można dowolnie zmieniać protokół poprzez ponowną implementację __getattribute__.

Ta technika jest znacznie potężniejsza niż dekoratorzy.

Giorgi
źródło
6

Ruby ma wbudowaną obsługę kontynuacji callcc.

Dlatego możesz wdrożyć fajne rzeczy, takie jak amb-operator

Dario
źródło
Chciałbym zrozumieć callcc. Czy możesz podać bardziej przyziemny scenariusz aplikacji niż „Dwuznaczny operator” McCarthy'ego, aby docenić jego merrity? Mam na myśli coś z prawdziwego świata, a nie funky CS ?!
ThomasH
„Funky CS stuff” jest prawdziwe. Poświęć trochę czasu na naukę: intertwingly.net/blog/2005/04/13/Continuations-for-Curmudgeons
Stephen Eilert
6

Na tym etapie Python nadal ma lepszą obsługę Unicode

John La Rooy
źródło
5

Python ma dokumenty i ruby ​​nie ... Lub jeśli nie, nie są one tak łatwo dostępne jak w Pythonie.

Ps. Jeśli się mylę, proszę, zostaw przykład? Mam obejście, które można łatwo dopasować do klas, ale chciałbym mieć coś w rodzaju „rodzimej” metody docstring.

rasjani
źródło
3
nie ma docstring, ale ma RDoc. Tak, nie tak łatwo dostępne, ale nie w 100% ukryte.
Omar Qureshi
Ruby nie używa dokumentów. Robi dokumentację w inny sposób.
Chuck,
1
Omar: tak, wiem o rdoc, ale afaik, nie są one „tak dostępne” jak dokumentacja Pythona. Na przykład, jeśli mam klasę i chcę wyprowadzić dokumentację rdoc z klasy, jest to dość ciężka praca. To, co zrobiłem, to to, że generuję dokumentację ri, którą staram się aktualizować, a następnie sam pobieram te informacje. Zdecydowanie nie do tego samego poziomu, co dokumenty Pythona ..
rasjani,
Dokumenty mogą być używane do dostarczania dokumentów. Czy jest coś takiego dla Ruby?
Lennart Regebro,
2
Tak, nazywa się to „Ruby Doctest”. Jeśli chodzi o testy dokumentów, najważniejsze jest to, że masz gdzieś czytelną dokumentację, która zawiera testowalne fragmenty kodu - nie ma znaczenia, czy jest to dokumentacja czy komentarz.
Chuck,
5

Ruby ma pętlę linia po linii nad plikami wejściowymi (flaga „-n”) z wiersza poleceń, dzięki czemu można go używać jak AWK. Ten Rubinowy jednowarstwowy:

ruby -ne 'END {puts $.}'

policzy linie takie jak AWK:

awk 'END{print NR}'

Ruby dostaje to za pośrednictwem Perla, który wziął to z AWK jako sposób na włączenie sysadminów do Perla bez konieczności zmiany sposobu, w jaki robią.

Pinochle
źródło
1
Chciałbym dodać, że obsługa wiersza poleceń Pythona jest raczej słaba. Oprócz brakującej automatycznej pętli nie można wstawić kilku instrukcji w jednym wierszu i przekazać jej jako interpretera jako argument w jednym wierszu poleceń. Przynajmniej tego nie zrobiłem.
ThomasH
Oczywiście, że możesz. Ale będziesz musiał (jak w każdym innym języku) dołączyć w cudzysłowie.
Lennart Regebro
Python nie jest przeznaczony do używania w wierszu poleceń, ponieważ musisz jasno python -c "import sys; print len(list(sys.stdin))"
wyrażać się na
5

Ruby ma pieczęci i gałązki, Python nie.

Edycja : I jedna bardzo ważna rzecz, o której zapomniałem (w końcu poprzednią było tylko trochę rozpalić :-p):

Python ma kompilator JIT ( Psyco ), wyraźnie niższy poziom języka do pisania szybszego kodu ( Pyrex ) oraz możliwość dodawania wbudowanego kodu C ++ ( Weave ).

fortran
źródło
To prawda, ale to tylko składnia.
Lennart Regebro,
6
Cóż, jeśli chcesz iść tą drogą: obie są kompletne w Turingu. Cała reszta to tylko składnia.
Jörg W Mittag,
Tak i różnica w składni importax ;-)
fortran
1
Jak to ważne, jeśli piszesz @foo lub self.foo?
Lennart Regebro
1
@ Jörg: OK, nazwij to inaczej niż „składnia”. Chodzi o to, że @foo i self.foo robią to samo, w rzeczywistości nie jest to funkcjonalność, którą ma Ruby, a Python nie.
Lennart Regebro
5

Mój pyton jest zardzewiały, więc niektóre z nich mogą znajdować się w Pythonie i po prostu nie pamiętam / nigdy się nie nauczyłem, ale oto kilka pierwszych, o których myślałem:

Biała przestrzeń

Ruby całkowicie zmienia białe znaki. Na początek nie trzeba nic wciskać (co oznacza, że ​​nie ma znaczenia, czy użyjesz 4 spacji lub 1 tabulacji). Wykonuje również kontynuację inteligentnej linii, więc następujące informacje są prawidłowe:

def foo(bar,
        cow)

Zasadniczo, jeśli zakończysz operatorem, dowiesz się, co się dzieje.

Mixiny

Ruby ma mixiny, które mogą rozszerzać instancje zamiast pełnych klas:

module Humor
  def tickle
    "hee, hee!"
  end
end
a = "Grouchy"
a.extend Humor
a.tickle    »   "hee, hee!"

Enums

Nie jestem pewien, czy jest to to samo, co generatory, ale od Ruby 1.9 ruby ​​jak wyliczenia, więc

>> enum = (1..4).to_enum
=> #<Enumerator:0x1344a8>

Odniesienie: http://blog.nuclearsquid.com/writings/ruby-1-9-what-s-new-what-s-changed

„Argumenty słów kluczowych”

Oba wymienione tam elementy są obsługiwane w Ruby, chociaż nie można pominąć takich wartości domyślnych. Możesz albo przejść w kolejności

def foo(a, b=2, c=3)
  puts "#{a}, #{b}, #{c}"
end
foo(1,3)   >> 1, 3, 3
foo(1,c=5) >> 1, 5, 3
c          >> 5

Zauważ, że c = 5 faktycznie przypisuje zmiennej c w zakresie wywołującym wartość 5 i ustawia parametr b na wartość 5.

lub możesz to zrobić za pomocą skrótów, które rozwiązują drugi problem

def foo(a, others)
  others[:b] = 2 unless others.include?(:b)
  others[:c] = 3 unless others.include?(:c)
  puts "#{a}, #{others[:b]}, #{others[:c]}"
end
foo(1,:b=>3) >> 1, 3, 3
foo(1,:c=>5) >> 1, 2, 5

Odniesienie: Pragmatyczny przewodnik dla programistów Rubiego

Scott Dugas
źródło
Twój drugi przykład foo (1, c = 5) nie robi tego, co myślisz. Ruby nie ma nazwanych parametrów.
horseyguy,
5
Python ma niejawną kontynuację linii w nawiasach (, [lub{
u0b34a0f6ae
5

Możesz mieć kod w definicji klasy zarówno w Ruby, jak i Python. Jednak w Ruby masz odniesienie do klasy (self). W Pythonie nie ma odniesienia do klasy, ponieważ klasa nie jest jeszcze zdefiniowana.

Przykład:

class Kaka
  puts self
end

self w tym przypadku jest klasą, a ten kod wypisuje „Kaka”. W Pythonie nie ma możliwości wydrukowania nazwy klasy ani w żaden inny sposób uzyskania dostępu do klasy z treści definicji klasy.

Lennart Regebro
źródło
Czy możesz podać więcej szczegółów (takich jak kod) dla pierwszego punktu?
Loïc Wolff
Przykładowy kod jest dobrym pomysłem, dodałem, że chociaż ten przypadek jest trywialny.
Lennart Regebro
@SilentGhost: Nie mogę wymyślić takiego, który nie jest tak naprawdę niejasny. :)
Lennart Regebro
możesz uzyskać dostęp do nazwy klasy wewnątrz klasy w python: class foo (): def init __ (self): print self .__ class .__
name__
1
@txwikinger: tak, ale nie w treści klasy, która jest wykonywana w tym samym czasie, co classinstrukcja.
Bastien Léonard,
4

Składnia nie jest drobną sprawą, ma bezpośredni wpływ na to, jak myślimy. Ma to również bezpośredni wpływ na reguły, które tworzymy dla używanych przez nas systemów. Jako przykład podajemy kolejność operacji ze względu na sposób pisania równań lub zdań matematycznych. Standardowa notacja matematyczna pozwala ludziom czytać ją na więcej niż jeden sposób i uzyskiwać różne odpowiedzi na podstawie tego samego równania. Gdybyśmy użyli notacji prefiksowej lub postfiksowej, stworzylibyśmy reguły, aby odróżnić, którymi liczbami podlegały manipulacje, zamiast mieć tylko reguły dotyczące kolejności obliczania wartości.

Standardowa notacja wyraźnie mówi o liczbach, o których mówimy, przy ustalaniu kolejności ich niejednoznaczności. Notacje przedrostków i postfiksów ustalają kolejność, w której obliczenia są proste, a liczby dwuznaczne. Python miałby już wielowierszowe lambdy, gdyby nie trudności spowodowane syntaktyczną białą spacją. (Istnieją propozycje odciągnięcia tego rodzaju rzeczy bez konieczności dodawania wyraźnych separatorów bloków).

Łatwiej jest mi napisać warunki, w których chcę, aby coś się zdarzyło, jeśli warunek jest fałszywy, dużo łatwiej jest napisać za pomocą instrukcji chyba w Rubim niż semantycznie równoważna konstrukcja „jeśli-nie” w Rubim lub innych językach. Jeśli większość języków, których ludzie używają dzisiaj, ma taką samą moc, to jak składnię każdego języka można uznać za trywialną rzecz? Po określonych cechach, takich jak bloki i mechanizmy dziedziczenia itp., Składnia jest najważniejszą częścią języka, a nie powierzchowną rzeczą.

To, co powierzchowne, to estetyczne cechy piękna, które przypisujemy składni. Estetyka nie ma nic wspólnego z tym, jak działa nasze poznanie, podobnie jak składnia.

umiejętności cieni
źródło
Ten „komentarz” jest trzy razy dłuższy niż dopuszczalny w komentarzu, niezależnie od przedstawiciela.
Andrew Grimm,
To właściwie wydaje mi się dobrą odpowiedzią. Wydano fragment „to jest komentarz”.
Bill the Lizard
3

Zaskoczony faktem, że nic nie wspominało o mechanizmie ruby ​​„brak metody”. Podałbym przykłady metod find_by _... w Railsach, jako przykład potęgi tej funkcji językowej. Domyślam się, że coś podobnego można zaimplementować w Pythonie, ale o ile wiem, nie ma go natywnie.

MikeIsGo
źródło
Python ma get_attribute , który realizuje w zasadzie to samo, co brak metody Ruby.
mipadi
3
Dlaczego programiści Pythona zawsze tak bardzo bolą, gdy mówi się o Ruby GDZIEKOLWIEK? Nie możesz zaprzeczyć, że to nieprawda.
aarona
method_missingmogą być emulowane w Pythonie w niektórych przypadkach: class M(): def __getattr__(self, n): return lambda: "Missing! " + n; M().hi(). Istnieją jednak niewielkie różnice i wątpię, czy jest to idiomatyczne w Pythonie :-)
1
@DJTripleThreat: Zaprzeczam, że to prawda.
Lennart Regebro,
3

Inną różnicę w lambdach między Pythonem a Ruby pokazuje problem generatora akumulatorów Paula Grahama . Przedruk tutaj:

Napisz funkcję foo, która przyjmuje liczbę n i zwraca funkcję, która przyjmuje liczbę i, i zwraca n inkrementowaną o i. Uwaga: (a) to liczba, nie liczba całkowita, (b), która jest zwiększana o, a nie plus.

W Ruby możesz to zrobić:

def foo(n)
  lambda {|i| n += i }
end

W Pythonie utworzyłbyś obiekt do przechowywania stanu n:

class foo(object):
    def __init__(self, n):
        self.n = n
    def __call__(self, i):
        self.n += i
        return self.n

Niektórzy ludzie mogą preferować wyraźne podejście w języku Python jako bardziej przejrzyste koncepcyjnie, nawet jeśli jest to nieco bardziej szczegółowe. Przechowujesz stan tak jak robisz dla czegokolwiek innego. Musisz tylko owinąć głowę wokół pomysłu na obiekty, które można wywoływać. Ale niezależnie od tego, które podejście preferuje się estetycznie, pokazuje jeden szacunek, w którym lambdy Ruby są silniejszymi konstrukcjami niż Python.

dormsbee
źródło
3
W Pythonie nie można zwiększać liczb, więc ograniczenie nie ma sensu. W Pythonie liczby są niezmienne. Jeśli zamiast tego zmienimy go na „plus”, klasa nie będzie potrzebna. Dlatego nie świadczy to o różnicy lambda, ale o różnicy w sposobie działania liczb. O ile oczywiście nie stworzysz zmiennej klasy liczb. :)
Lennart Regebro
2
Ograniczenie ma na celu wyjaśnienie pożądanego zachowania. Problemem jest: f = foo (10) f (2) >> 12 f (3) >> 15 ... lambda {| i | n + i} daje: f = foo (10) f (2) >> 12 f (3) >> 13 ... Liczby są również niezmienne w Rubim - na przykład nie można powiedzieć 2 + = 1. A n + = 1 jest w porządku w zwykłej funkcji Pythona, ale nie jest lambda. Jest więc kwestią tego, czym jest „n”, fakt, że jest on tworzony, gdy funkcja jest wywoływana i formowana jest lambda, że ​​można wykonać przypisanie w lambda (zamiast tylko wyrażeń), i że może on przechowywać wartość n przez wiele połączeń.
dormsbee
Nie wydaje mi się, żebyś musiał robić takie rzeczy w Pythonie. Funkcje można zdefiniować w ramach innych funkcji. def foo(n): def f(i): return n + i return f.
FMc,
2
To wciąż nie jest to samo, a twój przykład jest równoważny lambda Python w powyższym komentarzu. Wersja Ruby tworzy lambda, która utrzymuje stan między rozmowami. Opublikowany przykład pozwala skonfigurować wartość początkową dla n, ale funkcja zwracana przez foo zawsze będzie miała tę wartość początkową. Wersja Ruby rośnie. Powiedzmy, że f = foo (10). Pythonową wersja: F = (1)> 11, m = (1)> 11 Ruby wersja f.call (1) => 11 f.call (1) => 12
dormsbee
def foo(n): L=[n] def f(i): L[0] += i return L[0] return f. W Python3 możesz użyć nonlocalsłowa kluczowego.
jfs
3

python nazwał opcjonalne argumenty

def func(a, b=2, c=3):
    print a, b, c

>>> func(1)
1 2 3
>>> func(1, c=4)
1 2 4

AFAIK Ruby ma tylko ustawione argumenty, ponieważ b = 2 w deklaracji funkcji to wpływ, który zawsze się dołącza.

Batiste Bieler
źródło
3
co oznacza „Ruby ma tylko ustawione argumenty, ponieważ b = 2 w deklaracji funkcji jest wpływem, który zawsze się dołącza”, a nawet oznacza?
horseyguy,
3
Nie wiem, na jakiej planecie mieszkasz, ale def my_method(param1, optional = false)działa w Ruby 1.8.6, 1.8.7 i prawdopodobnie 1.9!
Robert K,
5
Zła Pchła i ludzie, którzy głosowali jego komentarz, nie spojrzeliście na przykład wystarczająco blisko. Jest w stanie pominąć bparametr w funcwywołaniu i nadal zachowuje wartość domyślną. Oznacza to, że bjest drugim argumentem w podpisie, ale może go pominąć, poprzedzając przedrostek drugim parametrem za pomocą c=. Ruby używa skrótów, aby to zasymulować, ale nie jest to dokładnie to samo.
maček
2

Ruby ma osadzoną dokumentację:

 =begin

 You could use rdoc to generate man pages from this documentation

 =end
ko-dos
źródło
5
Dokumenty kończą się jako część metod / klas, na których je ustawiłeś. Więc możesz pomóc (klasa), a pokażą ci dokumenty itp.
Lennart Regebro
2

W Rubim podczas importowania pliku z wymaganiem wszystkie elementy zdefiniowane w tym pliku znajdą się w globalnej przestrzeni nazw.

Dzięki Cargo możesz „ wymagać bibliotek bez zaśmiecania przestrzeni nazw ”.

# foo-1.0.0.rb
class Foo
  VERSION = "1.0.0"
end

# foo-2.0.0.rb
class Foo
  VERSION = "2.0.0"
end
>> Foo1 = import („foo-1.0.0”)
>> Foo2 = import („foo-2.0.0”)
>> Foo1 :: WERSJA
=> „1.0.0”
>> Foo2 :: WERSJA
=> „2.0.0”
Jonas Elfström
źródło
To raczej powinien być komentarz, a nie nowa odpowiedź.
Lennart Regebro 30.01.11