2011-01-22 16 views
116

Conozco a Ruby muy bien. Creo que puedo necesitar aprender Python actualmente. Para aquellos que conocen ambos, ¿qué conceptos son similares entre los dos y qué son diferentes?Aprendiendo Python de Ruby; Diferencias y similitudes

Estoy buscando una lista similar a un manual que escribí para Learning Lua for JavaScripters: cosas simples como significado de espacio en blanco y construcciones de bucle; el nombre de nil en Python, y qué valores se consideran "verdad"; es idiomática a utilizar el equivalente de map y each, o son Mumble somethingaboutlistcomprehensionsmurmullo la norma?

Si recibo una buena variedad de respuestas, me complace agregarlas en una wiki de la comunidad. O bien, todos ustedes pueden luchar y protegerse mutuamente para tratar de crear la única y completa lista completa.

Editar: Para ser claros, mi objetivo es "apropiado" y idiomático Python. Si hay un equivalente en Python de inject, pero nadie lo usa porque hay una manera mejor/diferente de lograr la funcionalidad común de repetir una lista y acumular un resultado en el camino, quiero saber cómo se hacen las cosas. Tal vez actualice esta pregunta con una lista de objetivos comunes, cómo los logra en Ruby, y pregunte cuál es el equivalente en Python.

+1

lo único que leí fue http : //c2.com/cgi/wiki?PythonVsRuby, realmente no me gustan los self y los indentions pero me acostumbré :) –

+1

Relacionados: http://stackoverflow.com/questions/1113611/what-does-ruby- have-that-python-doesnt-and-vice-versa (No estoy seguro de si es un duplicado, ya que esa pregunta pide cosas sin equivalente). – delnan

+1

@Saif Esa discusión tuvo muchos ejemplos desactualizados y malos la última vez que revisé. Sugiriendo 'a = []; 0.upto (2) {| i | 0.upto (2) {| j | a << [i, j] si i! = J}}' como un equivalente de Ruby de '[ (x, y) para x en xrange (3) para y en xrange (3) si x! = y] '(y luego eliminando todos los espacios en blanco y llamando a eso una mejora) es más o menos lo que arriesgas cuando no lo haces prestar atención al consejo de Ircmaxell. – badp

Respuesta

141

Aquí hay algunas diferencias clave para mí:

  1. Ruby tiene bloques ; Python no.

  2. Python tiene funciones; Ruby no. En Python, puede tomar cualquier función o método y pasarlo a otra función. En Ruby, todo es un método y los métodos no pueden pasarse directamente. En cambio, debes envolverlos en Proc para pasarlos.

  3. Ruby y Python son compatibles con cierres, pero de diferentes maneras. En Python, puede definir una función dentro de otra función. La función interna tiene acceso de lectura a las variables de la función externa, pero no al acceso de escritura. En Ruby, defines cierres usando bloques. Los cierres tienen acceso completo de lectura y escritura a las variables del alcance externo.

  4. Python tiene una lista de comprensiones bastante expresiva. Por ejemplo, si usted tiene una lista de números, puede escribir

    [x*x for x in values if x > 15] 
    

    para obtener una nueva lista de los cuadrados de los valores superiores a 15.En Ruby, debe escribir lo siguiente:

    values.select {|v| v > 15}.map {|v| v * v} 
    

    El código de Ruby no se siente tan compacto. Tampoco es tan eficiente ya que primero convierte la matriz de valores en una matriz intermedia más corta que contiene los valores superiores a 15. Luego, toma la matriz intermedia y genera una matriz final que contiene los cuadrados de los intermedios. La matriz intermedia se descarta. Entonces, Ruby termina con 3 matrices en la memoria durante el cálculo; Python solo necesita la lista de entrada y la lista resultante.

    Python también proporciona comprensiones de mapas similares.

  5. Python admite tuplas; Ruby no. En Ruby, debes usar matrices para simular tuplas.

  6. Ruby admite declaraciones de interruptor/caja; Python no.

  7. Ruby admite el operador ternario estándar expr ? val1 : val2; Python no.

  8. Ruby solo admite herencia individual. Si necesita imitar una herencia múltiple, puede definir módulos y usar mezclas para extraer los métodos del módulo en clases. Python admite herencia múltiple en lugar de módulos mix-ins.

  9. Python solo admite funciones lambda de línea única. Los bloques de Ruby, que son una especie de/tipo de funciones lambda, pueden ser arbitrariamente grandes. Debido a esto, el código de Ruby generalmente se escribe en un estilo más funcional que el código de Python. Por ejemplo, para recorrer una lista en Ruby, lo hace normalmente

    collection.each do |value| 
        ... 
    end 
    

    El bloque funciona muy parecido a una función que se pasa al collection.each. Si se va a hacer la misma cosa en Python, que tendría que definir una función llamada interior y luego pasar a la colección que cada método (si la lista apoyado este método):

    def some_operation(value): 
        ... 
    
    collection.each(some_operation) 
    

    que no fluye muy amable. Así que, por lo general el enfoque no funcional después se utilizaría en Python:

    for value in collection: 
        ... 
    
  10. El uso de los recursos de una manera segura es bastante diferente entre las dos lenguas. Aquí, el problema es que desea asignar algún recurso (abrir un archivo, obtener un cursor de base de datos, etc.), realizar alguna operación arbitraria en él y luego cerrarlo de manera segura incluso si se produce una excepción.

    En Ruby, porque los bloques son tan fáciles de usar (ver n. ° 9), normalmente codificaría este patrón como un método que requiere un bloque para que la operación arbitraria funcione en el recurso.

    En Python, pasar una función para la acción arbitraria es un poco más lento ya que tiene que escribir una función interna con nombre (ver # 9). En cambio, Python usa una declaración with para el manejo seguro de recursos. Ver How do I correctly clean up a Python object? para más detalles.

+2

3. Python 3 'nonlocal' corrige esto 4. Python también le da expresiones de generador (similar a listas de comprensión, pero no computa nada hasta que se le pide - piense en listas de comprensiones como expresiones generadoras alimentadas a' list' (que toma una iterable y devuelve una lista que contiene todo lo que produjo iterable); esto puede ahorrar mucho esfuerzo en algunos casos). – delnan

+25

7. Sí lo hace. 'val1 if expr else val2'. 8.Aunque lo veo principalmente utilizado para el aumento de estilo mixin. – delnan

+2

@ClintMiller Whoa, no switch/case? Entonces, ¿cuál es la forma sugerida de lograr una funcionalidad similar en Python? if/else/if? – Phrogz

10

Mi sugerencia: No intente aprender las diferencias. Aprenda cómo abordar el problema en Python. Al igual que hay un enfoque Ruby para cada problema (que funciona muy bien dando las limitaciones y fortalezas del lenguaje), hay un enfoque de Python para el problema. ambos son diferentes Para obtener lo mejor de cada idioma, realmente debe aprender el idioma en sí, y no solo la "traducción" de uno a otro.

Ahora, dicho esto, la diferencia te ayudará a adaptarte más rápido y hacer modificaciones de 1 a un programa de Python. Y eso está bien para comenzar a escribir. Pero tratar de aprender de otros proyectos el por qué detrás de las decisiones de arquitectura y diseño en lugar de la forma detrás de la semántica de la lengua ...

+7

Agradezco su sugerencia. Estoy completamente de acuerdo con el sentimiento _ (que interpreto como "Aprende a programar Python idiomático") _. Eso es precisamente lo que trato de hacer. No pregunto _ "¿Cuál es el nombre de Python para el método 'cada uno' de Ruby?" _ Pregunto _ "¿Cómo se hacen las cosas correctamente en Python a diferencia de Ruby, y dónde se hacen de la misma manera?" _ Si El '' falso' de Python es en realidad 'False', eso es tan importante como saber dónde y cuándo debo hacer las cosas de manera Rubyesque, y dónde y cuándo no debería hacerlo. – Phrogz

+1

@Phrogz: Eso es justo. La forma en que interpreté tu pregunta fue: * Hagamos una lista de las diferencias para que podamos cambiar el idioma en el que estamos programando *. Pero es una buena pregunta. Supongo que interpreté mal lo que estabas pidiendo. Lo dejo aquí para referencia, pero será interesante ver qué más aparece ... – ircmaxell

+0

Estoy aprendiendo python y ruby ​​al mismo tiempo, y en el desarrollo de aplicaciones web veo más similitudes que diferencias. – FaithReaper

7

sé poco Ruby, pero aquí hay unos puntos sobre las cosas que usted ha mencionado:

  • nil, el valor que indica la falta de un valor, sería None (tenga en cuenta que compruebe si hay es como x is None o x is not None, no con == - o mediante coerción a booleano, consulte el siguiente punto).
  • None, números del cero-esque (0, 0.0, 0j (número complejo)) y colecciones vacías ([], {}, set(), la cadena vacía "", etc.) se consideran Falsy, todo lo demás se considera Truthy.
  • Para efectos secundarios, (for -) loop explícitamente. Para generar un nuevo grupo de cosas sin efectos secundarios, use listas de comprensión (o sus parientes, expresiones generadoras para iteradores perezosos de una sola vez, comprensión dictada/establecida para dichas colecciones).

En cuanto bucle: Usted tiene for, que opera en una iterable (sin contando!), Y while, que hace lo que se puede esperar. El remitente es mucho más poderoso, gracias al amplio soporte para iteradores. No solo casi todo lo que puede ser un iterador en lugar de una lista es un iterador (al menos en Python 3: en Python 2, tienes ambas cosas y la lista predeterminada es una lista, lamentablemente). Existen numerosas herramientas para trabajar con iteradores: zip itera cualquier número de iterables en paralelo, enumerate le da (index, item) (en cualquier iterable, no solo en las listas), incluso cortando iterables abritary (posiblemente grandes o infinitos)! Descubrí que esto hace que muchas tareas de bucle sean mucho más simples. No hace falta decir que se integran muy bien con listas de comprensión, expresiones de generador, etc.

+2

Las expresiones de generador son geniales. Le dan a Python algunas de las capacidades de evaluación perezosa de lenguajes como Haskell. –

+0

@Clint: sí. Y los generadores completos son aún más capaces (aunque no necesarios para casos simples, que son la mayoría). – delnan

+0

¿Por qué comprueba con 'x is None' o' x is not None'? Siempre controlo con 'x == None' y' x! = None'. – John

6

En Ruby, las variables de instancia y los métodos no tienen ninguna relación, excepto cuando los relacionas explícitamente con attr_accessor o algo así.

En Python, los métodos son solo una clase especial de atributos: uno que es ejecutable.

Así, por ejemplo:

>>> class foo: 
...  x = 5 
...  def y(): pass 
... 
>>> f = foo() 
>>> type(f.x) 
<type 'int'> 
>>> type(f.y) 
<type 'instancemethod'> 

Esa diferencia tiene muchas implicaciones, como por ejemplo el que se refiere a f.x se refiere al método objeto, en lugar de llamarlo. Además, como puede ver, f.x es público por defecto, mientras que en Ruby, las variables de instancia son privadas por defecto.

+1

En realidad, lo declararía aún más crudamente: en Python, los métodos son solo un tipo particular de atributo, mientras que en Ruby, los atributos son solo un tipo particular de método. Algunas características importantes contrastantes entre los dos idiomas se desprenden de esto: Funciones de primera clase en Python y el Principio de acceso uniforme en Ruby – philomory

26

Acabo de pasar un par de meses aprendiendo Python después de 6 años de Ruby. Realmente no hubo una gran comparación para los dos idiomas, así que decidí levantarme y escribir uno yo mismo. Ahora, es principalmente relacionado con la programación funcional, pero como mencionas el método inject de Ruby, supongo que estamos en la misma longitud de onda.

espero que esto ayude: The 'ugliness' of Python

Un par de puntos que les permite conocer moviendo en la dirección correcta:

  • toda la calidad de la programación funcional se utiliza en Ruby es en Python, y es aún más fácil.Por ejemplo, puede asignar más funciones exactamente como era de esperar:

    def f(x): 
        return x + 1 
    
    map(f, [1, 2, 3]) # => [2, 3, 4] 
    
  • Python no tiene un método que actúa como each. Dado que sólo se utiliza each para los efectos secundarios, el equivalente en Python es el bucle for:

    for n in [1, 2, 3]: 
        print n 
    
  • listas por comprensión son grandes cuando a) usted tiene que tratar con funciones y colecciones de objetos juntos y b) cuando se necesitan iterar usando múltiples índices. Por ejemplo, para encontrar todos los palíndromos en una cadena (suponiendo que tiene una función p() que devuelve cierto para los palíndromos), todo lo que necesita es una lista única de comprensión:

    s = 'string-with-palindromes-like-abbalabba' 
    l = len(s) 
    [s[x:y] for x in range(l) for y in range(x,l+1) if p(s[x:y])] 
    
+3

Suspiro, leí esa publicación y confirma mi sospecha: pocas personas entienden el papel y la utilidad de los métodos especiales en Pitón. Son increíblemente útiles y estandarizados, y se subrayan así para evitar nombrar conflictos con los integrales que a menudo implementan. Nadie que realmente conozca Python está tratando de desalentar su uso. –

+5

Parece que no entiende cómo funcionan los métodos. Un método es, esencialmente, una función cuyo primer argumento es una instancia de la clase a la que pertenece el método. Cuando escribe 'Class.method', el método es" unbound "y el primer argumento debe ser una instancia' Class'; cuando escribes 'object.method', el método está" vinculado "a la instancia' object' de 'Class'. Esto le permite elegir si usar map (etc) para llamar al método en una instancia de diferencia cada vez (pasar un método independiente), o mantener la instancia fija y pasar un segundo argumento diferente cada vez. Ambos son útiles. – LaC

+2

Tienes razón, no entendía cómo funcionaban. Desde que publiqué el artículo, lo entendí mejor. ¡Gracias! –

Cuestiones relacionadas