132 votes

Apprendre Python à partir de Ruby ; différences et similitudes

Je connais très bien Ruby. Je pense que je devrais peut-être apprendre Python actuellement. Pour ceux qui connaissent les deux, quels sont les concepts similaires entre les deux, et ceux qui sont différents ?

Je cherche une liste similaire à celle que j'ai rédigée pour Apprendre Lua pour les JavaScripters : des choses simples comme la signification de l'espace blanc et les constructions en boucle ; le nom de l'élément nil en Python, et quelles valeurs sont considérées comme "véridiques" ; est-il idiomatique d'utiliser l'équivalent de map y each ou sont mumble quelque chose à propos des compréhensions de la liste mumble la norme ?

Si je reçois une bonne variété de réponses, je serai heureux de les regrouper dans un wiki communautaire. Sinon, vous pouvez tous vous battre et vous inspirer les uns des autres pour essayer de créer la seule vraie liste complète.

Editar : Pour être clair, mon objectif est un Python "correct" et idiomatique. S'il existe un équivalent Python de inject mais personne ne l'utilise parce qu'il existe un moyen meilleur/différent de réaliser la fonctionnalité commune d'itération d'une liste et d'accumulation d'un résultat en cours de route, je veux savoir comment vous faites les choses. Je vais peut-être mettre à jour cette question avec une liste d'objectifs communs, comment vous les atteignez en Ruby, et demander quel est l'équivalent en Python.

1 votes

La seule chose que j'ai lue est c2.com/cgi/wiki?PythonVsRuby Je n'aime pas vraiment le self et les indentations mais je m'y suis habituée :)

1 votes

En rapport : stackoverflow.com/questions/1113611/ (Je ne suis pas tout à fait sûr qu'il s'agisse d'un doublon, car cette question demande des choses sans équivalent).

1 votes

@Saif Cette discussion comportait beaucoup d'exemples dépassés et mauvais la dernière fois que j'ai vérifié. Suggérer a=[];0.upto(2){|i|0.upto(2){|j|a<<[i,j] if i!=j}} comme un équivalent Ruby de [(x,y) for x in xrange(3) for y in xrange(3) if x != y] (et ensuite supprimer tous les espaces et appeler cela une amélioration) est à peu près ce que vous risquez de faire lorsque vous ne tenez pas compte des conseils d'ircmaxell.

154voto

Clint Miller Points 6339

Voici les principales différences à mes yeux :

  1. Ruby a des blocs ; Python n'en a pas.

  2. Python a des fonctions, Ruby n'en a pas. En Python, vous pouvez prendre n'importe quelle fonction ou méthode et la passer à une autre fonction. En Ruby, tout est une méthode, et les méthodes ne peuvent pas être passées directement. Au lieu de cela, vous devez les envelopper dans des Proc pour les transmettre.

  3. Ruby et Python supportent tous deux les fermetures, mais de manière différente. En Python, vous pouvez définir une fonction à l'intérieur d'une autre fonction. La fonction interne a accès en lecture aux variables de la fonction externe, mais pas en écriture. En Ruby, vous définissez les fermetures à l'aide de blocs. Les fermetures ont un accès complet en lecture et en écriture aux variables de la fonction externe.

  4. Python possède des compréhensions de listes, qui sont assez expressives. Par exemple, si vous avez une liste de nombres, vous pouvez écrire

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

    pour obtenir une nouvelle liste des carrés de toutes les valeurs supérieures à 15. En Ruby, vous devriez écrire ce qui suit :

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

    Le code Ruby ne semble pas aussi compact. Il n'est pas non plus aussi efficace puisqu'il convertit d'abord le tableau des valeurs en un tableau intermédiaire plus court contenant les valeurs supérieures à 15. Ensuite, il prend le tableau intermédiaire et génère un tableau final contenant les carrés des tableaux intermédiaires. Le tableau intermédiaire est ensuite jeté. Ainsi, Ruby se retrouve avec 3 tableaux en mémoire pendant le calcul ; Python n'a besoin que de la liste d'entrée et de la liste résultante.

    Python fournit également des compréhensions de cartes similaires.

  5. Python supporte les tuples ; Ruby ne le fait pas. En Ruby, vous devez utiliser des tableaux pour simuler les tuples.

  6. Ruby supporte les instructions switch/case ; Python ne le fait pas.

  7. Ruby supporte le standard expr ? val1 : val2 opérateur ternaire ; Python ne le fait pas.

  8. Ruby ne supporte que l'héritage simple. Si vous souhaitez imiter l'héritage multiple, vous pouvez définir des modules et utiliser des mix-ins pour intégrer les méthodes du module dans les classes. Python supporte l'héritage multiple plutôt que les mix-ins de modules.

  9. Python ne prend en charge que les fonctions lambda à ligne unique. Les blocs Ruby, qui sont des sortes de fonctions lambda, peuvent avoir une taille arbitraire. De ce fait, le code Ruby est généralement écrit dans un style plus fonctionnel que le code Python. Par exemple, pour boucler sur une liste en Ruby, vous faites généralement

    collection.each do |value|
      ...
    end

    Le bloc fonctionne de manière très similaire à une fonction passée à collection.each . Si vous deviez faire la même chose en Python, vous devriez définir une fonction interne nommée, puis la passer à la méthode collection each (si la liste supporte cette méthode) :

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

    Ça ne s'enchaîne pas très bien. Donc, typiquement, l'approche non-fonctionnelle suivante serait utilisée en Python :

    for value in collection:
      ...
  10. L'utilisation des ressources de manière sûre est assez différente entre les deux langues. Ici, le problème est que vous voulez allouer une ressource (ouvrir un fichier, obtenir un curseur de base de données, etc.), effectuer une opération arbitraire sur celle-ci, puis la fermer de manière sûre même si une exception se produit.

    En Ruby, les blocs étant très faciles à utiliser (voir n°9), vous coderez typiquement ce modèle comme une méthode qui prend un bloc pour l'opération arbitraire à effectuer sur la ressource.

    En Python, passer une fonction pour l'action arbitraire est un peu plus compliqué car vous devez écrire une fonction interne nommée (voir n°9). Au lieu de cela, Python utilise une fonction with pour une manipulation sûre des ressources. Voir Comment nettoyer correctement un objet Python ? pour plus de détails.

2 votes

3. Python 3 nonlocal Python vous offre également des expressions génératrices (similaires aux compréhensions de listes, mais qui ne calculent rien tant qu'on ne le leur demande pas - considérez les compréhensions de listes comme des expressions génératrices alimentées à list (qui prend un itérable et renvoie une liste contenant tout ce que l'itérable a donné) - cela peut économiser beaucoup d'efforts dans certains cas).

25 votes

7. Oui, c'est vrai. val1 if expr else val2 . 8. Bien que je le vois surtout utilisé pour l'augmentation de style mixin.

2 votes

@ClintMiller Whoa, pas de switch/case ? Alors, quel est le moyen suggéré pour obtenir une fonctionnalité similaire en Python ? if/else/if ?

27voto

David J. Points 1036

Comme vous, j'ai cherché inject et d'autres méthodes fonctionnelles lors de l'apprentissage de Python. J'ai été déçu de constater qu'elles n'étaient pas toutes présentes, ou que Python privilégiait une approche impérative. Cela dit, la plupart des constructions sont là si vous regardez. Dans certains cas, une bibliothèque rendra les choses plus agréables.

Quelques points forts pour moi :

  • Les modèles de programmation fonctionnelle que vous connaissez de Ruby sont disponibles en Python. Ils sont simplement un peu différents. Par exemple, il existe une fonction map :

      def f(x):
          return x + 1
    
      map(f, [1, 2, 3]) # => [2, 3, 4]

    De même, il existe un reduce fonction pour replier des listes, etc.

    Cela dit, Python manque de blocs et ne dispose pas d'une syntaxe simplifiée pour enchaîner ou composer des fonctions. (Pour une belle façon de faire cela sans blocs, consultez la syntaxe riche de Haskell).

  • Pour une raison ou une autre, la communauté Python semble préférer l'itération impérative pour des choses qui, en Ruby, se feraient sans mutation. Par exemple, les plis (c'est-à-dire, inject ), se font souvent à l'aide d'un impératif for au lieu de reduce :

      running_total = 0
      for n in [1, 2, 3]:
          running_total = running_total + n

    Ce n'est pas seulement une convention, c'est aussi renforcé par les mainteneurs de Python. Par exemple, le fichier Notes de version de Python 3 favoriser explicitement for boucle sur reduce :

    Utilisez functools.reduce() si vous en avez vraiment besoin ; cependant, dans 99 % des cas, une version explicite for La boucle est plus lisible.

  • Les compréhensions de listes sont un moyen concis d'exprimer des opérations fonctionnelles complexes (similaire à la monade de liste de Haskell). Elles ne sont pas disponibles en Ruby et peuvent être utiles dans certains scénarios. Par exemple, pour trouver tous les palindromes dans une chaîne de caractères (en supposant que vous ayez une fonction p() qui renvoie vrai pour les palindromes) ressemble à ceci :

      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])]
  • Les méthodes en Python peuvent être traitées comme des fonctions sans contexte dans de nombreux cas, ce à quoi vous devrez vous habituer en venant de Ruby, mais qui peut être très puissant.

Au cas où cela vous aiderait, j'ai rédigé d'autres réflexions ici en 2011 : La "laideur" de Python . Ils peuvent avoir besoin d'être mis à jour à la lumière de l'accent mis aujourd'hui sur le ML.

3 votes

Sigh, j'ai lu ce post et cela confirme mes soupçons : peu de gens comprennent le rôle et l'utilité des méthodes spéciales en Python. Elles sont incroyablement utiles et standardisées, et elles sont soulignées comme ça pour éviter les conflits de noms avec les builtins qu'elles implémentent souvent. Aucune personne connaissant réellement Python n'essaie de décourager leur utilisation.

5 votes

Vous ne semblez pas comprendre comment les méthodes fonctionnent. Une méthode est, essentiellement, une fonction dont le premier argument est une instance de la classe à laquelle la méthode appartient. Lorsque vous écrivez Class.method la méthode est "non liée" et le premier argument doit être un numéro d'identification de la méthode. Class par exemple, lorsque vous écrivez object.method la méthode est "liée" à l object exemple de Class . Cela vous permet de choisir d'utiliser map (etc) pour appeler la méthode sur une instance différente à chaque fois (passer une méthode non liée), ou de garder l'instance fixe et de passer un second argument différent à chaque fois. Les deux méthodes sont utiles.

2 votes

Tu as raison, je n'ai pas compris comment ils fonctionnaient. Depuis la publication de l'article, j'en ai une meilleure idée. Merci !

11voto

ircmaxell Points 74865

Ma suggestion : N'essayez pas d'apprendre les différences. Apprenez comment aborder le problème en Python. Tout comme il existe une approche Ruby pour chaque problème (qui fonctionne très bien compte tenu des limites et des forces du langage), il existe une approche Python pour le même problème. Pour tirer le meilleur parti de chaque langage, vous devez vraiment apprendre le langage lui-même, et pas seulement la "traduction" de l'un à l'autre.

Cela dit, la différence vous aidera à vous adapter plus rapidement et à apporter des modifications ponctuelles à un programme Python. Et c'est très bien pour commencer à écrire. Mais essayez d'apprendre d'autres projets le pourquoi derrière l'architecture et les décisions de conception plutôt que le comment derrière la sémantique du langage...

7 votes

J'apprécie votre suggestion. Je suis tout à fait d'accord avec le sentiment (ce que j'interprète comme "Apprendre à programmer du Python idiomatique") . C'est précisément ce que j'essaie de faire. Je ne demande pas "Quel est le nom en Python de la fonction Ruby each méthode ?" Je demande "En quoi les choses faites correctement en Python sont-elles différentes de celles faites correctement en Ruby, et en quoi sont-elles les mêmes ?". Si le programme de Python false est en fait False Il est aussi important de savoir où et quand je dois faire les choses à la manière de Ruby, et où et quand je ne dois pas les faire.

2 votes

@Phrogz : C'est juste. La façon dont j'ai interprété votre question était : Dressons une liste des différences afin de pouvoir changer le langage dans lequel nous programmons. . Mais c'est une question juste. Je suppose que j'ai juste mal interprété ce que vous demandiez. Je vais laisser ça ici pour référence, mais il sera intéressant de voir ce qu'il en ressortira d'autre...

0 votes

J'apprends python et ruby en même temps, et pour le développement d'applications web, je vois plus de similitudes que de différences.

8voto

delnan Points 52260

Je connais peu le Ruby, mais voici quelques points sur les choses que vous avez mentionnées :

  • nil la valeur indiquant l'absence de valeur serait la suivante None (notez que vous le vérifiez comme x is None o x is not None et non avec == - ou par coercition en booléen, voir le point suivant).
  • None , les nombres zero-esque ( 0 , 0.0 , 0j (nombre complexe)) et les collections vides ( [] , {} , set() la chaîne vide "" etc.) sont considérées comme fausses, tout le reste est considéré comme véridique.
  • Pour les effets secondaires, ( for -)boucle de manière explicite. Pour générer un nouveau tas de choses sans effets secondaires, utilisez les compréhensions de listes (ou leurs parents - les expressions de générateur pour les itérateurs uniques paresseux, les compréhensions de dict/set pour lesdites collections).

Concernant le bouclage : Vous avez for qui opère sur un itérable ( ! pas de comptage), et while qui fait ce que l'on attend d'elle. Le fromer est bien plus puissant, grâce à la prise en charge étendue des itérateurs. Non seulement presque tout ce qui peut être un itérateur au lieu d'une liste est un itérateur (au moins dans Python 3 - dans Python 2, vous avez les deux et le défaut est une liste, malheureusement). Il existe de nombreux outils pour travailler avec les itérateurs. zip itère un nombre quelconque d'itérables en parallèle, enumerate vous donne (index, item) (sur tout itérable, et pas seulement sur des listes), et même de trancher des itérables abrités (éventuellement grands ou infinis) ! J'ai trouvé que cela rendait beaucoup de tâches de bouclage beaucoup plus simples. Inutile de dire qu'ils s'intègrent parfaitement aux comprehensions de listes, aux expressions génératrices, etc.

2 votes

Les expressions des générateurs sont cool. Elles donnent à Python un peu des capacités d'évaluation paresseuse de langages comme Haskell.

0 votes

@Clint : Oui. Et les générateurs complets sont encore plus capables (bien qu'ils ne soient pas nécessaires pour les cas simples, qui se trouvent être la majorité).

0 votes

Pourquoi vérifiez-vous avec x is None o x is not None ? Je vérifie toujours avec x == None y x != None .

6voto

Paul Prescod Points 31

En Ruby, les variables d'instance et les méthodes ne sont absolument pas liées, sauf lorsque vous les associez explicitement avec attr_accessor ou quelque chose du genre.

En Python, les méthodes ne sont qu'une classe spéciale d'attribut : une classe exécutable.

Donc, par exemple :

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

Cette différence a de nombreuses implications, comme par exemple le fait que se référer à f.x fait référence à l'objet méthode, plutôt que de l'appeler. De plus, comme vous pouvez le voir, f.x est publique par défaut, alors qu'en Ruby, les variables d'instance sont privées par défaut.

2 votes

En fait, je dirais même plus : en Python, les méthodes ne sont qu'un type particulier d'attribut, alors qu'en Ruby, les attributs ne sont qu'un type particulier de méthode. Certains contrastes importants entre les deux langages en découlent : Les fonctions de première classe en Python et le principe d'accès uniforme en Ruby.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X