¿Qué tiene Ruby que Python no tiene, y viceversa?


263

Hay muchas discusiones sobre Python vs Ruby, y todas las encuentro completamente inútiles, porque todas dan vueltas por qué la característica X es una mierda en el lenguaje Y, o eso afirma que el lenguaje Y no tiene X, aunque en realidad sí lo tiene. También sé exactamente por qué prefiero Python, pero eso también es subjetivo, y no ayudaría a nadie a elegir, ya que es posible que no tengan los mismos gustos en desarrollo que yo.

Por lo tanto, sería interesante enumerar las diferencias de manera objetiva. Así que no "las lambdas de Python apestan". En cambio, explique lo que las lambdas de Ruby pueden hacer que Python no puede hacer. Sin subjetividad. ¡El código de ejemplo es bueno!

No tenga varias diferencias en una respuesta, por favor. Y vote por los que sabe que son correctos, y por los que sabe que son incorrectos (o subjetivos). Además, las diferencias en la sintaxis no son interesantes. Sabemos que Python hace con sangría lo que Ruby hace con corchetes y extremos, y que @ se llama self en Python.

ACTUALIZACIÓN: Esta es ahora una wiki comunitaria, por lo que podemos agregar las grandes diferencias aquí.

Ruby tiene una referencia de clase en el cuerpo de la clase.

En Ruby tienes una referencia a la clase (self) que ya está en el cuerpo de la clase. En Python, no tiene una referencia a la clase hasta que finaliza la construcción de la clase.

Un ejemplo:

class Kaka
  puts self
end

self en este caso es la clase, y este código imprimirá "Kaka". No hay forma de imprimir el nombre de la clase o de otra manera acceder a la clase desde el cuerpo de definición de clase en Python (definiciones de método externas).

Todas las clases son mutables en Ruby.

Esto le permite desarrollar extensiones para las clases principales. Aquí hay un ejemplo de una extensión de rieles:

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

Python (imagina que no hubiera ''.startswithmétodo):

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

Puede usarlo en cualquier secuencia (no solo cadenas). Con el fin de utilizarlo debe importar que explícitamente por ejemplo, from some_module import starts_with.

Ruby tiene características de script similares a Perl

Ruby tiene expresiones regulares de primera clase, $ -variables, el bucle de entrada línea por línea awk / perl y otras características que lo hacen más adecuado para escribir pequeños scripts de shell que combinan archivos de texto o actúan como código de pegamento para otros programas.

Ruby tiene continuaciones de primera clase.

Gracias a la declaración callcc. En Python puede crear continuaciones mediante diversas técnicas, pero no hay soporte integrado en el lenguaje.

Ruby tiene bloques

Con la instrucción "do" puede crear una función anónima de varias líneas en Ruby, que se pasará como un argumento al método frente a do, y se llamará desde allí. En Python, en su lugar, haría esto ya sea pasando un método o con generadores.

Rubí:

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

Python (los bloques Ruby corresponden a diferentes construcciones en 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

Curiosamente, la declaración de conveniencia en Ruby para llamar a un bloque se llama "rendimiento", que en Python creará un generador.

Rubí:

def themethod
    yield 5
end

themethod do |foo|
    puts foo
end

Pitón:

def themethod():
    yield 5

for foo in themethod():
    print foo

Aunque los principios son diferentes, el resultado es sorprendentemente similar.

Ruby admite la programación de estilo funcional (similar a una tubería) más fácilmente

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

Pitón:

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

Python tiene generadores integrados (que se usan como bloques Ruby, como se señaló anteriormente)

Python tiene soporte para generadores en el lenguaje. En Ruby 1.8 puede usar el módulo generador que usa las continuaciones para crear un generador a partir de un bloque. O bien, ¡podría usar un bloque / proc / lambda! Además, en Ruby 1.9 las fibras son, y se pueden usar como, generadores, y la clase Enumerator es un generador incorporado 4

docs.python.org tiene este ejemplo de generador:

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

Contraste esto con los ejemplos de bloques anteriores.

Python tiene un manejo flexible del espacio de nombres

En Ruby, cuando importa un archivo con require , todas las cosas definidas en ese archivo terminarán en su espacio de nombres global. Esto causa la contaminación del espacio de nombres. La solución a eso son los módulos Rubys. Pero si crea un espacio de nombres con un módulo, entonces debe usar ese espacio de nombres para acceder a las clases contenidas.

En Python, el archivo es un módulo y puede importar sus nombres contenidos from themodule import *, contaminando así el espacio de nombres si lo desea. Pero también puede importar nombres seleccionados con from themodule import aname, anothero simplemente puede import themoduley luego acceder a los nombres con themodule.aname. Si desea más niveles en su espacio de nombres, puede tener paquetes, que son directorios con módulos y un __init__.pyarchivo.

Python tiene docstrings

Las cadenas de documentos son cadenas que se adjuntan a módulos, funciones y métodos y pueden introspectarse en tiempo de ejecución. Esto ayuda a crear cosas como el comando de ayuda y la documentación automática.

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

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

Los equivalentes de Ruby son similares a los javadocs, y se encuentran sobre el método en lugar de dentro de él. Se pueden recuperar en tiempo de ejecución de los archivos mediante el uso del ejemplo del método # source_location 1.9 de 1.9

Python tiene herencia múltiple

Ruby no lo hace ("a propósito" - vea el sitio web de Ruby, vea aquí cómo se hace en Ruby ). Reutiliza el concepto de módulo como un tipo de clases abstractas.

Python tiene comprensiones de listas / dict

Pitón:

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

Rubí:

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

Pitón:

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

Rubí:

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

Rubí:

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

Python tiene decoradores

También se pueden crear cosas similares a los decoradores en Ruby, y también se puede argumentar que no son tan necesarios como en Python.

Diferencias de sintaxis

Ruby requiere "fin" o "}" para cerrar todos sus ámbitos, mientras que Python usa solo espacios en blanco. Ha habido intentos recientes en Ruby para permitir espacios en blanco solo sangría http://github.com/michaeledgar/seamless


2
Con respecto a la herencia múltiple, decir simplemente "Ruby no" es falso. No puedo pensar en nada que pueda hacer en Python con herencia múltiple que no pueda hacer en ruby ​​con módulos / "herencia mixin". (Incluso es discutible que incluir módulos simplemente es herencia múltiple).
Logan Capaldo

2
Que puedes hacer lo mismo de otra manera es un argumento que no es válido. Puedes hacer todo aquí de otra manera. Y dado que los módulos no son clases, no es herencia múltiple. Le invitamos a contribuir ejemplos de código de cómo se hace en Pythons herencia múltiple vs con módulos Rubys.
Lennart Regebro

3
Los módulos no son clases, pero las clases son módulos. % ruby ​​-e 'p Clase <Módulo' verdadero
Logan Capaldo

8
-1 ¡Desafortunadamente, esta pregunta no cumple su objetivo y la mayoría de las supuestas diferencias no son diferencias en absoluto y abunda la información errónea!
sesgo

2
El módulo incluye, de hecho, herencia múltiple, no solo en concepto sino también en implementación real en el intérprete de Ruby. Cuando se incluye un módulo Ruby, se inyecta en la cadena de herencia exactamente de la misma manera que las superclases. La resolución del método es la misma. En Ruby, el módulo múltiple incluye herencia múltiple. Cualquiera que quiera impugnar esto semánticamente "no es lo mismo" que la herencia múltiple es simplemente ser pedante. ¿De qué sirve que algo no sea la "misma cosa" si el efecto es idéntico y se logra con la misma facilidad? Una distinción sin diferencia.
Dave Sims

Respuestas:


34

Ruby tiene los conceptos de bloques , que son esencialmente azúcar sintáctico alrededor de una sección de código; son una forma de crear cierres y pasarlos a otro método que puede o no usar el bloque. Se puede invocar un bloque más adelante mediante una yielddeclaración.

Por ejemplo, una definición simple de un eachmétodo en Arraypodría ser algo como:

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

Entonces puedes invocar esto así:

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

Python tiene funciones / cierres / lambdas anónimos, pero no tiene bloques, ya que le falta algo del azúcar sintáctico útil. Sin embargo, hay al menos una forma de obtenerlo de manera ad-hoc. Ver, por ejemplo, aquí .


66
@Lennart: aparte de su ejemplo, simplemente siendo horrible, también es sintácticamente incorrecto.

2
@unbeknow: A, cierto. Pero si eso hubiera sido una función en lugar de una impresión, habría funcionado. En python 3 esto funciona: [print (e + 5) para e en [1,2,3,4]] Y cuando se trata de lo horrible, creo que el código ruby ​​anterior es horrible, por lo que es claramente subjetivo y, por lo tanto, no un parte de esta pregunta @John No digo que sea equivalente, digo que no es obvio cuál es la diferencia con tu ejemplo. @Bastien, no, pero que puedas hacer cosas similares no significa que sean lo mismo. Las diferencias aquí deberían enumerarse incluso si hay otras formas de hacerlo.
Lennart Regebro

22
Soy un programador de Python. Me gustaría ver un ejemplo de cómo los bloques Ruby te ayudan a escribir algo más conciso o más hermoso que con Python porque no tiene bloques. Su ejemplo podría escribirse: para i en [1, 2, 3, 4]: print (i + 5). No usa bloques, pero es conciso y hermoso, así como el rubí en cada ejemplo.
Manuel Ceron

10
@Manuel, los procs son útiles para unir functores a estructuras de datos no triviales (árboles, gráficos ...) que no pueden ser 'for-loop' y, por lo tanto, requieren iteradores especiales para atravesar. Los bloques, que son procesos anónimos, le permiten implementar el functor en una expresión (en lugar de definir luego implementar), lo que acelera drásticamente el proceso de codificación y aclara la intención. Por ejemplo, si estaba creando una estructura de datos de gráficos, podría definir un iterador 'cada' y luego mezclar Enumerable, lo que le daría acceso instantáneo a docenas de iteradores (¿ordenar, todos ?, ¿cualquier ?, grep). Ahora llamas a un bloque ...
sesgo

44
@RommeDeSerieux, ¡porque necesita un nombre en el idioma! Además, es un objeto de función, no una función. Echemos un vistazo a los Ruby Docs: "Los objetos de proceso son bloques de código que se han vinculado a un conjunto de variables locales", por lo que un proceso anónimo es solo el bloque y ciertamente no es solo una función.
sesgo

28

Ejemplo de Python

Las funciones son variables de primera clase en Python. Puede declarar una función, pasarla como un objeto y sobrescribirla:

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

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

Esta es una característica fundamental de los lenguajes de script modernos. JavaScript y Lua también hacen esto. Ruby no trata las funciones de esta manera; nombrar una función la llama.

Por supuesto, hay formas de hacer estas cosas en Ruby, pero no son operaciones de primera clase. Por ejemplo, puede ajustar una función con Proc.new para tratarla como una variable, pero ya no es una función; Es un objeto con un método de "llamada".

Las funciones de Ruby no son objetos de primera clase.

Las funciones de Ruby no son objetos de primera clase. Las funciones deben estar envueltas en un objeto para pasarlas; El objeto resultante no puede ser tratado como una función. Las funciones no se pueden asignar de manera de primera clase; en su lugar, se debe llamar a una función en su objeto contenedor para modificarlos.

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
Estás muy confundido Los objetos de primera clase se asignan por asignación: x = yno por llamada self.class.send(:define_method, :func, method(:func2)). Su "contraejemplo" muestra cómo las funciones de Ruby no son de primera clase. Si no está de acuerdo, no dude en publicar su propia respuesta; no pegues tu confusión en la mía.
Glenn Maynard

77
Las cosas definidas por def ... enden ruby ​​no son funciones. Son métodos (la forma en que los has definido Kernel). Los métodos pueden ser independientes (utilizando el #methodmétodo), que luego son objetos. Lo más cercano que tiene Ruby a las funciones son las Procinstancias, que también son objetos, y se pueden pasar o invocar. También tiene una sintaxis especial para pasar una única devolución Procde llamada a un método, como John Feminella comenta en su respuesta .
rampion

44
@Glenn: Entiendo lo que dices, pero me quejaría con la afirmación de que las funciones redefinidoras de Ruby: los métodos son un concepto semántico separado. Si quieres jugar el juego de definición, el código más imperativo son los procedimientos, no las funciones. No estoy tratando de ser difícil, es solo que creo que las definiciones y la exactitud son importantes. Estoy de acuerdo en que manipular un UnboundMethodpuede ser un PITA, aunque.
rampion

55
@Glenn: La belleza está en el ojo del espectador. No obstante, los métodos son objetos de primera clase al cumplir con la definición (en este caso me refiero a la definición de Wikipedia). Tal vez, ¿tienes alguna otra definición de primera clase? ¿Necesitan una tarjeta de viajero frecuente de platino para pasar a primera clase?
sesgo

44
@Glenn Consulte la sección de preguntas frecuentes de SO "¿Otras personas pueden editar mis cosas?" - Esta es una Wiki de la comunidad.
sesgo

26

En última instancia, todas las respuestas serán subjetivas en algún nivel, y las respuestas publicadas hasta ahora prueban que no se puede señalar ninguna característica que no sea factible en el otro idioma de una manera igualmente agradable (si no similar) , ya que ambos idiomas son muy concisos y expresivos.

Me gusta la sintaxis de Python. Sin embargo, debes profundizar un poco más que la sintaxis para encontrar la verdadera belleza de Ruby. Hay belleza zenlike en la consistencia de Ruby. Si bien ningún ejemplo trivial puede explicar esto completamente, intentaré encontrar uno aquí solo para explicar lo que quiero decir.

Invierta las palabras en esta cadena:

sentence = "backwards is sentence This"

Cuando piense en cómo lo haría, haría lo siguiente:

  1. Divide la oración en palabras
  2. Invierte las palabras
  3. Vuelva a unir las palabras en una cadena

En Ruby, harías esto:

sentence.split.reverse.join ' '

Exactamente como lo piensa, en la misma secuencia, una llamada de método tras otra.

En python, se vería más así:

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

No es difícil de entender, pero no tiene el mismo flujo. El sujeto (oración) está enterrado en el medio. Las operaciones son una mezcla de funciones y métodos de objeto. Este es un ejemplo trivial, pero uno descubre muchos ejemplos diferentes cuando realmente trabaja y comprende Ruby, especialmente en tareas no triviales.


1
Estoy de acuerdo. Ruby parece fluir naturalmente cuando lo escribo, por lo que "zenlike" es un buen término.
The Tin Man

18

Python tiene una mentalidad de "todos somos adultos aquí". Por lo tanto, encontrará que Ruby tiene cosas como constantes, mientras que Python no (aunque las constantes de Ruby solo generan una advertencia). La forma de pensar de Python es que si quieres hacer algo constante, debes poner los nombres de las variables en mayúsculas y no cambiarlo.

Por ejemplo, Ruby:

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

Pitón:

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

19
Ja ... esto solo me recuerda que al menos en Python 2. *, pudiste hacer "True, False = False, True" ... Creo que lo han solucionado correctamente en Python 3.0 ... eso es algo que deberías ser impedido de hacer.
Tom

11
Personalmente, me gustan las pautas estrictas que impone el lenguaje porque hace que todo el código escrito en ese idioma sea coherente. Te obliga a seguir las pautas, y los desarrolladores que leen tu código pueden decir de un vistazo qué es qué. Si bien la mayoría de los codificadores de Python usan el mismo "estilo" general, he visto algunas inconsistencias bastante grandes que no serían posibles en Ruby.
Sasha Chedygov

8
@bias: no estoy seguro de por qué me estás rechazando. Esta respuesta no está de acuerdo o en desacuerdo con la forma en que Python hace las cosas. Es solo una declaración de hecho.
Jason Baker

13
¿@Jason "todos somos adultos aquí" es una declaración de un hecho? Me gustaría llamar a eso una opinión envuelta alrededor de una característica, de ahí el voto negativo.
sesgo

77
@bias - Decir "todos somos adultos aquí" no fue un desaire. Es un lema no oficial de Python, que creo que se explica mejor aquí: mail.python.org/pipermail/tutor/2003-October/025932.html
Evan Porter

18

Solo puede importar funciones específicas de un módulo en Python. En Ruby, importa la lista completa de métodos. Podrías "no importarlos" en Ruby, pero no se trata de eso.

EDITAR:

tomemos este módulo Ruby:


module Whatever
  def method1
  end

  def method2
  end
end

si lo incluye en su código:


include Whatever

verá que tanto el método1 como el método2 se han agregado a su espacio de nombres. No puede importar solo el método1 . Los importas a ambos o no los importas en absoluto. En Python puede importar solo los métodos que elija. Si esto tuviera un nombre, ¿tal vez se llamaría importación selectiva?


2
¡Correcto! A Python le gustan los espacios de nombres. ¿No es ese el caso en Ruby? ¿No import bla; bla.foo()en Ruby?
Lennart Regebro

2
Solo puede importar la función a, no todas las funciones que contiene. Si, por ejemplo, incluye un módulo Ruby que declara 3 funciones no estáticas, las incluirá todas en su espacio de nombres. En python tendrías que escribir desde el módulo import *.
Geo

66
¿Eso no conduce a un montón de desorden de espacio de nombres?
Lennart Regebro

1
Creo que si. Eso es lo que odio de los módulos Ruby.
Geo

8
Ruby realmente no tiene un sistema de módulos en el mismo sentido que Python. requiere trabajos básicamente como inclusión textual con algunas comprobaciones para la inclusión de duplicados incorporados. Puede (ab) usar módulos como espacios de nombres, pero en modulerealidad es un nombre poco apropiado. Los módulos son básicamente clases sans el new, allocatemétodos. Funcionan mejor como una forma de compartir código por clase / objeto, no como mecanismo para particionar bibliotecas, o para compartir código entre programas.
Logan Capaldo

16

Desde el sitio web de Ruby :

Similitudes Como con Python, en Ruby, ...

  • Hay un mensaje interactivo (llamado irb).
  • Puede leer documentos en la línea de comandos (con el comando ri en lugar de pydoc).
  • No hay terminadores de línea especiales (excepto la nueva línea habitual).
  • Los literales de cadena pueden abarcar varias líneas como las cadenas de triple cita de Python.
  • Los corchetes son para listas, y los corchetes son para dictados (que, en Ruby, se denominan "hashes").
  • Las matrices funcionan igual (agregarlas forma una matriz larga, pero componerlas así a3 = [ a1, a2 ] le proporciona una matriz de matrices).
  • Los objetos están fuertemente y dinámicamente tipados.
  • Todo es un objeto, y las variables son solo referencias a objetos.
  • Aunque las palabras clave son un poco diferentes, las excepciones funcionan más o menos igual.
  • Tienes herramientas de documentación incrustadas (Ruby se llama rdoc).

Diferencias a diferencia de Python, en Ruby, ...

  • Las cuerdas son mutables.
  • Puede hacer constantes (variables cuyo valor no desea cambiar).
  • Hay algunas convenciones de casos forzadas (por ejemplo, los nombres de clase comienzan con una letra mayúscula, las variables comienzan con una letra minúscula).
  • Solo hay un tipo de contenedor de lista (una matriz), y es mutable.
  • Las cadenas entre comillas dobles permiten secuencias de escape (como \ t) y una sintaxis especial de "sustitución de expresiones" (que le permite insertar los resultados de expresiones Ruby directamente en otras cadenas sin tener que "agregar" + "cadenas" + "juntas") . Las cadenas entre comillas simples son como las "cadenas crudas" de Python.
  • No hay clases de "estilo nuevo" y "estilo antiguo". Solo un tipo.
  • Nunca accedes directamente a los atributos. Con Ruby, todo son llamadas a métodos.
  • Los paréntesis para las llamadas a métodos suelen ser opcionales.
  • Hay acceso público, privado y protegido para imponer el acceso, en lugar de Python _voluntary_ underscore __convention__ .
  • "Mixin" se utilizan en lugar de herencia múltiple.
  • Puede agregar o modificar los métodos de las clases integradas. Ambos idiomas le permiten abrir y modificar clases en cualquier momento, pero Python evita la modificación de los elementos integrados, Ruby no.
  • Tienes verdadero y falso en lugar de verdadero y falso (y nulo en lugar de ninguno).
  • Cuando se prueba la verdad, solo falso y nulo evalúan a un valor falso. Todo lo demás es cierto (incluidos 0, 0.0, "" y []).
  • Es elsif en lugar de elif.
  • Se requiere en lugar de importar. De lo contrario, el uso es el mismo.
  • Los comentarios de estilo habitual en la (s) línea (s) sobre las cosas (en lugar de las cadenas de documentos debajo de ellas) se utilizan para generar documentos.
  • Hay varios atajos que, aunque te dan más para recordar, aprendes rápidamente. Tienden a hacer que Ruby sea divertido y muy productivo.

2
"Se requiere en lugar de importar. De lo contrario, el uso es el mismo". Parece ser completamente inexacto.
Glenjamin

También hay Conjuntos en Ruby que la gente rara vez usa, pero están integrados. Así que puedo decir, stuff_in_backpack = Set.new; stuff_in_backpack << "computadora"; stuff_in_backpack << "zapatos"; # y el conjunto contendrá todos los valores sin garantizar el orden.
zachaysan

12

Lo que Ruby tiene sobre Python son sus capacidades de lenguaje de script. El lenguaje de secuencias de comandos en este contexto significa que se utilizará para el "código de pegamento" en los scripts de shell y la manipulación general de texto.

Estos se comparten principalmente con Perl. Expresiones regulares incorporadas de primera clase, $ -Variables, opciones útiles de línea de comandos como Perl (-a, -e) etc.

Junto con su sintaxis breve pero epxresiva, es perfecta para este tipo de tareas.

Python para mí es más un lenguaje de negocios de tipo dinámico que es muy fácil de aprender y tiene una sintaxis clara. No es tan "genial" como Ruby, pero ordenado. Lo que Python tiene sobre Ruby para mí es la gran cantidad de enlaces para otras bibliotecas. Enlaces a Qt y otras bibliotecas GUI, muchas bibliotecas de soporte de juegos y y y. Ruby tiene mucho menos. Si bien los enlaces muy utilizados, por ejemplo, a las bases de datos son de buena calidad, encontré que las bibliotecas de nicho son mejor compatibles con Python, incluso si para la misma biblioteca también hay un enlace Ruby.

Entonces, yo diría que ambos idiomas tienen su uso y es la tarea que define cuál usar. Ambos son lo suficientemente fáciles de aprender. Los uso uno al lado del otro. Ruby para scripting y Python para aplicaciones independientes.


1
Pregunta de alguien que aún no conoce a Ruby: ¿Qué quieres decir con "$ -Variables"? ¿Te refieres a variables globales? Si es así, en Python, una variable definida en un módulo fuera de una clase o función es global. Si no, ¿cuál es la distinción?
Anon

1
Anon: si declaras una variable $ en cualquier parte del código, es global debido al prefijo. Por lo tanto, no importa dónde se defina, siempre es global y siempre se conoce como tal.
Robert K

8
No exactamente, en realidad me refería a variables predefinidas como $ _, $ 1, etc. Estas son rellenadas automáticamente con valores por el propio ruby. $ _ es la última línea leída. $ 1, $ 2, etc. son las coincidencias de expresiones regulares de la última coincidencia. Consulte aquí para obtener una lista completa: zenspider.com/Languages/Ruby/QuickRef.html#17 Básicamente es un truco para scripts compactos. También puede obtener toda la información a través de llamadas API, pero usando $ variables es más claro. Este tipo de variables simplemente no se ajusta al estilo de Python, deliberadamente las dejaron fuera.
haffax

Gracias por ese enlace de zenspider: había estado buscando algo así para una sensación rápida (no tutorial) para Ruby.
Anon

12

No creo que "Ruby tenga X y Python no, mientras que Python tiene Y y Ruby no" es la forma más útil de verlo. Son lenguajes bastante similares, con muchas habilidades compartidas.

En gran medida, la diferencia es lo que el lenguaje hace elegante y legible. Para usar un ejemplo que mencionaste, ambos teóricamente tienen lambdas, pero los programadores de Python tienden a evitarlos, y las construcciones hechas con ellos no parecen tan legibles o idiomáticas como en Ruby. Entonces, en Python, un buen programador querrá tomar una ruta diferente para resolver el problema que lo haría en Ruby, solo porque en realidad es la mejor manera de hacerlo.


55
Estoy de acuerdo en que las lambdas tienen un alcance limitado y no son útiles en muchos casos. Sin embargo, no creo que sea justo decir que los programadores de Python los evitan como la peste.
Jason Baker

1
Estoy de acuerdo en que las lambdas se usan a menudo con Python, como con map, filter, reduce. La gran diferencia parece ser que las lambdas de Python están limitadas a expresiones, mientras que los bloques Ruby pueden ser multilínea e involucrar declaraciones. Mi impresión general de lo que he leído sobre Ruby es que esta característica en particular hace que los Rubyists opten por el enfoque DSL, mientras que los Pythonistas tienden a crear API. Sin embargo, mi información sobre Ruby sigue siendo muy superficial.
Anon

2
@Lennart: los bloques multilínea se usan todo el tiempo en Ruby, más a menudo de lo que veo las lambdas usadas en el código idiomático de Python, en realidad. Para ver un ejemplo común, consulte info.michael-simons.eu/2007/08/06/rails-respond_to-method .
Chuck

1
@ Lennart: No, no usa rendimiento. (El rendimiento de Ruby es completamente diferente del de Python de todos modos, no devuelve un generador). No sería significativo escribir for format in respond_to(). El respond_tométodo no devuelve nada significativo, simplemente responde a la solicitud HTTP actual. El doen respond_to does el comienzo de un bloque. En ese bloque, hablamos con un objeto temporal (etiquetado formaten este ejemplo) que implementa un DSL muy básico para responder a una solicitud HTTP.
Chuck

3
¿Puedes 'mezclar Enumerable' contra un generador y obtener instantáneamente 30 iteradores nuevos y maravillosos? Debes mirar el lenguaje en su totalidad antes de entender por qué los bloques / Procs son geniales.
sesgo

12

Me gustaría sugerir una variante de la pregunta original, "¿Qué tiene Ruby que Python no tiene y viceversa?" que admite la respuesta decepcionante: "Bueno, ¿qué puedes hacer con Ruby o Python que no se puede hacer en Intercal?" Nada en ese nivel, porque Python y Ruby son ambos parte de la vasta familia real sentada en el trono de ser aproximadamente Turing.

Pero qué hay de esto:

¿Qué se puede hacer con gracia y bien en Python que no se puede hacer en Ruby con tanta belleza y buena ingeniería, o viceversa?

Eso puede ser mucho más interesante que la mera comparación de características.


Un comentario en el mejor de los casos. sigue siendo mi +1
nawfal

11

Python tiene una sintaxis incorporada explícita para comprensiones de listas y generadores, mientras que en Ruby usaría bloques de código y de mapa.

Comparar

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

a

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

¿Cómo las comprensiones de listas no son una simple Python ? y hay una función de mapa en Python también.
SilentGhost

Pero no hay una sintaxis de comprensión de listas en 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

"Las variables que comienzan con mayúscula se convierten en constantes y no se pueden modificar"

Incorrecto. Ellos pueden.

Solo recibes una advertencia si lo haces.


2
Si un idioma le da una advertencia para una operación, es mi opinión que muy bien puede considerar la operación "no posible". Cualquier otra cosa es locura.
porgarmingduod

11

Algo más en el lado de la infraestructura:

  • Python tiene una integración mucho mejor con C ++ (a través de cosas como Boost.Python , SIP y Py ++ ) que Ruby, donde las opciones parecen estar escritas directamente en la API de intérprete de Ruby (que también puede hacer con Python, por supuesto, pero en ambos casos, hacerlo es de bajo nivel, tedioso y propenso a errores) o usar SWIG (que, si bien funciona y definitivamente es excelente si desea admitir muchos idiomas, no es tan bueno como Boost.Python o SIP si específicamente está buscando vincular C ++).

  • Python tiene varios entornos de aplicaciones web (Django, Pylons / Turbogears, web.py, probablemente al menos media docena de otros), mientras que Ruby (efectivamente) tiene uno: Rails. (Existen otros marcos web de Ruby, pero aparentemente tienen dificultades para obtener mucha tracción contra Rails). ¿Es este aspecto bueno o malo? Difícil de decir, y probablemente bastante subjetivo; Puedo imaginar fácilmente argumentos de que la situación de Python es mejor y que la situación de Ruby es mejor.

  • Culturalmente, las comunidades Python y Ruby parecen algo diferentes, pero solo puedo insinuar esto, ya que no tengo mucha experiencia interactuando con la comunidad Ruby. Estoy agregando esto principalmente con la esperanza de que alguien que tenga mucha experiencia con ambos pueda amplificar (o rechazar) esta declaración.


77
Su segundo punto está, en el mejor de los casos, mal informado. Deberías comenzar mirando a Rack y Sinatra
Max Ogden

66
Observo explícitamente que existen otras pilas de Rails; Simplemente no creo que nadie los esté usando realmente. Verificar a Sinatra y Rack no cambió exactamente esa impresión. ¿Realmente cree, por ejemplo, que Sinatra (94 preguntas SO en total), o Camping (2 preguntas SO en total), o cualquiera de los otros, en realidad tiene una base de usuarios / comunidad real? La mayoría de ellos ni siquiera tienen usuarios de la vida real, por lo que puedo decir. Compare con Django (4K +) o Rails (7K +), o incluso web.py para el caso.
Jack Lloyd

1
Sinatra es realmente bastante popular para diferentes tareas livianas debido a su DSL. Es menos usado porque el MVC de Rail proporciona más. Rails en realidad se basa en Rack: eso es lo que hace posible Phusion Passenger.
alternativa el

11

Copió / pegó descaradamente de: Alex Martelli responde en el hilo " ¿Qué es mejor sobre Ruby que Python " de la lista de correo comp.lang.python .

18 de agosto de 2003, 10:50 am Erik Max Francis escribió:

"Brandon J. Van Every" escribió:

¿Qué hay de mejor en Ruby que en Python? Estoy seguro de que hay algo. ¿Qué es?

¿No tendría mucho más sentido preguntarle a la gente de Ruby esto, en lugar de preguntarle a la gente de Python?

Podría, o no, dependiendo de los propósitos de uno; por ejemplo, si los propósitos de uno incluyen un "estudio sociológico" de la comunidad de Python, entonces hacer preguntas a esa comunidad probablemente resulte más revelador de información al respecto, que ponerlas en otro lugar :-).

Personalmente, aproveché la oportunidad para seguir el tutorial de un día de Dave Thomas sobre Ruby en el último OSCON. Debajo de una delgada capa de diferencias de sintaxis, encuentro que Ruby y Python son increíblemente similares: si calculara el árbol de expansión mínimo entre casi cualquier conjunto de idiomas, estoy bastante seguro de que Python y Ruby serían las dos primeras hojas en fusionarse un nodo intermedio :-).

Claro, me canso, en Ruby, de escribir el tonto "final" al final de cada bloque (en lugar de simplemente desangrar), pero luego evito escribir el igualmente tonto ':' que Python requiere en el comienzo de cada bloque, así que eso es casi un lavado :-). Otras diferencias de sintaxis como '@foo' versus 'self.foo', o la mayor importancia del caso en Ruby vs Python, son realmente tan irrelevantes para mí.

Otros, sin duda, basan su elección de lenguajes de programación en tales problemas, y generan los debates más candentes, pero para mí eso es solo un ejemplo de una de las Leyes de Parkinson en acción (la cantidad de debate sobre un tema es inversamente proporcional a la del tema importancia real).

Editar (antes de la AM 19/06/2010 11:45): esto también se conoce como "pintar el bikeshed" (o, para abreviar, "bikeshedding") - la referencia es, nuevamente, a Northcote Parkinson, quien dio "debates" sobre qué color pintar el bikeshed "como un ejemplo típico de" debates candentes sobre temas triviales ". (fin de edición).

Una diferencia de sintaxis que considero importante, y a favor de Python, pero otras personas sin duda pensarán exactamente lo contrario, es "cómo se llama a una función que no toma parámetros". En Python (como en C), para llamar a una función siempre se aplica el "operador de llamada" - paréntesis finales justo después del objeto que está llamando (dentro de esos paréntesis finales van los argumentos que está pasando en la llamada, si no estás pasando argumentos, entonces los paréntesis están vacíos). Esto deja la mera mención de cualquierobjeto, sin operador involucrado, ya que significa solo una referencia al objeto, en cualquier contexto, sin casos especiales, excepciones, reglas ad-hoc y similares. En Ruby (como en Pascal), para llamar a una función CON argumentos, pasa los argumentos (normalmente entre paréntesis, aunque ese no es siempre el caso) - PERO si la función no tiene argumentos, simplemente mencionar la función implícitamente la llama. Esto puede cumplir con las expectativas de muchas personas (al menos, sin duda, aquellas cuya única experiencia previa de programación fue con Pascal u otros lenguajes con "llamadas implícitas" similares, como Visual Basic), pero para mí, significa la mera mención de un objeto puede significar ya sea una referencia al objeto, O una llamada al objeto, dependiendo del tipo de objeto, y en los casos en que puedo ' Para obtener una referencia al objeto con solo mencionarlo, tendré que usar explícitamente "¡dame una referencia a esto, NO lo llames!" operadores que no son necesarios de otra manera. Siento que esto afecta la "primera clase" de funciones (o métodos u otros objetos invocables) y la posibilidad de intercambiar objetos sin problemas. Por lo tanto, para mí, esta diferencia de sintaxis específica es una marca negra seria contra Ruby, pero entiendo por qué los demás pensarían lo contrario, a pesar de que difícilmente podría estar en desacuerdo con ellos con más vehemencia :-). de funciones (o métodos u otros objetos invocables) y la posibilidad de intercambiar objetos sin problemas. Por lo tanto, para mí, esta diferencia de sintaxis específica es una marca negra seria contra Ruby, pero entiendo por qué los demás pensarían lo contrario, a pesar de que difícilmente podría estar en desacuerdo con ellos con más vehemencia :-). de funciones (o métodos u otros objetos invocables) y la posibilidad de intercambiar objetos sin problemas. Por lo tanto, para mí, esta diferencia de sintaxis específica es una marca negra seria contra Ruby, pero entiendo por qué los demás pensarían lo contrario, a pesar de que difícilmente podría estar en desacuerdo con ellos con más vehemencia :-).

Debajo de la sintaxis, llegamos a algunas diferencias importantes en la semántica elemental: por ejemplo, las cadenas en Ruby son objetos mutables (como en C ++), mientras que en Python no son mutables (como en Java, o creo que C #). Una vez más, las personas que juzgan principalmente por lo que ya están familiarizados pueden pensar que esto es una ventaja para Ruby (a menos que estén familiarizados con Java o C #, por supuesto :-). Yo, creo que las cadenas inmutables son una excelente idea (y no me sorprende que Java, independientemente, creo que reinventó esa idea que ya estaba en Python), aunque tampoco me importaría tener un tipo de "buffer de cadena mutable" (e idealmente uno con mejor facilidad de uso que los propios "buffers de cadenas" de Java); y no juzgo por familiaridad, antes de estudiar Java, todos los datos son inmutables, todos los lenguajes que conocía tenían cadenas mutables; sin embargo, cuando vi por primera vez la idea de la cadena inmutable en Java (que aprendí mucho antes de aprender Python), inmediatamente me pareció excelente, una muy buena opción para la semántica de referencia de un lenguaje de programación de nivel superior (a diferencia de la semántica de valor que mejor se adapta a los lenguajes más cercanos a la máquina y más alejados de las aplicaciones, como C) con cadenas como una primera clase, incorporada (y bonita crucial) tipo de datos.

Ruby tiene algunas ventajas en la semántica elemental, por ejemplo, la eliminación de la distinción extremadamente sutil de "listas vs tuplas" de Python. Pero sobre todo el puntaje (como lo mantengo, con simplicidad, una gran ventaja y distinciones sutiles e inteligentes, un notable menos) está en contra de Ruby (por ejemplo, tener intervalos cerrados y medio abiertos, con las anotaciones a..by a .. .b [alguien quiere decir que es obvio cuál es cuál? -)], es una tontería - ¡En mi humilde opinión, por supuesto!). Una vez más, las personas que consideran tener muchas cosas similares pero sutilmente diferentes en el núcleo de un idioma MÁS, en lugar de MENOS, por supuesto contarán esto "al revés" de la forma en que los cuento :-).

No se deje engañar por estas comparaciones para pensar que los dos idiomas son muydiferente, te importa. No lo son Pero si me piden que compare "capelli d'angelo" con "spaghettini", después de señalar que estos dos tipos de pasta son prácticamente indistinguibles para cualquiera e intercambiables en cualquier plato que desee preparar, entonces inevitablemente tendría para pasar al examen microscópico de cómo las longitudes y diámetros difieren imperceptiblemente, cómo se afilan los extremos de los hilos en un caso y no en el otro, y así sucesivamente, para tratar de explicar por qué yo personalmente preferiría capelli d 'angelo como la pasta en cualquier tipo de caldo, pero preferiría espaguetis como la pastasciutta para ir con salsas adecuadas para esas formas largas y delgadas de pasta (aceite de oliva, ajo picado, pimientos rojos picados y anchoas finamente molidas, por ejemplo, pero si rebanó los ajos y los pimientos en lugar de picarlos, entonces debe elegir el cuerpo de espagueti más sólido en lugar de la evanescencia más delgada de los espaguetis, y le recomendamos que renuncie a las achovies y agregue un poco de albahaca fresca de primavera [ o incluso, soy un hereje ...! - hojas de menta clara - en el último momento antes de servir el plato). Vaya, lo siento, eso demuestra que estoy viajando al extranjero y no he comido pasta por un tiempo, supongo. ¡Pero la analogía sigue siendo bastante buena! -) - hojas de menta clara - en el último momento antes de servir el plato). Vaya, lo siento, eso demuestra que estoy viajando al extranjero y no he comido pasta por un tiempo, supongo. ¡Pero la analogía sigue siendo bastante buena! -) - hojas de menta clara - en el último momento antes de servir el plato). Vaya, lo siento, eso demuestra que estoy viajando al extranjero y no he comido pasta por un tiempo, supongo. ¡Pero la analogía sigue siendo bastante buena! -)

Entonces, volviendo a Python y Ruby, llegamos a los dos grandes (en términos del lenguaje apropiado: abandonar las bibliotecas y otros elementos auxiliares importantes como herramientas y entornos, cómo incrustar / extender cada idioma, etc., etc.) por ahora, no se aplicarían a todas las IMPLEMENTACIONES de cada idioma de todos modos, por ejemplo, Jython vs Classic Python son dos implementaciones del lenguaje Python):

  1. Los iteradores y bloques de código de Ruby frente a los iteradores y generadores de Python;

  2. La "dinámica" desenfrenada TOTAL de Ruby, que incluye la capacidad
    de "reabrir" cualquier clase existente, incluidas todas las integradas, y cambiar su comportamiento en tiempo de ejecución, frente a la gran pero limitada dinámica de Python , que nunca cambia el comportamiento de las clases existentes. clases incorporadas y sus instancias.

Personalmente, considero que 1 es un lavado (las diferencias son tan profundas que fácilmente podría ver a las personas odiando cualquiera de los dos enfoques y revertir el otro, pero en MIS escalas personales, las ventajas y desventajas son casi iguales); y 2 un tema crucial, uno que hace que Ruby sea mucho más adecuado para "retoques", PERO Python es igualmente más adecuado para su uso en aplicaciones de gran producción. Es divertido, en cierto modo, porque ambos idiomas son MUCHO más dinámicos que la mayoría de los demás, que al final la diferencia clave entre ellos de mi POV debería depender de eso: que Ruby "va a once" en este sentido (la referencia aquí es "Spinal Tap", por supuesto). En rubí¡PUEDO HACER ESO ! Es decir, puedo alterar dinámicamente la clase de cadena incorporada para que a = "Hello World" b = "hello world" si a == b print "igual! \ N" sino print "different! \ N" end WILL print " igual". En python, NO hay forma de que pueda hacer eso. A los efectos de la metaprogramación, la implementación de marcos experimentales y similares, esta increíble capacidad dinámica de Ruby es extremadamente atractivo. PERO, si hablamos de aplicaciones grandes, desarrolladas por muchas personas y mantenidas por más, incluyendo todo tipo de bibliotecas de diversas fuentes, y que necesitan entrar en producción en sitios de clientes ... bueno, no QUIERO un lenguaje que es MUY dinámico, muchas gracias. Odio la idea de que una biblioteca rompa involuntariamente otras no relacionadas que confían en que esas cadenas son diferentes: ese es el tipo de "canal" profundo y profundamente oculto, entre piezas de código que MIRAN separadas y DEBEN SER separadas, que deletrean la muerte en programación a gran escala. Al permitir que cualquier módulo afecte el comportamiento de cualquier otro "encubierto", la capacidad de mutar la semántica de los tipos incorporados es solo una MALA idea para la programación de aplicaciones de producción,

Si tuviera que usar Ruby para una aplicación tan grande, trataría de confiar en restricciones de estilo de codificación, muchas pruebas (para volver a ejecutar cada vez que CUALQUIER COSA cambie, incluso lo que debería estar totalmente sin relación ...) y similares, para prohibir el uso de esta función de lenguaje. Pero NO tener la función en primer lugar es incluso mejor, en mi opinión, de la misma manera que Python sería un lenguaje aún mejor para la programación de aplicaciones si se pudiera "concretar" cierto número de funciones integradas, por lo que SABÍA que , por ejemplo, len ("ciao") es 4 (en lugar de tener que preocuparse subliminalmente de si alguien ha cambiado el enlace del nombre 'len' en el módulo integrado ...). Espero que eventualmente Python "clave" sus elementos integrados.

Pero el problema es menor, ya que volver a vincular los elementos integrados es una práctica bastante obsoleta y poco común en Python. En Ruby, me parece importante, al igual que las instalaciones macro demasiado potentes de otros idiomas (como, por ejemplo, Dylan) presentan riesgos similares en mi opinión (espero que Python nunca tenga un sistema macro tan poderoso, no importa el encanto de "dejar que las personas definan sus propios pequeños idiomas específicos de dominio incrustados en el lenguaje en sí mismo", en mi humilde opinión, perjudicaría la maravillosa utilidad de Python para la programación de aplicaciones, al presentar una "molestia atractiva" al aspirante a manipulador que acecha en el corazón de cada programador ...).

Alex


9

Algunos otros de:

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

(Si he malinterpretado algo o alguno de estos ha cambiado en el lado de Ruby desde que se actualizó esa página, alguien puede editarlo ...)

Las cadenas son mutables en Ruby, no en Python (donde las nuevas cadenas son creadas por "cambios").

Ruby tiene algunas convenciones de casos forzados, Python no.

Python tiene listas y tuplas (listas inmutables). Ruby tiene matrices correspondientes a las listas de Python, pero no hay una variante inmutable de ellas.

En Python, puede acceder directamente a los atributos del objeto. En Ruby, siempre es a través de métodos.

En Ruby, los paréntesis para las llamadas a métodos suelen ser opcionales, pero no en Python.

Ruby tiene acceso público, privado y protegido para forzar el acceso, en lugar de la convención de Python de utilizar guiones bajos y nombres de nombres.

Python tiene herencia múltiple. Ruby tiene "mixins".

Y otro enlace muy relevante:

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

Lo que, en particular, enlaza con otro bueno de Alex Martelli , quien también ha estado publicando muchas cosas geniales aquí en SO:

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


1
En ruby, simplemente podría congelar su matriz para cambiarla a algo inmutable
user163365

Excelente publicación de Alex Martelli :)
Skilldrick

8

No estoy seguro de esto, así que primero lo agrego como respuesta.

Python trata los métodos independientes como funciones

Eso significa que puede llamar a un método como theobject.themethod()o por TheClass.themethod(anobject).

Editar: aunque la diferencia entre métodos y funciones es pequeña en Python y no existe en Python 3, tampoco existe en Ruby, simplemente porque Ruby no tiene funciones. Cuando define funciones, en realidad está definiendo métodos en Object.

Pero aún no puede tomar el método de una clase y llamarlo como una función, tendría que volver a vincularlo al objeto al que desea llamar, lo que es mucho más obstinado.


Ruby no tiene funciones en absoluto. Dicho eso, TheClass.instance_method(:themethod).bind(anobject).callsería el rubí equivalente.
Logan Capaldo

Oh. Entonces, ¿hay algún tipo de clase principal mágica cuando define una función que no está en una clase explícita?
Lennart Regebro

Sí, los métodos definidos en el nivel superior son métodos privados de Object.
Logan Capaldo

1
FWIW, parece que en Python, las funciones y los métodos son en realidad del mismo tipo, y su comportamiento diferente proviene de los descriptores: users.rcn.com/python/download/… .
Bastien Léonard

1
Pero si lo vincula a un objeto, entonces no está desatado. Duh :-) Y son lo mismo en Python también. Es solo que Ruby en realidad no tiene funciones. Y eso significa que mi afirmación es correcta. Puede llamar a un método independiente como si fuera una función en Python. Y eso es realmente útil, eso significa, por ejemplo, que puede llamar a un método definido en una clase en un objeto que no tiene esa clase, que a veces es útil.
Lennart Regebro

7

Me gustaría mencionar la API de descriptor de Python que permite personalizar la "comunicación" de objeto a atributo. También es digno de mención que, en Python, uno es libre de implementar un protocolo alternativo anulando el valor predeterminado dado a través de la implementación predeterminada del __getattribute__método. Permítanme dar más detalles sobre lo mencionado anteriormente. Los descriptores son clases regulares con __get__, __set__y / o __delete__métodos. Cuando el intérprete encuentra algo como esto anObj.anAttr, se realiza lo siguiente:

  • __getattribute__anObjSe invoca el método de
  • __getattribute__ recupera un objeto Attr de la clase dict
  • Se comprueba si el objeto abAttr tiene __get__, __set__o __delete__los objetos no desembolsadas
  • el contexto (es decir, el objeto o la clase que llama, y ​​el valor, en lugar de este último, si tenemos setter) se pasa al objeto invocable
  • Se devuelve el resultado.

Como se mencionó, este es el comportamiento predeterminado. Uno es libre de cambiar el protocolo al volver a implementarlo __getattribute__.

Esta técnica es mucho más poderosa que los decoradores.


6

Ruby tiene soporte de continuación incorporado usando callcc.

Por lo tanto, puede implementar cosas interesantes como el operador amb


Desearía haber entendido callcc. ¿Puede dar un escenario de aplicación más mundano que el Operador ambiguo de McCarthy para apreciar sus ventajas? ¡Me refiero a algo del mundo real, no a esas cosas funky de CS!
ThomasH

"Funky CS stuff" es real. Tómese un tiempo para aprender: intertwingly.net/blog/2005/04/13/Continuations-for-Curmudgeons
Stephen Eilert


5

Python tiene cadenas de documentos y Ruby no ... O si no las tiene, no son accesibles tan fácilmente como en Python.

PD. Si estoy equivocado, bonito por favor, ¿deja un ejemplo? Tengo una solución alternativa que podría incluir en las clases con bastante facilidad, pero me gustaría tener la función docstring de alguna manera "nativa".


3
no tiene docstring, pero sí tiene RDoc. Entonces sí, no es tan accesible, pero no está 100% oculto.
Omar Qureshi

Ruby no usa cadenas de documentos. Hace la documentación de una manera diferente.
Chuck

1
Omar: sí, sé sobre rdoc pero afaik, no son "tan accesibles" como las cadenas de documentos de Python. Por ejemplo, si tengo una clase y quiero generar la documentación de rdoc desde dentro de la clase, es un trabajo bastante pesado. Lo que he hecho es generar una documentación de ri que intento mantener actualizada y luego obtener esa información. Sin duda no hasta el mismo nivel que las cadenas de documentación de Python ..
rasjani

Las cadenas de documentos se pueden usar para proporcionar pruebas de documentos. ¿Hay algo así para Ruby?
Lennart Regebro

2
Sí, se llama "Ruby Doctest". En lo que respecta a los documentos, todo lo que realmente importa es que tenga documentación legible en algún lugar que incluya fragmentos de código comprobables; no importa si está en una cadena de documentos o en un comentario.
Chuck

5

Ruby tiene un bucle línea por línea sobre los archivos de entrada (el indicador '-n') desde la línea de comandos para que pueda usarse como AWK. Esta línea de rubí:

ruby -ne 'END {puts $.}'

contará líneas como el AWK one-liner:

awk 'END{print NR}'

Ruby obtiene esta función a través de Perl, que lo tomó de AWK como una forma de hacer que los administradores de sistemas se unan a Perl sin tener que cambiar la forma en que hacen las cosas.


1
Me gustaría agregar que el soporte de línea de comando de Python es bastante débil. Además del bucle automático que falta, no puede poner un par de declaraciones en una sola línea y pasarla como un argumento de línea de comando de una sola cadena al intérprete. Al menos no pude hacerlo.
ThomasH

Por supuesto que puede. Pero (como con cualquier otro idioma) necesitará encerrarlo entre comillas.
Lennart Regebro

Python no está hecho para ser utilizado en la línea de comandos, ya que tiene que ser explícito acerca de algunas cosas (como sys.stdin) si desea utilizar de esa manerapython -c "import sys; print len(list(sys.stdin))"
u0b34a0f6ae

5

Ruby tiene sigilos y ramitas, Python no.

Editar : Y una cosa muy importante que olvidé (después de todo, lo anterior fue solo para encender un poco :-p):

Python tiene un compilador JIT ( Psyco ), un lenguaje de nivel visualmente inferior para escribir código más rápido ( Pyrex ) y la capacidad de agregar código C ++ en línea ( Weave ).


Es cierto, pero eso es solo la sintaxis.
Lennart Regebro

66
Bueno, si quieres ir por ese camino: ambos son completos de Turing. Todo lo demás es solo sintaxis.
Jörg W Mittag el

Sí y una diferencia de sintaxis importax ;-)
fortran

1
¿Qué importancia tiene si escribes @foo o self.foo?
Lennart Regebro

1
@ Jörg: OK, entonces llámalo de otra manera que "sintaxis". El punto es que @foo y self.foo hacen lo mismo, en realidad no es una funcionalidad que Ruby tiene y Python no.
Lennart Regebro

5

Mi pitón está oxidado, por lo que algunos de estos pueden estar en python y simplemente no recuerdo / nunca aprendí en primer lugar, pero aquí están los primeros que pensé:

Espacio en blanco

Ruby maneja los espacios en blanco completamente diferentes. Para empezar, no necesita sangrar nada (lo que significa que no importa si usa 4 espacios o 1 pestaña). También realiza la continuación de línea inteligente, por lo que lo siguiente es válido:

def foo(bar,
        cow)

Básicamente, si termina con un operador, se da cuenta de lo que está sucediendo.

Mixins

Ruby tiene mixins que pueden extender instancias en lugar de clases completas:

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

Enumeraciones

No estoy seguro de si esto es lo mismo que los generadores, pero a partir de Ruby 1.9 ruby ​​como enumeraciones, entonces

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

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

"Argumentos de palabras clave"

Los dos elementos enumerados allí son compatibles con Ruby, aunque no puede omitir valores predeterminados como ese. Puedes ir en orden

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

Tenga en cuenta que c = 5 en realidad asigna a la variable c en el alcance de la llamada el valor 5 y establece el parámetro b en el valor 5.

o puede hacerlo con hashes, que abordan el segundo 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

Referencia: La guía del programador pragmático para Ruby


Su segundo ejemplo foo (1, c = 5) no hace lo que cree que hace. Ruby no tiene parámetros con nombre.
horseyguy 03 de

55
Python tiene continuación de línea implícita entre paréntesis (, [o{
u0b34a0f6ae

5

Puede tener código en la definición de clase en Ruby y Python. Sin embargo, en Ruby tienes una referencia a la clase (self). En Python no tiene una referencia a la clase, ya que la clase aún no está definida.

Un ejemplo:

class Kaka
  puts self
end

self en este caso es la clase, y este código imprimirá "Kaka". No hay forma de imprimir el nombre de la clase o de otra manera acceder a la clase desde el cuerpo de definición de clase en Python.


¿Puede proporcionar más detalles (como el código) para su primer punto?
Loïc Wolff el

El código de ejemplo es una buena idea, agregué eso, aunque este caso es trivial.
Lennart Regebro

@SilentGhost: No puedo pensar en uno que no sea realmente oscuro en este momento. :)
Lennart Regebro

puede acceder al nombre de la clase dentro de la clase en python: class foo (): def init __ (self): print self .__ class .__ name__
txwikinger

1
@txwikinger: sí, pero no dentro del cuerpo de la clase, que se ejecuta al mismo tiempo que la classdeclaración.
Bastien Léonard

4

La sintaxis no es algo menor, tiene un impacto directo en cómo pensamos. También tiene un efecto directo sobre las reglas que creamos para los sistemas que utilizamos. Como ejemplo, tenemos el orden de las operaciones debido a la forma en que escribimos ecuaciones u oraciones matemáticas. La notación estándar para las matemáticas permite a las personas leerla de más de una manera y llegar a diferentes respuestas dada la misma ecuación. Si hubiéramos utilizado la notación de prefijo o postfijo, habríamos creado reglas para distinguir cuáles eran los números a manipular en lugar de tener solo reglas para el orden en que se calculan los valores.

La notación estándar deja en claro de qué números estamos hablando al tiempo que hace que el orden en el que se calculan sea ambiguo. La notación de prefijos y postfijos hace que el orden en el que se compute sea simple mientras que los números son ambiguos. Python ya tendría lambdas multilínea si no fuera por las dificultades causadas por el espacio en blanco sintáctico. (Existen propuestas para lograr este tipo de cosas sin agregar necesariamente delimitadores de bloque explícitos).

Me resulta más fácil escribir condiciones en las que quiero que ocurra algo si una condición es falsa, es mucho más fácil escribir con la declaración a menos en Ruby que la construcción semánticamente equivalente "si no" en Ruby u otros idiomas, por ejemplo. Si la mayoría de los idiomas que la gente usa hoy en día tienen el mismo poder, ¿cómo puede considerarse que la sintaxis de cada idioma es algo trivial? Después de características específicas como bloques y mecanismos de herencia, etc., la sintaxis es la parte más importante de un lenguaje, apenas algo superficial.

Lo superficial son las cualidades estéticas de la belleza que atribuimos a la sintaxis. La estética no tiene nada que ver con cómo funciona nuestra cognición, la sintaxis sí.


Este "comentario" es tres veces más largo de lo que está permitido en un comentario, independientemente del representante.
Andrew Grimm

Esto realmente parece estar bien como respuesta para mí. Editado el bit "esto es un comentario".
Bill the Lizard

3

Sorprendido de no ver nada del mecanismo de "método perdido" de Ruby. Daría ejemplos de los métodos find_by _... en Rails, como un ejemplo del poder de esa característica del lenguaje. Supongo que algo similar podría implementarse en Python, pero que yo sepa no está allí de forma nativa.


Python tiene get_attribute , que logra básicamente lo mismo que el método de pérdida de Ruby.
mipadi

3
¿Por qué los desarrolladores de python siempre se lastiman tanto cuando se menciona ruby ​​EN CUALQUIER LUGAR? No puedes negar que esto no es cierto.
aarona

method_missingpuede ser emulado en Python en algunos casos: class M(): def __getattr__(self, n): return lambda: "Missing! " + n; M().hi(). Sin embargo, existen pequeñas diferencias y dudo que sea idiomático en Python :-)

1
@DJTripleThreat: niego que sea cierto.
Lennart Regebro

3

El problema del generador de acumuladores de Paul Graham demuestra otra diferencia en lambdas entre Python y Ruby . Reimpreso aquí:

Escriba una función foo que tome un número n y devuelva una función que tome un número i, y devuelva n incrementada en i. Nota: (a) es un número, no un entero, (b) se incrementa en, no más.

En Ruby, puedes hacer esto:

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

En Python, crearía un objeto para mantener el estado de n:

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

Algunas personas podrían preferir el enfoque explícito de Python como más claro conceptualmente, incluso si es un poco más detallado. Almacena el estado como lo hace para cualquier otra cosa. Solo necesita comprender la idea de los objetos invocables. Pero independientemente de cuál enfoque prefiera estéticamente, muestra un respeto en el que las lambdas de Ruby son construcciones más poderosas que las de Python.


3
No puede incrementar los números en Python, por lo que esa restricción no tiene sentido. En Python los números son inmutables. Si lo cambiamos a "más", la clase es innecesaria. Por lo tanto, esto no demuestra nada sobre la diferencia lambda, sino la diferencia en cómo funcionan los números. A menos que, por supuesto, cree una clase de número mutable. :)
Lennart Regebro

2
La restricción está ahí para aclarar el comportamiento deseado. Lo que pide el problema es: f = foo (10) f (2) >> 12 f (3) >> 15 ... lambda {| i | n + i} da: f = foo (10) f (2) >> 12 f (3) >> 13 ... Los números también son inmutables en Ruby; por ejemplo, no se puede decir 2 + = 1. Y n + = 1 está bien en una función Python normal, pero no en una lambda. Entonces, es una cuestión de qué es "n", el hecho de que se crea cuando se invoca la función y se forma el lambda, que puede hacer una asignación en un lambda (en lugar de solo expresiones), y que puede contener el valor de n sobre múltiples llamadas.
dormsbee

No creo que debas llegar a tales extremos en Python. Las funciones se pueden definir dentro de otras funciones. def foo(n): def f(i): return n + i return f.
FMc

2
Sin embargo, todavía no es lo mismo, y su ejemplo es equivalente a la lambda de Python en el comentario anterior. La versión Ruby crea una lambda que mantiene el estado entre llamadas. El ejemplo que publicó le permite configurar un valor inicial para n, pero la función que devuelve foo siempre tendrá ese valor inicial. La versión Ruby se incrementa. Entonces digamos f = foo (10). La versión de Python: f (1) => 11, f (1) => 11. La versión de 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. En Python3 podría usar la nonlocalpalabra clave.
jfs

3

Python ha nombrado argumentos opcionales

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 solo ha posicionado argumentos porque b = 2 en la declaración de función es una afectación que siempre se agrega.


3
¿Qué significa "Ruby solo ha posicionado argumentos porque b = 2 en la declaración de función es una afectación que siempre se agrega" incluso significa?
horseyguy

3
¡No sé en qué planeta vives, pero def my_method(param1, optional = false)funciona en Ruby 1.8.6, 1.8.7 y presumiblemente 1.9!
Robert K

55
The Wicked Flea, y las personas que votaron por su comentario, no miraste el ejemplo lo suficientemente cerca. Es capaz de omitir el bparámetro en la funcllamada y aún mantiene su valor predeterminado. Es decir, bes el segundo argumento en la firma, pero puede omitirlo al prefijar el segundo parámetro con c=. Ruby usa hashes para simular esto, pero no es exactamente lo mismo.
maček

2

Ruby tiene documentación incrustada:

 =begin

 You could use rdoc to generate man pages from this documentation

 =end

55
Las cadenas de documentos terminan como parte de los métodos / clases en los que los configuró. Para que pueda ayudar (clase) y le mostrará las cadenas de documentos, etc.
Lennart Regebro


2

En Ruby, cuando importa un archivo con require, todas las cosas definidas en ese archivo terminarán en su espacio de nombres global.

Con Cargo puede " requerir bibliotecas sin saturar su espacio de nombres ".

# 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 = importar ("foo-1.0.0")
>> Foo2 = importar ("foo-2.0.0")
>> Foo1 :: VERSIÓN
=> "1.0.0"
>> Foo2 :: VERSIÓN
=> "2.0.0"

Más bien debería haber sido un comentario, no una nueva respuesta.
Lennart Regebro
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.