Je connais très bien Ruby. Je pense que j'ai peut-être besoin d'apprendre Python actuellement. Pour ceux qui connaissent les deux, quels concepts sont similaires entre les deux et qu'est-ce qui est différent?
Je recherche une liste similaire à une introduction que j'ai écrite pour Learning Lua pour les JavaScripters : des choses simples comme la signification des espaces blancs et les constructions en boucle; le nom de nil
en Python, et quelles valeurs sont considérées comme "véridiques"; est-il idiomatique d'utiliser l'équivalent de map
et each
, ou marmonne-t-il quelque chose à propos de la liste des compréhensions marmonnant la norme?
Si j'obtiens une bonne variété de réponses, je suis heureux de les regrouper dans un wiki communautaire. Ou bien vous pouvez tous vous battre et vous bercer les uns des autres pour essayer de créer la seule véritable liste complète.
Edit : Pour être clair, mon objectif est Python "approprié" et idiomatique. S'il existe un équivalent Python de inject
, mais que personne ne l'utilise car il existe un moyen meilleur / différent d'obtenir la fonctionnalité commune d'itération d'une liste et d'accumuler 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 les atteindre en Ruby, et demander quel est l'équivalent en Python.
Réponses:
Voici quelques différences clés pour moi:
Ruby a des blocs; Python ne le fait pas.
Python a des fonctions; Ruby ne le fait pas. En Python, vous pouvez prendre n'importe quelle fonction ou méthode et la transmettre à une autre fonction. Dans Ruby, tout est une méthode et les méthodes ne peuvent pas être transmises directement. Au lieu de cela, vous devez les envelopper dans Proc pour les transmettre.
Ruby et Python prennent tous deux en charge les fermetures, mais de manière différente. En Python, vous pouvez définir une fonction dans une autre fonction. La fonction interne a un accès en lecture aux variables de la fonction externe, mais pas un accès en écriture. Dans 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 portée externe.
Python a des compréhensions de liste, qui sont assez expressives. Par exemple, si vous avez une liste de nombres, vous pouvez écrire
pour obtenir une nouvelle liste des carrés de toutes les valeurs supérieures à 15. Dans Ruby, vous devez écrire ce qui suit:
Le code Ruby n'est pas aussi compact. Il n'est pas non plus aussi efficace car il convertit d'abord le tableau de 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 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 carte similaires.
Python prend en charge les tuples; Ruby ne le fait pas. Dans Ruby, vous devez utiliser des tableaux pour simuler des tuples.
Ruby prend en charge les instructions switch / case; Python ne le fait pas.
Ruby prend en charge l'expr ? val1 : val2
opérateur ternaire standard ; Python ne le fait pas.Ruby ne prend en charge qu'un seul héritage. Si vous avez besoin d'imiter l'héritage multiple, vous pouvez définir des modules et utiliser des mix-ins pour extraire les méthodes de module en classes. Python prend en charge l'héritage multiple plutôt que les mix-ins de modules.
Python prend en charge uniquement les fonctions lambda sur une seule ligne. Les blocs Ruby, qui sont une sorte de / sorte de fonctions lambda, peuvent être arbitrairement grands. Pour cette raison, le code Ruby est généralement écrit dans un style plus fonctionnel que le code Python. Par exemple, pour parcourir une liste dans Ruby, vous faites généralement
Le bloc fonctionne très bien comme une fonction transmise
collection.each
. Si vous deviez faire la même chose en Python, vous devrez définir une fonction interne nommée, puis la transmettre à la collection chaque méthode (si la liste prend en charge cette méthode):Cela ne va pas très bien. Ainsi, l'approche non fonctionnelle suivante serait généralement utilisée en Python:
Utiliser les ressources de manière sûre est assez différent entre les deux langues. Ici, le problème est que vous souhaitez allouer une ressource (ouvrir un fichier, obtenir un curseur de base de données, etc.), effectuer une opération arbitraire dessus, puis la fermer de manière sûre même si une exception se produit.
Dans Ruby, étant donné que les blocs sont si faciles à utiliser (voir # 9), vous coderiez généralement 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 maladroit puisque vous devez écrire une fonction interne nommée (voir # 9). Au lieu de cela, Python utilise une
with
instruction pour une gestion sûre des ressources. Consultez Comment nettoyer correctement un objet Python? pour plus de détails.la source
nonlocal
corrige ce problème 4. Python vous donne également des expressions génératrices (similaires aux compréhensions de liste, mais ne calculez rien tant qu'on ne vous le demande pas - pensez aux compréhensions de listes comme des expressions génératrices alimentéeslist
(qui prend un itérable et renvoie une liste contenant tout l'itérable produit) - cela peut économiser beaucoup d'efforts dans certains cas).val1 if expr else val2
. 8. Bien que je le vois principalement utilisé pour l'augmentation de style mixin.values.map{|v| v*v if v > 15}.compact
. IMHO, c'est encore plus expressif (et certainement plus clair) que votre exemple python.values.map{|v| v*v if v > 15}.compact!
. Cela signifie que seules la liste d'entrée et la liste résultante existent en mémoire. Voir le n ° 4 ici: igvita.com/2008/07/08/6-optimization-tips-for-ruby-mriJe viens de passer quelques mois à apprendre Python après 6 ans de Ruby. Il n'y avait vraiment pas de comparaison formidable pour les deux langues, alors j'ai décidé de m'en occuper et d'en écrire une moi-même. Maintenant, il s'agit principalement de programmation fonctionnelle, mais puisque vous mentionnez la
inject
méthode de Ruby , je suppose que nous sommes sur la même longueur d'onde.J'espère que cela aide: La `` laideur '' de Python
Quelques points qui vous permettront d'aller dans la bonne direction:
Tous les avantages de la programmation fonctionnelle que vous utilisez dans Ruby sont en Python, et c'est encore plus facile. Par exemple, vous pouvez mapper des fonctions exactement comme vous vous y attendez:
Python n'a pas de méthode qui agit comme
each
. Puisque vous n'utilisez queeach
pour les effets secondaires, l'équivalent en Python est la boucle for:Les compréhensions de listes sont excellentes lorsque a) vous devez gérer ensemble des fonctions et des collections d'objets et b) lorsque vous avez besoin d'itérer en utilisant plusieurs index. Par exemple, pour trouver tous les palindromes dans une chaîne (en supposant que vous ayez une fonction
p()
qui renvoie true pour les palindromes), tout ce dont vous avez besoin est une seule compréhension de liste:la source
Class.method
, la méthode est "indépendante" et le premier argument doit être uneClass
instance; lorsque vous écrivezobject.method
, la méthode est "liée" à l'object
instance deClass
. Cela vous permet de choisir d'utiliser map (etc.) pour appeler la méthode sur une instance de différence à chaque fois (passer une méthode indépendante), ou pour maintenir l'instance fixe et passer un deuxième argument différent à chaque fois. Les deux sont utiles.[s[x:y] for x in range(l) for y in range(x,l+1) if p(s[x:y])]
- cette ligne montre à quel point Python est difficile à lire. Lorsque vous lisez du code Ruby, vous déplacez vos yeux de gauche à droite, sans retour. Mais pour lire le code Python, vous devez aller gauche-droite-gauche-droite-gauche-droite ... et parenthèses, parenthèses, parenthèses, parenthèses ... Aussi en Python, vous avez souvent besoin de mélanger des méthodes et des fonctions. C'est de la folie:E(C(A.B()).D())
au lieu de Ruby'sA.B.C.D.E
Ma suggestion: n'essayez pas d'apprendre les différences. Apprenez à 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 du problème. ils sont tous les deux différents. Pour tirer le meilleur parti de chaque langue, vous devez vraiment apprendre la langue elle-même, et pas seulement la «traduction» de l'une à l'autre.
Maintenant, cela dit, la différence vous aidera à vous adapter plus rapidement et à apporter une modification à un programme Python. Et c'est bien pour commencer à écrire. Mais essayez d'apprendre des autres projets le pourquoi derrière les décisions d'architecture et de conception plutôt que le comment derrière la sémantique du langage ...
la source
each
méthode Ruby ?" Je demande "En quoi les choses sont-elles faites correctement en Python différentes de Ruby et où sont-elles faites correctement de la même manière?" Si Python l'false
est réellementFalse
, c'est aussi important de savoir que où et quand je devrais faire les choses de manière Rubyesque, et où et quand je ne devrais pas.Je connais le petit Ruby, mais voici quelques points sur les choses que vous avez mentionnées:
nil
, la valeur indiquant l'absence de valeur, seraitNone
(notez que vous la vérifiez commex is None
oux is not None
, pas avec==
- ou par coercition en booléen, voir le point suivant).None
, Le nombre zéro-esque (0
,0.0
,0j
(nombre complexe)) et des collections vides ([]
,{}
,set()
, la chaîne vide""
, etc.) sont considérés comme falsy, tout le reste est considéré comme truthy.for
boucle ( -) explicitement. Pour générer un nouveau tas de trucs sans effets secondaires, utilisez les compréhensions de liste (ou leurs parents - expressions génératrices pour les itérateurs ponctuels paresseux, compréhensions dict / set pour lesdites collections).Concernant le bouclage: Vous avez
for
, qui opère sur un itérable (! Pas de comptage), etwhile
, qui fait ce que vous attendez. Le fromer est beaucoup 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 la valeur par défaut est une liste, malheureusement). Il existe de nombreux outils pour travailler avec des itérateurs -zip
itère n'importe quel nombre d'itérables en parallèle,enumerate
vous donne(index, item)
(sur n'importe quel itérable, pas seulement sur des listes), même découpant des itérables abritaires (éventuellement grands ou infinis)! J'ai trouvé que cela simplifiait beaucoup de tâches en boucle. Inutile de dire qu'ils s'intègrent très bien avec les compréhensions de liste, les expressions génératrices, etc.la source
x is None
oux is not None
? Je vérifie toujours avecx == None
etx != None
.x
définit__eq__
de manière idiote, cela pourrait donner un faux positif. Si le__eq__
n'est pas programmé assez soigneusement, il pourrait planter (par exempleAttributeError
) lorsqu'on lui donne certaines valeurs (c'est-à-direNone
). Au contraire,is
ne peut pas être remplacé - il compare toujours l'identité de l'objet, ce qui est la bonne façon (la plus robuste, la plus simple et la plus propre) de rechercher un singleton.Dans Ruby, les variables d'instance et les méthodes sont totalement indépendantes, sauf lorsque vous les associez explicitement à attr_accessor ou quelque chose du genre.
En Python, les méthodes ne sont qu'une classe spéciale d'attributs: une classe exécutable.
Donc par exemple:
Cette différence a de nombreuses implications, comme par exemple le fait que se référer à fx fait référence à l'objet méthode, plutôt que de l'appeler. De plus, comme vous pouvez le voir, fx est public par défaut, alors que dans Ruby, les variables d'instance sont privées par défaut.
la source