Che cosa ha Ruby che Python non ha, e viceversa?


263

Ci sono molte discussioni su Python vs Ruby, e tutte le trovo del tutto inutili, perché girano tutte intorno al motivo per cui la caratteristica X fa schifo nella lingua Y, o che afferma che la lingua Y non ha X, anche se in realtà lo è. So anche esattamente perché preferisco Python, ma è anche soggettivo e non aiuterebbe nessuno a scegliere, poiché potrebbero non avere gli stessi gusti nello sviluppo di me.

Sarebbe quindi interessante elencare le differenze, obiettivamente. Quindi nessun "lambda di Python fa schifo". Spiega invece cosa possono fare gli lambda di Ruby che Python non può fare. Nessuna soggettività Il codice di esempio è buono!

Non avere diverse differenze in una risposta, per favore. E vota quelli che conosci sono corretti e quelli che conosci sono errati (o soggettivi). Inoltre, le differenze di sintassi non sono interessanti. Sappiamo che Python fa con indentazione ciò che Ruby fa con parentesi e punte, e che @ è chiamato sé in Python.

AGGIORNAMENTO: Questo è ora un wiki della comunità, quindi possiamo aggiungere qui le grandi differenze.

Ruby ha un riferimento di classe nel corpo della classe

In Ruby hai un riferimento alla classe (sé) già nel corpo della classe. In Python non hai un riferimento alla classe fino al termine della costruzione della classe.

Un esempio:

class Kaka
  puts self
end

self in questo caso è la classe e questo codice stampa "Kaka". Non è possibile stampare il nome della classe o accedere in altro modo alla classe dal corpo della definizione della classe in Python (definizioni del metodo esterno).

Tutte le classi sono mutabili in Ruby

Ciò consente di sviluppare estensioni per le classi principali. Ecco un esempio di estensione di rotaie:

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

Python (immagina che non esistesse un ''.startswithmetodo):

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

Potresti usarlo su qualsiasi sequenza (non solo sulle stringhe). Per poterlo utilizzare è necessario importarlo esplicitamente , ad es from some_module import starts_with.

Ruby ha funzionalità di scripting simili al Perl

Ruby ha regexps di prima classe, $ -variables, il ciclo di input riga per riga awk / perl e altre funzionalità che lo rendono più adatto alla scrittura di piccoli script shell che coprono file di testo o fungono da codice colla per altri programmi.

Ruby ha continuazioni di prima classe

Grazie all'istruzione callcc. In Python puoi creare continuazioni con varie tecniche, ma non c'è supporto integrato nel linguaggio.

Ruby ha dei blocchi

Con l'istruzione "do" è possibile creare una funzione anonima multilinea in Ruby, che verrà passata come argomento nel metodo di fronte a do e chiamata da lì. In Python lo faresti invece passando un metodo o con generatori.

Rubino:

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

Python (i blocchi Ruby corrispondono a diversi costrutti in Python):

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

O

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

O

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

amethod(function)     # `function` is a callback

È interessante notare che la dichiarazione di convenienza in Ruby per chiamare un blocco si chiama "yield", che in Python creerà un generatore.

Rubino:

def themethod
    yield 5
end

themethod do |foo|
    puts foo
end

Pitone:

def themethod():
    yield 5

for foo in themethod():
    print foo

Sebbene i principi siano diversi, il risultato è sorprendentemente simile.

Ruby supporta la programmazione di stili funzionali (simili a pipe) più facilmente

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

Pitone:

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

Python ha generatori integrati (che sono usati come blocchi di Ruby, come notato sopra)

Python supporta i generatori nella lingua. In Ruby 1.8 è possibile utilizzare il modulo generatore che utilizza le continuazioni per creare un generatore da un blocco. Oppure potresti semplicemente usare un blocco / proc / lambda! Inoltre, in Ruby 1.9 le fibre sono e possono essere utilizzate come generatori e la classe Enumerator è un generatore integrato 4

docs.python.org ha questo esempio di generatore:

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

Contrastare questo con gli esempi di blocco sopra.

Python ha una gestione flessibile dello spazio dei nomi

In Ruby, quando importi un file con require, tutte le cose definite in quel file finiranno nel tuo spazio dei nomi globale. Ciò provoca l'inquinamento dello spazio dei nomi. La soluzione a ciò sono i moduli Rubys. Ma se si crea uno spazio dei nomi con un modulo, è necessario utilizzare quello spazio dei nomi per accedere alle classi contenute.

In Python, il file è un modulo e puoi importare i suoi nomi contenuti con from themodule import *, inquinando così lo spazio dei nomi se vuoi. Ma puoi anche importare solo i nomi selezionati con from themodule import aname, anothero puoi semplicemente import themodulee quindi accedere ai nomi con themodule.aname. Se vuoi più livelli nel tuo spazio dei nomi puoi avere dei pacchetti, che sono directory con moduli e un __init__.pyfile.

Python ha dotstrings

Le docstring sono stringhe collegate a moduli, funzioni e metodi e che possono essere introspezionate in fase di esecuzione. Questo aiuta a creare cose come il comando help e la documentazione automatica.

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

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

L'equivalente di Ruby è simile a javadocs e si trova sopra il metodo anziché all'interno. Possono essere recuperati in fase di runtime dai file usando l' uso dell'esempio # # source_location di 1.9

Python ha eredità multipla

Ruby non lo fa ("apposta" - vedi il sito web di Ruby, vedi qui come è fatto in Ruby ). Riutilizza il concetto di modulo come un tipo di classi astratte.

Python ha una comprensione elenco / dettatura

Pitone:

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

Rubino:

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

Pitone:

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

Rubino:

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

Rubino:

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

Python ha decoratori

Cose simili ai decoratori possono anche essere create in Ruby, e si può anche sostenere che non sono necessarie come in Python.

Differenze di sintassi

Ruby richiede "end" o "}" per chiudere tutti i suoi ambiti, mentre Python usa solo spazi bianchi. Ci sono stati recenti tentativi in ​​Ruby di consentire solo il rientro degli spazi bianchi http://github.com/michaeledgar/seamless


2
Per quanto riguarda l'ereditarietà multipla, dire semplicemente "Ruby no" è disonesto. Non riesco a pensare a niente che tu possa fare in Python con eredità multipla che non puoi fare in ruby ​​con i moduli / "ereditarietà mix". (È persino discutibile che includere moduli semplicemente semplici sia eredità multipla.)
Logan Capaldo,

2
Che tu possa fare la stessa cosa in un altro modo è un argomento che non regge. Puoi fare tutto qui in qualche altro modo. E poiché i moduli non sono classi, non è ereditarietà multipla. Sei il benvenuto per fornire esempi di codice di come viene eseguita l'ereditarietà multipla di Pythons rispetto ai moduli Rubys.
Lennart Regebro,

3
I moduli non sono classi ma le classi sono moduli. % ruby ​​-e 'p Class <Modulo' true
Logan Capaldo,

8
-1 Sfortunatamente, questa domanda non raggiunge il suo obiettivo e la maggior parte delle presunte differenze non sono affatto differenze e la disinformazione abbonda!
pregiudizio,

2
I moduli includono infatti ereditarietà multiple, non solo concettuali ma nell'attuazione effettiva nell'interprete Ruby. Quando un modulo Ruby è incluso, viene iniettato nella catena di eredità esattamente allo stesso modo delle superclassi. La risoluzione del metodo è la stessa. In Ruby i moduli multipli includono ereditarietà multiple. Chiunque voglia contestare questo come semanticamente "non è la stessa cosa" come eredità multipla è solo pedante. Qual è il punto in cui qualcosa non è la "stessa cosa" se l'effetto è identico e altrettanto facilmente raggiungibile? Una distinzione senza differenze.
Dave Sims,

Risposte:


34

Ruby ha i concetti di blocchi , che sono essenzialmente zucchero sintattico attorno a una sezione di codice; sono un modo per creare chiusure e passarle a un altro metodo che può o meno utilizzare il blocco. Un blocco può essere richiamato in seguito tramite yieldun'istruzione.

Ad esempio, una semplice definizione di un eachmetodo Arraypotrebbe essere simile a:

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

Quindi puoi invocarlo in questo modo:

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

Python ha funzioni / chiusure / lambdas anonime, ma non ha dei blocchi poiché manca un po 'dello zucchero sintattico utile. Tuttavia, c'è almeno un modo per farlo in modo ad hoc. Vedi, per esempio, qui .


6
@Lennart: a parte il tuo esempio, essere orribile è anche sintatticamente sbagliato.

2
@unbeknow: A, giusto. Ma se fosse stata una funzione anziché una stampa, avrebbe funzionato. In Python 3 funziona: [stampa (e + 5) per e in [1,2,3,4]] E quando si tratta di orribilità, penso che il codice ruby ​​sopra sia orribile, quindi è chiaramente soggettivo e quindi non un parte di questa domanda. @John Non sto dicendo che è equivalente, sto dicendo che non è evidente quale sia la differenza dal tuo esempio. @Bastien, no, ma che puoi fare cose simili non significa che siano uguali. Le differenze qui dovrebbero essere elencate anche se ci sono altri modi per farlo.
Lennart Regebro,

22
Sono un programmatore Python. Vorrei vedere un esempio di come i blocchi di Ruby ti aiutano a scrivere qualcosa di più conciso o più bello che con Python perché non ha blocchi. Il tuo esempio potrebbe essere scritto: per i in [1, 2, 3, 4]: print (i + 5). Non usa blocchi, ma è conciso e bello come pure il rubino di ogni esempio.
Manuel Ceron,

10
@Manuel, i proc sono utili per collegare funzioni a strutture di dati non banali (alberi, grafici ...) che non possono essere "for-loop" e quindi richiedono speciali iteratori per attraversare. I blocchi, che sono proc anonimi, consentono di implementare il funzione in una espressione (rispetto a definire quindi implementare) che accelera notevolmente il processo di codifica e chiarisce l'intento. Ad esempio, se si creasse una struttura di dati grafici, è possibile definire un iteratore "ciascuno" e quindi mixare Enumerable che ti darebbe immediatamente accesso a dozzine di iteratori (sort, all ?, any ?, grep). Ora chiami un blocco ...
bias

4
@RommeDeSerieux, perché ha bisogno di un nome nella lingua! Inoltre, è un oggetto funzione, non una funzione. Diamo un'occhiata a Ruby Docs: "Gli oggetti Proc sono blocchi di codice che sono stati associati a un insieme di variabili locali", quindi un Proc anonimo è solo il blocco e non è certamente solo una funzione!
pregiudizio,

28

Esempio di Python

Le funzioni sono variabili di prima classe in Python. Puoi dichiarare una funzione, passarla come oggetto e sovrascriverla:

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

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

Questa è una caratteristica fondamentale dei moderni linguaggi di scripting. Anche JavaScript e Lua lo fanno. Ruby non tratta le funzioni in questo modo; la denominazione di una funzione la chiama.

Certo, ci sono modi per fare queste cose in Ruby, ma non sono operazioni di prima classe. Ad esempio, è possibile racchiudere una funzione con Proc.new per trattarla come una variabile, ma non è più una funzione; è un oggetto con un metodo "call".

Le funzioni di Ruby non sono oggetti di prima classe

Le funzioni di Ruby non sono oggetti di prima classe. Le funzioni devono essere racchiuse in un oggetto per passarle in giro; l'oggetto risultante non può essere trattato come una funzione. Le funzioni non possono essere assegnate in un modo di prima classe; invece, una funzione nel suo oggetto contenitore deve essere chiamata per modificarli.

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!"    

8
Sei gravemente confuso. Gli oggetti di prima classe sono assegnati per incarico: x = ynon per chiamata self.class.send(:define_method, :func, method(:func2)). Il tuo "controesempio" mostra come le funzioni di Ruby non siano di prima classe. Se non sei d'accordo, sentiti libero di pubblicare la tua risposta; non confondere la tua confusione nella mia.
Glenn Maynard,

7
Le cose definite da def ... endin ruby ​​non sono funzioni. Sono metodi (il modo in cui li hai definiti, di Kernel). I metodi possono essere non associati (usando il #methodmetodo), che sono quindi oggetti. La cosa più vicina alle funzioni di ruby ​​sono le Procistanze, che sono anche oggetti e possono essere passate in giro o invocate. Ha anche una sintassi speciale per passare un singolo callback Proca un metodo, come discute John Feminella nella sua risposta .
rampion

4
@Glenn: Capisco quello che stai dicendo, ma mi dispiacerebbe con l'affermazione che le funzioni di ridefinizione di Ruby - i metodi sono un concetto semantico separato. Se vuoi giocare al gioco di definizione, il codice più imperativo sono le procedure, non le funzioni. Non sto cercando di essere difficile, è solo che credo che le definizioni e l'esattezza siano importanti. Concordo sul fatto che manipolare un UnboundMethodpuò essere un PITA, comunque.
rampion

5
@Glenn: la bellezza è negli occhi di chi guarda. Tuttavia, i metodi sono oggetti di prima classe soddisfacendo la definizione (in questo caso mi riferisco alla definizione di Wikipedia). Forse, hai qualche altra definizione di prima classe? Hanno bisogno di una Platinum Frequent Flier Card per essere imbattuti in prima classe?
pregiudizio il

4
@Glenn Controlla la sezione FAQ SO "Altre persone possono modificare le mie cose ?!" - questo è un Wiki della comunità.
pregiudizio

26

Alla fine tutte le risposte saranno soggettive ad un certo livello e le risposte pubblicate finora dimostrano praticamente che non puoi puntare a nessuna caratteristica che non è realizzabile nell'altra lingua in un modo altrettanto piacevole (se non simile) , poiché entrambe le lingue sono molto concise ed espressive.

Mi piace la sintassi di Python. Tuttavia, devi scavare un po 'più in profondità della sintassi per trovare la vera bellezza di Ruby. C'è una bellezza da zen nella consistenza di Ruby. Sebbene nessun esempio banale possa spiegarlo completamente, proverò a trovarne uno qui solo per spiegare cosa intendo.

Invertire le parole in questa stringa:

sentence = "backwards is sentence This"

Quando pensi a come lo faresti, dovresti fare quanto segue:

  1. Dividi la frase in parole
  2. Invertire le parole
  3. Ricollegare le parole in una stringa

In Ruby, faresti questo:

sentence.split.reverse.join ' '

Esattamente come ci pensi, nella stessa sequenza, un metodo chiama dopo l'altro.

In Python, sarebbe più simile a questo:

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

Non è difficile da capire, ma non ha lo stesso flusso. Il soggetto (frase) è sepolto nel mezzo. Le operazioni sono un mix di funzioni e metodi oggetto. Questo è un esempio banale, ma si scoprono molti esempi diversi quando si lavora e si capisce veramente Ruby, specialmente su compiti non banali.


1
Sono d'accordo. Ruby sembra fluire naturalmente quando lo scrivo, quindi "zenlike" è un buon termine.
Tin Man,

18

Python ha una mentalità "siamo tutti adulti qui". Quindi, scoprirai che Ruby ha cose come le costanti mentre Python no (anche se le costanti di Ruby sollevano solo un avvertimento). Il modo di pensare di Python è che se vuoi rendere costante qualcosa, dovresti mettere i nomi delle variabili in maiuscolo e non cambiarlo.

Ad esempio, Ruby:

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

Pitone:

>>> PI = 3.14
>>> PI += 1
>>> PI
4.1400000000000006

19
Ah .. questo mi ricorda che almeno in Python 2. *, sei stato in grado di fare "Vero, Falso = Falso, Vero" ... Credo che lo abbiano corretto correttamente in Python 3.0 ... è qualcosa che dovresti essere impedito di fare.
Tom,

11
Personalmente, mi piacciono le linee guida rigorose applicate dalla lingua perché rende coerente tutto il codice scritto in quella lingua. Essa costringe a seguire le linee guida, e gli sviluppatori di lettura il codice può dire a colpo d'occhio come stanno le cose. Mentre la maggior parte dei programmatori Python usano lo stesso "stile" generale, ho visto alcune incongruenze piuttosto grandi che non sarebbero possibili in Ruby.
Sasha Chedygov,

8
@bias - Non sono sicuro del perché mi stai sottovalutando. Questa risposta non è d'accordo o in disaccordo con il modo pitone di fare le cose. È solo una dichiarazione di fatto.
Jason Baker,

13
@Jason "siamo tutti adulti qui" è una dichiarazione di fatto? Vorrei dire che un'opinione si è chiusa attorno a una caratteristica, da cui il voto negativo.
pregiudizio

7
@bias - Dire che "siamo tutti adulti qui" non è stato un minimo. È un motto non ufficiale di Python, che credo sia meglio spiegato qui: mail.python.org/pipermail/tutor/2003-October/025932.html
Evan Porter,

18

Puoi importare solo funzioni specifiche da un modulo in Python. In Ruby, importi l'intero elenco di metodi. Potresti "non importarli" in Ruby, ma non è questo il punto.

MODIFICARE:

prendiamo questo modulo di Ruby:


module Whatever
  def method1
  end

  def method2
  end
end

se lo includi nel tuo codice:


include Whatever

vedrai che sia method1 e method2 sono stati aggiunti allo spazio dei nomi. Non puoi importare solo method1 . O li importi entrambi o non li importi affatto. In Python puoi importare solo i metodi di tua scelta. Se questo avesse un nome forse si chiamerebbe importazione selettiva?


2
Oh giusto! A Python piacciono gli spazi dei nomi. Non è così per Ruby? Non sei import bla; bla.foo()in Ruby?
Lennart Regebro,

2
Puoi importare solo la funzione a, non tutte le funzioni all'interno. Se ad esempio includi un modulo Ruby che dichiara 3 funzioni non statiche, le ottieni tutte incluse nel tuo spazio dei nomi. In Python dovresti scrivere dall'importazione del modulo *.
Geo,

6
Ciò non porta a un sacco di disordine nello spazio dei nomi?
Lennart Regebro,

1
Penso di si. Questo è ciò che odio dei moduli di Ruby.
Geo,

8
Ruby non ha davvero un sistema modulare nello stesso senso di Python. requisito funziona fondamentalmente come inclusione testuale con alcuni controlli per l'inclusione duplicata. È possibile (ab) utilizzare i moduli come spazi dei nomi, ma in modulerealtà è un termine improprio. I moduli sono fondamentalmente classi sans il new, allocatemetodi. Funzionano meglio come un modo per condividere il codice su una base per classe / oggetto, non come meccanismo per il partizionamento delle librerie o per condividere il codice tra programmi.
Logan Capaldo,

16

Dal sito Web di Ruby :

Somiglianze Come per Python, in Ruby, ...

  • C'è un prompt interattivo (chiamato irb).
  • Puoi leggere documenti dalla riga di comando (con il comando ri anziché pydoc).
  • Non ci sono terminatori di linea speciali (tranne la solita newline).
  • I letterali di stringa possono estendersi su più righe come le stringhe a tre virgolette di Python.
  • Le parentesi sono per gli elenchi e le parentesi sono per i dadi (che, in Ruby, sono chiamati "hash").
  • Gli array funzionano allo stesso modo (aggiungendoli a3 = [ a1, a2 ]si ottiene un array lungo, ma componendoli in questo modo si ottiene un array di array).
  • Gli oggetti sono tipizzati in modo forte e dinamico.
  • Tutto è un oggetto e le variabili sono solo riferimenti ad oggetti.
  • Sebbene le parole chiave siano leggermente diverse, le eccezioni funzionano allo stesso modo.
  • Hai strumenti doc incorporati (Ruby si chiama rdoc).

Differenze Diversamente da Python, in Ruby, ...

  • Le stringhe sono mutabili.
  • Puoi creare costanti (variabili il cui valore non intendi modificare).
  • Esistono alcune convenzioni caso applicate (es. I nomi delle classi iniziano con una lettera maiuscola, le variabili iniziano con una lettera minuscola).
  • Esiste un solo tipo di contenitore elenco (un array) ed è modificabile.
  • Le stringhe tra virgolette doppie consentono sequenze di escape (come \ t) e una sintassi speciale di "sostituzione di espressioni" (che consente di inserire i risultati delle espressioni di Ruby direttamente in altre stringhe senza dover "aggiungere" + "stringhe" + "insieme") . Le stringhe a virgoletta singola sono come le "stringhe" di Python.
  • Non ci sono lezioni di "nuovo stile" e "vecchio stile". Solo un tipo.
  • Non accedi mai direttamente agli attributi. Con Ruby, sono tutte chiamate al metodo.
  • Le parentesi per le chiamate di metodo sono generalmente opzionali.
  • C'è pubblico, privato e protetto per imporre l'accesso, al posto di quello di Python _voluntary_ underscore __convention__.
  • I "mixin" sono usati al posto dell'eredità multipla.
  • È possibile aggiungere o modificare i metodi delle classi integrate. Entrambe le lingue ti consentono di aprire e modificare le classi in qualsiasi momento, ma Python impedisce la modifica dei built-in - Ruby no.
  • Hai true e false invece di True e False (e zero invece di None).
  • Se testato per la verità, solo falso e zero valutano un valore falso. Tutto il resto è vero (compresi 0, 0,0, "" e []).
  • È elsif invece di elif.
  • È necessario invece di importare. Altrimenti, l'utilizzo è lo stesso.
  • I commenti di solito sulla linea (e) sopra le cose (anziché le stringhe sottostanti) sono usati per generare documenti.
  • Esistono numerose scorciatoie che, sebbene ti diano di più da ricordare, impari rapidamente. Tendono a rendere Ruby divertente e molto produttivo.

2
"È necessario anziché importare. Altrimenti, l'utilizzo è lo stesso." Sembra essere completamente impreciso.
Glenjamin,

Ci sono anche set in Ruby che le persone usano raramente, ma sono integrati. Quindi posso dire stuff_in_backpack = Set.new; stuff_in_backpack << "computer"; stuff_in_backpack << "scarpe"; # e il set conterrà tutti i valori senza garantire l'ordine.
Zachaysan,

12

Ciò che Ruby ha su Python sono le sue capacità di linguaggio di scripting. Linguaggio di scripting in questo contesto che significa essere utilizzato per il "codice colla" negli script di shell e nella manipolazione generale del testo.

Questi sono per lo più condivisi con Perl. Espressioni regolari integrate di prima classe, $ -Variables, utili opzioni da riga di comando come Perl (-a, -e) ecc.

Insieme alla sua sintassi concisa ma epxressiva, è perfetto per questo tipo di attività.

Python per me è più un linguaggio commerciale tipizzato in modo dinamico che è molto facile da imparare e ha una sintassi ordinata. Non "bello" come Ruby ma pulito. Quello che Python ha su Ruby per me è il vasto numero di associazioni per altre librerie. Associazioni a Qt e ad altre librerie GUI, molte librerie di supporto di giochi ee e. Ruby ha molto meno. Mentre i collegamenti molto usati, ad esempio ai database, sono di buona qualità, ho trovato che le librerie di nicchia erano meglio supportate in Python anche se per la stessa libreria esiste anche un collegamento Ruby.

Quindi, direi che entrambe le lingue hanno il suo uso ed è il compito che definisce quale usare. Entrambi sono abbastanza facili da imparare. Li uso fianco a fianco. Ruby per gli script e Python per le app autonome.


1
Domanda di qualcuno che non conosce ancora Ruby: cosa intendi con "$ -Variables"? Intendi le variabili globali? In tal caso, in Python, una variabile definita in un modulo al di fuori di una classe o di una funzione è globale. In caso contrario, qual è la distinzione?
Anon,

1
Anon: se si dichiara una variabile $ in qualsiasi parte del codice, è globale a causa del prefisso. Pertanto, non importa dove è definito, è sempre globale ed è sempre noto come tale.
Robert K,

8
Non esattamente, in realtà intendevo variabili predefinite come $ _, $ 1 ecc. Queste sono riempite automaticamente di valori dal rubino stesso. $ _ è l'ultima riga letta. $ 1, $ 2, ecc. Sono le corrispondenze di espressioni regolari dell'ultima corrispondenza. Vedi qui per un elenco completo: zenspider.com/Languages/Ruby/QuickRef.html#17 Fondamentalmente è un trucco per gli script compatti. Puoi ottenere tutte le informazioni anche tramite chiamate API, ma usando $ variabili è più conciso. Questo tipo di variabili non si adatta allo stile di Python, ma le hanno deliberatamente escluse.
Haffax,

Grazie per quel link zenspider - avevo cercato qualcosa del genere per una rapida sensazione (non tutorial) per Ruby.
Anon,

12

Non credo che "Ruby abbia X e Python no, mentre Python ha Y e Ruby no" è il modo più utile per vederlo. Sono lingue abbastanza simili, con molte abilità condivise.

In larga misura, la differenza è ciò che la lingua rende elegante e leggibile. Per usare un esempio che hai citato, entrambi teoricamente hanno lambda, ma i programmatori Python tendono ad evitarli, e i costrutti creati usando loro non sembrano affatto leggibili o idiomatici come in Ruby. Quindi in Python, un buon programmatore vorrà prendere una strada diversa per risolvere il problema rispetto a Ruby, solo perché in realtà è il modo migliore per farlo.


5
Concordo sul fatto che i lambda abbiano una portata limitata e non siano utili in molti casi. Tuttavia, non penso sia giusto dire che i programmatori Python li evitano come la peste.
Jason Baker,

1
Concordo sul fatto che i lambda vengano usati spesso con Python, come per la mappa, il filtro, la riduzione. La grande differenza sembra essere che le lambda di Python sono limitate alle espressioni mentre i blocchi di Ruby possono essere multilinea e comportare istruzioni. La mia impressione generale da quello che ho letto su Ruby è che questa caratteristica in particolare fa sì che i rubyisti adottino l'approccio DSL, mentre i pitonisti hanno maggiori probabilità di creare API. Le mie informazioni su Ruby sono comunque molto superficiali.
Anon,

2
@Lennart: i blocchi multilinea sono usati continuamente in Ruby - più spesso di quanto io veda lambda usati nel codice idiomatico di Python, in realtà. Per un esempio comune, consultare info.michael-simons.eu/2007/08/06/rails-respond_to-method .
Chuck,

1
@Lennart: No, non utilizza la resa. (La resa di Ruby è completamente diversa da quella di Python - non restituisce un generatore.) Non sarebbe significativo scrivere for format in respond_to(). Il respond_tometodo non restituisce nulla di significativo: risponde semplicemente alla richiesta HTTP corrente. L' doin respond_to doè l'inizio di un blocco. In quel blocco, parliamo di un oggetto temporaneo (etichettato formatin questo esempio) che implementa un DSL di base per rispondere a una richiesta HTTP.
Chuck,

3
Puoi "mischiare Enumerable" con un generatore e ottenere immediatamente 30 nuovi e meravigliosi iteratori? Devi guardare la lingua nel suo insieme prima di capire perché i blocchi / Proc sono fantastici.
pregiudizio,

12

Vorrei suggerire una variante della domanda originale, "Che cosa ha Ruby che Python non ha, e viceversa?" che ammette la risposta deludente, "Beh, cosa puoi fare con Ruby o Python che non si può fare in Intercal?" Niente a quel livello, perché Python e Ruby fanno entrambi parte della vasta famiglia reale seduta sul trono di essere Turing approssimativa.

Ma che dire di questo:

Cosa si può fare con grazia e bene in Python che non si può fare in Ruby con tanta bellezza e buona ingegneria, o viceversa?

Potrebbe essere molto più interessante del semplice confronto delle caratteristiche.


un commento al massimo. ancora il mio +1
nawfal

11

Python ha una sintassi esplicita e incorporata per l'elenco-comprehenion e generatori mentre in Ruby useresti blocchi mappa e codice.

Confrontare

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

per

res = (1..10).map{ |x| x*x }

come le comprensioni delle liste non sono un semplice Python ? e c'è una funzione mappa anche in Python.
SilentGhost,

Ma non c'è sintassi di comprensione dell'elenco in Ruby
Dario,

Python: res = map (lambda x: x * x, range (1,10))
GogaRieger,

Python:res=map(2 .__rpow__, range(1,10))
John La Rooy,

11

"Le variabili che iniziano con una lettera maiuscola diventano costanti e non possono essere modificate"

Sbagliato. Loro possono.

Riceverai un avviso solo se lo fai.


2
Se una lingua ti dà un avvertimento per un'operazione, è mia opinione che tu possa benissimo considerare l'operazione "impossibile". Qualsiasi altra cosa è follia.
porgarmingduod

11

Un po 'di più dal lato dell'infrastruttura:

  • Python ha una migliore integrazione con C ++ (tramite cose come Boost.Python , SIP e Py ++ ) rispetto a Ruby, dove le opzioni sembrano essere direttamente scritte sull'API dell'interprete Ruby (cosa che puoi fare anche con Python, ovviamente, ma in entrambi i casi farlo è di basso livello, noioso e soggetto a errori) o usa SWIG (che, mentre funziona e sicuramente è ottimo se vuoi supportare molte lingue, non è bello come Boost.Python o SIP se stai specificamente cercando di associare C ++).

  • Python ha diversi ambienti di applicazioni web (Django, Pylons / Turbogears, web.py, probabilmente almeno una mezza dozzina di altri), mentre Ruby (effettivamente) ne ha uno: Rails. (Esistono altri framework Web Ruby, ma a quanto pare è difficile ottenere molta trazione contro Rails). Questo aspetto è buono o cattivo? Difficile da dire, e probabilmente abbastanza soggettivo; Posso facilmente immaginare argomenti secondo cui la situazione di Python è migliore e che la situazione di Ruby è migliore.

  • Culturalmente, le comunità Python e Ruby sembrano in qualche modo diverse, ma posso solo accennare a questo dato che non ho molta esperienza di interazione con la comunità Ruby. Lo sto aggiungendo principalmente nella speranza che qualcuno che abbia molta esperienza con entrambi possa amplificare (o rifiutare) questa affermazione.


7
Il tuo secondo punto è nella migliore delle ipotesi male informato. Dovresti iniziare guardando Rack e Sinatra
Max Ogden il

6
Noto esplicitamente che esistono altri stack Rails; Non penso che qualcuno li stia effettivamente usando. Controllare Sinatra e Rack non ha esattamente cambiato quell'impressione. Pensi davvero, diciamo, Sinatra (94 domande SO in totale), o Camping (2 domande SO in totale), o una qualsiasi delle altre, ha effettivamente una base / comunità di utenti reali? La maggior parte di loro non ha nemmeno utenti reali, per quanto ne so. Confronta con Django (4K +) o Rails (7K +), o anche web.py per quella materia.
Jack Lloyd,

1
Sinatra è in realtà piuttosto popolare per diversi compiti leggeri grazie al suo DSL. È solo meno utilizzato perché MVC di Rail offre di più. Rails è in realtà costruito su Rack - Questo è ciò che rende possibile Phusion Passenger.
alternativa il

11

Spudoratamente copia / incolla da: Alex Martelli risponde al thread " Cosa c'è di meglio di Ruby di Python " dalla mailing list comp.lang.python .

18 agosto 2003, 10:50 Erik Max Francis ha scritto:

"Brandon J. Van Every" ha scritto:

Cosa c'è di meglio di Ruby di Python? Sono sicuro che c'è qualcosa. Che cos'è?

Non avrebbe molto più senso chiedere alla gente di Ruby questo, piuttosto che alla gente di Python?

Potrebbe, o no, a seconda dei propri scopi - per esempio, se i propri scopi includono uno "studio sociologico" della comunità Python, allora porre domande a quella comunità probabilmente risulterà più rivelatore di informazioni al riguardo, piuttosto che metterle altrove :-).

Personalmente, ho colto volentieri l'occasione di seguire il tutorial di un giorno sul Ruby di Dave Thomas nell'ultimo OSCON. Sotto una sottile patina di differenze di sintassi, trovo Ruby e Python sorprendentemente simili - se stavo calcolando l'albero di spanning minimo tra quasi tutte le lingue, sono abbastanza sicuro che Python e Ruby sarebbero le prime due foglie in cui fondersi un nodo intermedio :-).

Certo, mi stanco, in Ruby, di digitare la "fine" sciocca alla fine di ogni blocco (piuttosto che solo unindenting) - ma poi riesco a evitare di digitare ugualmente la sciocca ":" di cui Python richiede l' inizio di ogni blocco, quindi è quasi un lavaggio :-). Altre differenze di sintassi come '@foo' rispetto a 'self.foo', o il significato più elevato del caso in Ruby vs Python, sono davvero altrettanto irrilevanti per me.

Altri senza dubbio basano la loro scelta di linguaggi di programmazione proprio su tali questioni e generano i dibattiti più importanti - ma per me questo è solo un esempio di una delle leggi del Parkinson in azione (l'ammontare del dibattito su una questione è inversamente proporzionale alla questione della questione importanza reale).

Modifica (di AM 19/06/2010 11:45): questo è anche noto come "dipingere il ciclismo" (o, in breve, "ciclismo") - il riferimento è, ancora una volta, a Northcote Parkinson, che ha dato "dibattiti su quale colore dipingere il bikeshed "come un tipico esempio di" dibattiti caldi su argomenti banali ". (end-of-Edit).

Una differenza di sintassi che trovo importante, e a favore di Python - ma altre persone penseranno senza dubbio al contrario - è "come si chiama una funzione che non accetta parametri". In Python (come in C), per chiamare una funzione applichi sempre l '"operatore di chiamata" - parentesi finali subito dopo l'oggetto che stai chiamando (all'interno di quelle parentesi finali vanno gli argomenti che stai passando nella chiamata - se non passi argomenti, quindi le parentesi sono vuote). Questo lascia la semplice menzione di qualsiasioggetto, senza operatore coinvolto, poiché significa solo un riferimento all'oggetto - in qualsiasi contesto, senza casi speciali, eccezioni, regole ad hoc e simili. In Ruby (come in Pascal), per chiamare una funzione CON argomenti si passa l'args (normalmente tra parentesi, anche se ciò non è sempre il caso) - MA se la funzione non prende argomenti, semplicemente menzionando implicitamente la funzione la chiama. Questo può soddisfare le aspettative di molte persone (almeno, senza dubbio, quelle la cui unica precedente esperienza di programmazione è stata con Pascal, o altri linguaggi con "chiamate implicite" simili, come Visual Basic) - ma per me significa che il la semplice menzione di un oggetto può ORE significare un riferimento all'oggetto, O una chiamata all'oggetto, a seconda del tipo di oggetto - e in quei casi in cui posso " Per ottenere un riferimento all'oggetto semplicemente citandolo, dovrò usare esplicito "dammi un riferimento a questo, NON chiamarlo!" operatori che non sono necessari altrimenti. Sento che ciò influisce sulla "prima classe" delle funzioni (o metodi, o altri oggetti richiamabili) e sulla possibilità di scambiare oggetti senza problemi. Pertanto, per me, questa specifica differenza di sintassi è un grave segno nero contro Ruby - ma capisco perché gli altri farebbero diversamente, anche se difficilmente potrei essere in disaccordo con più veemente :-). di funzioni (o metodi, o altri oggetti richiamabili) e la possibilità di scambiare oggetti senza problemi. Pertanto, per me, questa specifica differenza di sintassi è un grave segno nero contro Ruby - ma capisco perché gli altri farebbero diversamente, anche se difficilmente potrei essere in disaccordo con più veemente :-). di funzioni (o metodi, o altri oggetti richiamabili) e la possibilità di scambiare oggetti senza problemi. Pertanto, per me, questa specifica differenza di sintassi è un grave segno nero contro Ruby - ma capisco perché gli altri farebbero diversamente, anche se difficilmente potrei essere in disaccordo con più veemente :-).

Sotto la sintassi, entriamo in alcune importanti differenze nella semantica elementare - ad esempio, le stringhe in Ruby sono oggetti mutabili (come in C ++), mentre in Python non sono mutabili (come in Java, o credo C #). Ancora una volta, le persone che giudicano principalmente in base a ciò che hanno già familiarità possono pensare che questo sia un vantaggio per Ruby (a meno che non abbiano familiarità con Java o C #, ovviamente :-). Io penso che le stringhe immutabili siano un'ottima idea (e non mi sorprende che Java, indipendentemente da me, abbia reinventato quell'idea che era già in Python), anche se non mi dispiacerebbe avere un tipo di "buffer di stringa mutabile" (e idealmente uno con una migliore facilità d'uso rispetto ai "buffer di stringhe" di Java); e non do questo giudizio a causa della familiarità. Prima di studiare Java, tutti i dati sono immutabili, tutte le lingue che conoscevo avevano stringhe mutabili - eppure quando ho visto per la prima volta l'idea di stringa immutabile in Java (che ho imparato molto prima di apprendere Python), mi è sembrato immediatamente eccellente, un'ottima soluzione per la semantica di riferimento di un linguaggio di programmazione di livello superiore (al contrario della semantica di valore che si adatta meglio ai linguaggi più vicini alla macchina e più lontani dalle applicazioni, come C) con stringhe come di prima classe, integrate (e piuttosto cruciale) tipo di dati.

Ruby presenta alcuni vantaggi nella semantica elementare, ad esempio la rimozione delle "liste contro le tuple" di Python in modo estremamente sottile. Ma soprattutto il punteggio (come lo conservo, con semplicità un grande vantaggio e sottili, intelligenti distinzioni un notevole meno) è contro Ruby (ad esempio, con intervalli sia chiusi che semiaperti, con le notazioni a..b e a .. .b [qualcuno vuole affermare che è ovvio quale è quale? -)], è sciocco - IMHO, ovviamente!). Ancora una volta, le persone che considerano il fatto di avere un sacco di cose simili ma sottilmente diverse nel cuore di una lingua un PLUS, piuttosto che un MINUS, contano ovviamente questi "viceversa" da come li conto :-).

Non farti ingannare da questi confronti nel pensare che le due lingue siano moltodiverso, sia chiaro. Non lo sono. Ma se mi viene chiesto di confrontare "capelli d'angelo" con "spaghettini", dopo aver sottolineato che questi due tipi di pasta sono praticamente indistinguibili per chiunque e intercambiabili in qualsiasi piatto che potresti voler preparare, avrei inevitabilmente passare all'esame microscopico di come le lunghezze e i diametri differiscano impercettibilmente, come le estremità dei fili siano rastremate in un caso e non nell'altro, e così via - per cercare di spiegare perché io, personalmente, preferirei avere capelli d 'angelo come la pasta in qualsiasi tipo di brodo, ma preferirei gli spaghettini come la pastasciutta per accompagnare salse adatte a forme di pasta così lunghe e sottili (olio d'oliva, aglio tritato, peperoni rossi tritati e acciughe macinate finemente, per esempio - ma se hai tagliato l'aglio e i peperoni invece di tritarli, allora dovresti scegliere il corpo più sano degli spaghetti piuttosto che la più sottile evanescenza degli spaghettini, e ti consigliamo di rinunciare agli achovies e aggiungere invece un po 'di basilico fresco di primavera [ o anche - sono un eretico ...! - foglie di menta leggera ...] - all'ultimo momento prima di servire il piatto). Ops, scusa, dimostra che sto viaggiando all'estero e non ho mangiato pasta per un po ', immagino. Ma l'analogia è ancora abbastanza buona! -) - foglie di menta leggera ...] - all'ultimo momento prima di servire il piatto). Ops, scusa, dimostra che sto viaggiando all'estero e non ho mangiato pasta per un po ', immagino. Ma l'analogia è ancora abbastanza buona! -) - foglie di menta leggera ...] - all'ultimo momento prima di servire il piatto). Ops, scusa, dimostra che sto viaggiando all'estero e non ho mangiato pasta per un po ', immagino. Ma l'analogia è ancora abbastanza buona! -)

Quindi, tornando a Python e Ruby, arriviamo ai due biggie (in termini di linguaggio proprio - lasciando le librerie e altri importanti accessori come strumenti e ambienti, come incorporare / estendere ogni lingua, ecc., Ecc. Da per ora - non si applicherebbero comunque a tutte le IMPLEMENTAZIONI di ogni lingua, ad esempio, Jython vs Classic Python essendo due implementazioni del linguaggio Python!):

  1. Iteratori e blocchi di codice di Ruby vs iteratori e generatori di Python;

  2. La "dinamica" TOTALE e sfrenata di Ruby, inclusa la possibilità
    di "riaprire" qualsiasi classe esistente, comprese quelle incorporate, e di modificarne il comportamento in fase di esecuzione - rispetto alla vasta ma limitata dinamicità di Python , che non cambia mai il comportamento dell'esistente classi integrate e loro istanze.

Personalmente, considero 1 un lavaggio (le differenze sono così profonde che potrei facilmente vedere le persone odiare l'uno o l'altro approccio e riverire l'altro, ma sulla MIA scala personale i vantaggi e gli svantaggi sono quasi pari); e 2 un problema cruciale - uno che rende Ruby molto più adatto per "armeggiare", MA Python è anche più adatto per l'uso in grandi applicazioni di produzione. È divertente, in un certo senso, perché entrambe le lingue sono così MOLTO più dinamiche della maggior parte delle altre, che alla fine la differenza chiave tra loro dal mio POV dovrebbe dipendere da questo - che Ruby "va a undici" a questo proposito (il riferimento ecco "Spinal Tap", ovviamente). In Ruby,POSSO FARLO ! Cioè, posso modificare dinamicamente la classe di stringhe incorporata in modo che a = "Hello World" b = "ciao mondo" se a == b stampa "uguale! \ N" altrimenti stampa "diverso! \ N" fine STAMPA stampa " pari". In Python, NON c'è modo di farlo. Ai fini della metaprogrammazione, dell'implementazione di quadri sperimentali e simili, questa straordinaria abilità dinamica di Ruby è estremamente attraente. MA - se stiamo parlando di applicazioni di grandi dimensioni, sviluppate da molte persone e gestite da ancora di più, compresi tutti i tipi di librerie da diverse fonti, e che devono andare in produzione nei siti dei clienti ... beh, non VOGLIO un linguaggio che è abbastanza dinamico, grazie mille. Odio l'idea stessa di una biblioteca che rompa inconsapevolmente altre non correlate che si basano sul fatto che quelle stringhe sono diverse - questo è il tipo di "canale" profondo e profondamente nascosto, tra pezzi di codice che GUARDANO separati e DOVREBBERO ESSERE separati, che compongono la morte programmazione su larga scala. Consentendo a qualsiasi modulo di influenzare il comportamento di qualsiasi altro "di nascosto", la capacità di mutare la semantica dei tipi predefiniti è solo un'idea MALE per la programmazione delle applicazioni di produzione,

Se dovessi usare Ruby per un'applicazione così grande, proverei a fare affidamento su restrizioni in stile codifica, su molti test (da ripetere ogni volta che cambia QUALCOSA - anche ciò che dovrebbe essere totalmente estraneo ...) e simili, per vietare l'uso di questa funzione linguistica. Ma NON avere la funzionalità in primo luogo è ancora meglio, secondo me - proprio come Python stesso sarebbe un linguaggio ancora migliore per la programmazione dell'applicazione se un certo numero di built-in potesse essere "inchiodato", quindi SAPEVO che , ad esempio, len ("ciao") è 4 (piuttosto che doversi preoccupare subliminalmente se qualcuno ha cambiato il legame del nome 'len' nel modulo incorporato ...). Spero che alla fine Python "inchioda" i suoi built-in.

Ma il problema è minore, dal momento che il rebinding degli built-in è piuttosto deprecato e una pratica rara in Python. In Ruby, mi sembra importante - proprio come le macro strutture troppo potenti di altre lingue (come, diciamo, Dylan) presentano rischi simili secondo me (spero che Python non ottenga mai un sistema macro così potente, no importa il fascino di "lasciare che le persone definiscano le loro piccole lingue specifiche del dominio incorporate nella lingua stessa" - IMHO, comprometterebbe la meravigliosa utilità di Python per la programmazione delle applicazioni, presentando un "fastidio attraente" al potenziale armeggiare che si nasconde nel cuore di ogni programmatore ...).

alex


9

Alcuni altri da:

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

(Se ho frainteso qualcosa o qualcuno di questi è cambiato sul lato Ruby da quando quella pagina è stata aggiornata, qualcuno si sente libero di modificare ...)

Le stringhe sono mutabili in Ruby, non in Python (dove le nuove stringhe vengono create da "modifiche").

Ruby ha alcune convenzioni sul caso applicate, Python no.

Python ha sia liste che tuple (liste immutabili). Ruby ha array corrispondenti alle liste Python, ma nessuna variante immutabile di esse.

In Python puoi accedere direttamente agli attributi degli oggetti. In Ruby, è sempre tramite metodi.

In Ruby, le parentesi per le chiamate ai metodi sono generalmente opzionali, ma non in Python.

Ruby ha pubblico, privato e protetto per imporre l'accesso, invece della convenzione di Python di usare caratteri di sottolineatura e manipolazione dei nomi.

Python ha eredità multipla. Ruby ha "mixin".

E un altro link molto rilevante:

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

Che, in particolare, collega ad un altro buono di Alex Martelli , che ha anche pubblicato molte cose fantastiche qui su SO:

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


1
In ruby ​​potresti semplicemente congelare il tuo array per cambiarlo in qualcosa di immutabile
user163365

Post eccellente di Alex Martelli :)
Skilldrick,

8

Non ne sono sicuro, quindi lo aggiungo prima come risposta.

Python tratta i metodi non associati come funzioni

Ciò significa che puoi chiamare un metodo o like theobject.themethod()o by TheClass.themethod(anobject).

Modifica: Sebbene la differenza tra metodi e funzioni sia piccola in Python e inesistente in Python 3, non esiste nemmeno in Ruby, semplicemente perché Ruby non ha funzioni. Quando si definiscono le funzioni, in realtà si definiscono i metodi su Object.

Ma non puoi ancora prendere il metodo di una classe e chiamarlo come una funzione, dovresti ricollegarlo all'oggetto su cui vuoi invocare, il che è molto più ostacolo.


Ruby non ha affatto funzioni. Detto questo, TheClass.instance_method(:themethod).bind(anobject).callsarebbe il rubino equivalente.
Logan Capaldo,

Oh. Quindi c'è una sorta di classe principale magica quando definisci una funzione che non è in una classe esplicita?
Lennart Regebro,

Sì, i metodi definiti al livello superiore sono metodi privati ​​di Object.
Logan Capaldo,

1
FWIW, sembra che in Python funzioni e metodi siano effettivamente dello stesso tipo e il loro comportamento diverso provenga dai descrittori: users.rcn.com/python/download/… .
Bastien Léonard,

1
Ma se lo leghi a un oggetto, allora non è illimitato. Duh. :-) E sono la stessa cosa anche in Python. È solo che Ruby in realtà non ha funzioni. Ciò significa che la mia affermazione è corretta. Puoi chiamare un metodo non associato come se fosse una funzione in Python. E questo è effettivamente utile, ciò significa ad esempio che è possibile chiamare un metodo definito su una classe su un oggetto che non ha quella classe, che a volte è utile.
Lennart Regebro,

7

Vorrei menzionare l'API del descrittore Python che consente di personalizzare la "comunicazione" da oggetto a attributo. È anche degno di nota il fatto che, in Python, si è liberi di implementare un protocollo alternativo sostituendo il valore predefinito fornito tramite l'implementazione predefinita del __getattribute__metodo. Consentitemi di fornire maggiori dettagli in merito. I descrittori sono classi regolari con __get__, __set__e / o __delete__metodi. Quando l'interprete incontra qualcosa di simile anObj.anAttr, viene eseguito quanto segue:

  • __getattribute__anObjviene invocato il metodo di
  • __getattribute__ recupera un oggetto Attr dalla classe dict
  • Verifica se oggetto abAttr ha __get__, __set__o __delete__oggetti callable
  • il contesto (ovvero oggetto o classe del chiamante e valore, invece di quest'ultimo, se abbiamo setter) viene passato all'oggetto richiamabile
  • il risultato viene restituito.

Come accennato, questo è il comportamento predefinito. Uno è libero di modificare il protocollo reimplementando __getattribute__.

Questa tecnica è molto più potente dei decoratori.


6

Ruby ha integrato il supporto per la continuazione usando callcc.

Quindi puoi implementare cose interessanti come l' amb-operator


Vorrei aver capito callcc. Puoi dare uno scenario applicativo più banale rispetto all'ambiguo operatore di McCarthy, per apprezzarne le allegre? Intendo qualcosa del mondo reale, non quella roba funky di CS ?!
ThomasH,

"Funky CS stuff" è reale. Prenditi del tempo per imparare: intertwingly.net/blog/2005/04/13/Continuations-for-Curmudgeons
Stephen Eilert,


5

Python ha dotstring e ruby ​​no ... O in caso contrario, non sono accessibili così facilmente come in Python.

Ps. Se sbaglio, per favore, lascia un esempio? Ho una soluzione alternativa che potrei facilmente inserire in classi abbastanza facilmente, ma mi piacerebbe avere docstring una specie di caratteristica in "modo nativo".


3
non ha docstring, ma ha RDoc. Quindi sì, non così facilmente accessibile, ma non nascosto al 100%.
Omar Qureshi,

Ruby non usa docstrings. Fa la documentazione in modo diverso.
Chuck,

1
Omar: sì, conosco rdoc ma afaik, non sono "così accessibili" come le dotstring di Python. Ad esempio, se ho una classe e voglio produrre la documentazione rdoc all'interno della classe, è un lavoro piuttosto pesante. Quello che ho fatto è che ho generato la documentazione di ri che tento di mantenere aggiornato2 e poi vado a recuperare quelle informazioni. Sicuramente non all'altezza dei
dotstrings

Docstrings può essere utilizzato per fornire doctest. C'è qualcosa del genere per Ruby?
Lennart Regebro,

2
Sì, si chiama "Ruby Doctest". Per quanto riguarda i doctest, tutto ciò che conta davvero è che tu abbia una documentazione leggibile da qualche parte che includa frammenti di codice verificabili - non fa differenza se si trova in un docstring o in un commento.
Chuck,

5

Ruby ha un ciclo riga per riga sui file di input (il flag '-n') dalla riga di comando, quindi può essere usato come AWK. Questo Ruby one-liner:

ruby -ne 'END {puts $.}'

conterà le righe come la linea singola AWK:

awk 'END{print NR}'

Ruby ottiene questa funzionalità attraverso Perl, che l'ha presa da AWK come un modo per far entrare i amministratori di sistema con Perl senza dover cambiare il modo in cui fanno le cose.


1
Vorrei aggiungere che il supporto della riga di comando di Python è piuttosto debole. Oltre al ciclo automatico mancante non è possibile inserire un paio di istruzioni in una singola riga e passarle come argomento a riga di comando a stringa singola all'interprete. Almeno non ci sono riuscito.
ThomasH,

Certo che puoi. Ma dovrai (come in ogni altra lingua) racchiudere tra virgolette.
Lennart Regebro,

Python non è fatto per essere usato dalla riga di comando, poiché devi essere esplicito su alcune cose (come sys.stdin) se vuoi usarlo in questo modopython -c "import sys; print len(list(sys.stdin))"
u0b34a0f6ae

5

Ruby ha sigilli e ramoscelli, Python no.

Modifica : E una cosa molto importante che ho dimenticato (dopotutto, il precedente era solo un po 'infiammare :-p):

Python ha un compilatore JIT ( Psyco ), un linguaggio di livello inferiore per la scrittura di codice più veloce ( Pyrex ) e la possibilità di aggiungere codice C ++ in linea ( Weave ).


Vero, ma questa è solo sintassi.
Lennart Regebro,

6
Bene, se vuoi percorrere quella strada: entrambi sono Turing-completi. Tutto il resto è solo sintassi.
Jörg W Mittag,

Sì e una differenza di sintassi importax ;-)
fortran,

1
In che modo è importante scrivere @foo o self.foo?
Lennart Regebro,

1
@Jörg: OK, chiamalo in qualche modo diverso da "sintassi" allora. Il punto è che @foo e self.foo fanno la stessa cosa, in realtà non è una funzionalità di Ruby e Python no.
Lennart Regebro,

5

Il mio pitone è arrugginito, quindi alcuni di questi potrebbero essere in pitone e io non ricordo / non ho mai imparato in primo luogo, ma ecco i primi che ho pensato:

Lo spazio bianco

Ruby gestisce gli spazi completamente diversi. Per i principianti, non è necessario inserire alcun rientro (il che significa che non importa se si utilizzano 4 spazi o 1 scheda). Fa anche la continuazione della linea intelligente, quindi è valido quanto segue:

def foo(bar,
        cow)

Fondamentalmente, se finisci con un operatore, capisce cosa sta succedendo.

mixins

Ruby ha mixin che possono estendere istanze invece di classi complete:

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

Enums

Non sono sicuro che questo sia lo stesso dei generatori, ma dal Ruby 1.9 ruby ​​come enum, quindi

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

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

"Argomenti di parole chiave"

Entrambi gli elementi elencati sono supportati in Ruby, anche se non puoi saltare valori predefiniti del genere. Puoi andare in ordine

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

Si noti che c = 5 in realtà assegna alla variabile c nell'ambito della chiamata il valore 5 e imposta il parametro b il valore 5.

oppure puoi farlo con gli hash, che risolvono il secondo problema

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

Riferimento: The Pragmatic Progammer's Guide to Ruby


Il tuo secondo esempio foo (1, c = 5) non fa quello che pensi che faccia. Ruby non ha parametri nominati.
Horseyguy,

5
Python ha una continuazione di riga implicita tra parentesi (, [oppure{
u0b34a0f6ae,

5

Puoi avere il codice nella definizione della classe sia in Ruby che in Python. Tuttavia, in Ruby hai un riferimento alla classe (sé). In Python non hai un riferimento alla classe, poiché la classe non è ancora definita.

Un esempio:

class Kaka
  puts self
end

self in questo caso è la classe e questo codice stampa "Kaka". Non è possibile stampare il nome della classe o accedere in altro modo alla classe dal corpo della definizione della classe in Python.


Puoi fornire maggiori dettagli (come il codice) per il tuo primo punto?
Loïc Wolff,

Il codice di esempio è una buona idea, l'ho aggiunto, anche se questo caso è banale.
Lennart Regebro,

@SilentGhost: non riesco a pensare a uno che non sia davvero oscuro in questo momento. :)
Lennart Regebro,

puoi accedere al nome della classe all'interno della classe in python: class foo (): def init __ (self): print self .__ class .__ name__
txwikinger

1
@txwikinger: sì, ma non all'interno del corpo della classe, che viene eseguito contemporaneamente alla classdichiarazione.
Bastien Léonard,

4

La sintassi non è una cosa minore, ha un impatto diretto su come pensiamo. Ha anche un effetto diretto sulle regole che creiamo per i sistemi che utilizziamo. Ad esempio, abbiamo l'ordine delle operazioni a causa del modo in cui scriviamo equazioni o frasi matematiche. La notazione standard per la matematica consente alle persone di leggerlo in più di un modo e di arrivare a risposte diverse data la stessa equazione. Se avessimo usato la notazione prefisso o postfisso avremmo creato delle regole per distinguere quali fossero i numeri da manipolare piuttosto che avere solo regole per l'ordine in cui calcolare i valori.

La notazione standard chiarisce di quali numeri stiamo parlando rendendo l'ordine ambiguo per il loro calcolo. La notazione con prefisso e postfisso rende semplice l'ordine in cui calcolare chiaramente rendendo ambigui i numeri. Python avrebbe già lambda multilinea se non fosse per le difficoltà causate dallo spazio bianco sintattico. (Esistono proposte per realizzare questo tipo di cose senza necessariamente aggiungere delimitatori di blocchi espliciti.)

Trovo più facile scrivere le condizioni in cui voglio che si verifichi qualcosa se una condizione è falsa, molto più facile da scrivere con l'istruzione don't in Ruby rispetto alla costruzione semificamente equivalente "if-not" in Ruby o in altre lingue, ad esempio. Se la maggior parte delle lingue che le persone usano oggi sono uguali in termini di potere, come può la sintassi di ogni lingua essere considerata una cosa banale? Dopo funzionalità specifiche come blocchi, meccanismi di ereditarietà ecc. La sintassi è la parte più importante di un linguaggio, quasi una cosa superficiale.

Ciò che è superficiale sono le qualità estetiche della bellezza che attribuiamo alla sintassi. L'estetica non ha nulla a che fare con il funzionamento della nostra cognizione, fa la sintassi.


Questo "commento" è tre volte più lungo di quanto consentito in un commento, indipendentemente dal rappresentante.
Andrew Grimm,

Questo in realtà mi sembra una risposta. Modificato il bit "questo è un commento".
Bill the Lizard,

3

Sorpreso di non vedere nulla di menzionato del meccanismo di "metodo mancante" di Ruby. Darei esempi dei metodi find_by _... in Rails, come esempio della potenza di quella funzione linguistica. La mia ipotesi è che qualcosa di simile potrebbe essere implementato in Python, ma per quanto ne sappia non è lì nativamente.


Python ha get_attribute , che realizza sostanzialmente la stessa cosa del metodo di Ruby_missing.
mipadi,

3
Perché gli sviluppatori di Python si fanno sempre così male quando si parla di ruby ​​OVUNQUE? Non puoi negare che questo non sia vero.
aarona,

method_missingpuò essere emulato in Python, in alcuni casi: class M(): def __getattr__(self, n): return lambda: "Missing! " + n; M().hi(). Tuttavia, ci sono lievi differenze e dubito che sia idiomatico in Python :-)

1
@DJTripleThreat: nego che sia vero.
Lennart Regebro,

3

Un'altra differenza di lambda tra Python e Ruby è dimostrata dal problema del generatore di accumulatori di Paul Graham . Ristampato qui:

Scrivi una funzione foo che accetta un numero n e restituisce una funzione che accetta un numero i e restituisce n incrementato di i. Nota: (a) è un numero, non un numero intero, (b) è incrementato di, non più.

In Ruby, puoi farlo:

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

In Python, dovresti creare un oggetto per contenere lo stato di n:

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

Alcune persone potrebbero preferire l'approccio esplicito di Python come concettualmente più chiaro, anche se è un po 'più dettagliato. Memorizzi lo stato come fai per qualsiasi altra cosa. Hai solo bisogno di avvolgere la testa attorno all'idea di oggetti richiamabili. Ma indipendentemente dall'approccio che si preferisce esteticamente, mostra un rispetto in cui i lambda di Ruby sono costrutti più potenti di quelli di Python.


3
Non è possibile incrementare i numeri in Python, quindi questa limitazione non ha senso. In Python i numeri sono immutabili. Se invece lo cambiamo in "più", la classe non è necessaria. Quindi questo non dimostra nulla della differenza lambda, ma la differenza nel modo in cui funzionano i numeri. A meno che ovviamente non si crei una classe numerica mutabile. :)
Lennart Regebro,

2
La restrizione è lì per chiarire il comportamento desiderato. Qual è il problema che richiede è: f = foo (10) f (2) >> 12 f (3) >> 15 ... lambda {| i | n + i} dà: f = foo (10) f (2) >> 12 f (3) >> 13 ... I numeri sono immutabili anche in Ruby - non puoi dire 2 + = 1 per esempio. E n + = 1 va bene in una normale funzione Python, ma non in una lambda. Quindi è una questione di cosa sia "n", del fatto che viene creato quando viene invocata la funzione e formata la lambda, che è possibile eseguire l'assegnazione in una lambda (anziché solo espressioni) e che può contenere il valore di n su più chiamate.
dormsbee,

Non penso che tu debba andare così lontano in Python. Le funzioni possono essere definite all'interno di altre funzioni. def foo(n): def f(i): return n + i return f.
FMc,

2
Non è comunque lo stesso, e il tuo esempio è equivalente al lambda di Python nel commento sopra. La versione Ruby crea un lambda che mantiene lo stato tra le chiamate. L'esempio che hai pubblicato ti consente di configurare un valore iniziale per n, ma la funzione che foo restituisce avrà sempre quel valore iniziale. La versione di Ruby aumenta. Quindi diciamo f = foo (10). La versione di Python: f (1) => 11, f (1) => 11. La versione di Ruby 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. In Python3 potresti usare la nonlocalparola chiave.
jfs,

3

python ha chiamato argomenti opzionali

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 ha posizionato solo gli argomenti perché b = 2 nella dichiarazione di funzione è un'influenza che viene sempre aggiunta.


3
che cosa significa "Ruby ha posizionato solo gli argomenti perché b = 2 nella dichiarazione di funzione è un effetto che aggiunge sempre" significa anche?
Horseyguy,

3
Non so su quale pianeta vivi, ma def my_method(param1, optional = false)funziona in Ruby 1.8.6, 1.8.7 e presumibilmente 1.9!
Robert K,

5
The Wicked Flea, e le persone che hanno votato per il suo commento, non hai guardato l'esempio abbastanza vicino. È in grado di saltare il bparametro nella funcchiamata e mantiene comunque il suo valore predefinito. Cioè, bè il secondo argomento nella firma, ma può ignorarlo con il prefisso del secondo parametro con c=. Ruby usa gli hash per simulare questo, ma non è esattamente lo stesso.
maček,

2

Ruby ha incorporato la documentazione:

 =begin

 You could use rdoc to generate man pages from this documentation

 =end

5
I docstring finiscono come parte dei metodi / classi su cui li hai impostati. Quindi puoi aiutare (classe) e ti mostrerà le dotstring, ecc.
Lennart Regebro,


2

In Ruby, quando importi un file con un requisito, tutte le cose definite in quel file finiranno nel tuo spazio dei nomi globale.

Con Cargo puoi " richiedere librerie senza ingombrare il tuo spazio dei nomi ".

# 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 :: VERSIONE
=> "1.0.0"
>> Foo2 :: VERSIONE
=> "2.0.0"

Questo avrebbe dovuto piuttosto essere un commento, non una nuova risposta.
Lennart Regebro,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.