Ich kenne Ruby sehr gut. Ich glaube, dass ich momentan Python lernen muss. Welche Konzepte sind für beide, die beide kennen, ähnlich und welche unterschiedlich?
Ich suche nach einer Liste ähnlich einer Grundierung, die ich für Learning Lua for JavaScripters geschrieben habe : einfache Dinge wie Leerzeichenbedeutung und Schleifenkonstrukte; der Name von nil
in Python und welche Werte als "wahr" angesehen werden; Ist es idiomatisch, das Äquivalent von map
und zu verwenden each
, oder murmeln etwas über Listenverständnisse die Norm?
Wenn ich eine gute Auswahl an Antworten bekomme, fasse ich sie gerne zu einem Community-Wiki zusammen. Oder Sie können alle kämpfen und sich gegenseitig bekämpfen, um zu versuchen, eine wirklich umfassende Liste zu erstellen.
Edit : Um klar zu sein, mein Ziel ist "richtig" und idiomatisch Python. Wenn es ein Python-Äquivalent von gibt inject
, aber niemand es verwendet, weil es eine bessere / andere Möglichkeit gibt, die gemeinsame Funktionalität des Iterierens einer Liste und des Sammelns eines Ergebnisses auf dem Weg zu erreichen, möchte ich wissen, wie Sie Dinge tun. Vielleicht aktualisiere ich diese Frage mit einer Liste allgemeiner Ziele, wie Sie sie in Ruby erreichen, und frage, was das Äquivalent in Python ist.
Antworten:
Hier sind einige wichtige Unterschiede für mich:
Ruby hat Blöcke; Python nicht.
Python hat Funktionen; Ruby nicht. In Python können Sie jede Funktion oder Methode übernehmen und an eine andere Funktion übergeben. In Ruby ist alles eine Methode, und Methoden können nicht direkt übergeben werden. Stattdessen müssen Sie sie in Procs einwickeln, um sie zu übergeben.
Ruby und Python unterstützen beide Schließungen, jedoch auf unterschiedliche Weise. In Python können Sie eine Funktion in einer anderen Funktion definieren. Die innere Funktion hat Lesezugriff auf Variablen von der äußeren Funktion, jedoch keinen Schreibzugriff. In Ruby definieren Sie Verschlüsse mithilfe von Blöcken. Die Abschlüsse haben vollen Lese- und Schreibzugriff auf Variablen aus dem äußeren Bereich.
Python hat Listenverständnisse, die ziemlich ausdrucksstark sind. Wenn Sie beispielsweise eine Liste mit Zahlen haben, können Sie schreiben
Um eine neue Liste der Quadrate aller Werte größer als 15 zu erhalten, müssten Sie in Ruby Folgendes schreiben:
Der Ruby-Code fühlt sich nicht so kompakt an. Es ist auch nicht so effizient, da es zuerst das Wertearray in ein kürzeres Zwischenarray mit Werten über 15 konvertiert. Dann nimmt es das Zwischenarray und generiert ein endgültiges Array, das die Quadrate der Zwischenprodukte enthält. Das Zwischenarray wird dann verworfen. Ruby hat also während der Berechnung 3 Arrays im Speicher. Python benötigt nur die Eingabeliste und die resultierende Liste.
Python bietet auch ähnliche Kartenverständnisse.
Python unterstützt Tupel. Ruby nicht. In Ruby müssen Sie Arrays verwenden, um Tupel zu simulieren.
Ruby unterstützt switch / case-Anweisungen. Python nicht.
Ruby unterstützt denexpr ? val1 : val2
ternären Standardoperator . Python nicht.Ruby unterstützt nur eine einzelne Vererbung. Wenn Sie die Mehrfachvererbung nachahmen müssen, können Sie Module definieren und Mix-Ins verwenden, um die Modulmethoden in Klassen zu ziehen. Python unterstützt Mehrfachvererbung anstelle von Modul-Mix-Ins.
Python unterstützt nur einzeilige Lambda-Funktionen. Ruby-Blöcke, die eine Art Lambda-Funktion sind, können beliebig groß sein. Aus diesem Grund wird Ruby-Code normalerweise funktionaler geschrieben als Python-Code. Um beispielsweise eine Liste in Ruby zu durchlaufen, tun Sie dies normalerweise
Der Block funktioniert sehr ähnlich wie eine Funktion, an die übergeben wird
collection.each
. Wenn Sie dasselbe in Python tun würden, müssten Sie eine benannte innere Funktion definieren und diese dann jeder Methode an die Sammlung übergeben (wenn list diese Methode unterstützt):Das fließt nicht sehr gut. Daher wird in Python normalerweise der folgende nicht funktionale Ansatz verwendet:
Der sichere Umgang mit Ressourcen unterscheidet sich zwischen den beiden Sprachen erheblich. Hier besteht das Problem darin, dass Sie eine Ressource zuweisen möchten (eine Datei öffnen, einen Datenbankcursor erhalten usw.), eine beliebige Operation ausführen und sie dann auf sichere Weise schließen möchten, selbst wenn eine Ausnahme auftritt.
In Ruby codieren Sie dieses Muster normalerweise als Methode, die einen Block benötigt, damit die beliebige Operation für die Ressource ausgeführt werden kann, da Blöcke so einfach zu verwenden sind (siehe Nr. 9).
In Python ist die Übergabe einer Funktion für die beliebige Aktion etwas umständlicher, da Sie eine benannte innere Funktion schreiben müssen (siehe Nr. 9). Stattdessen verwendet Python eine
with
Anweisung zur sicheren Handhabung von Ressourcen. Siehe Wie bereinige ich ein Python-Objekt korrekt? für mehr Details.quelle
nonlocal
behebt dieses Problem. 4. Python bietet Ihnen auch Generatorausdrücke (ähnlich wie Listenverständnisse, berechnet jedoch nichts, bis Sie dazu aufgefordert werden. Stellen Sie sich Listenverständnisse als Generatorausdrücke vor, die eingespeist werdenlist
(die eine Iterierbarkeit annehmen und eine Liste mit allem zurückgeben) das iterable ergab) - dies kann in einigen Fällen viel Aufwand sparen).val1 if expr else val2
. 8. Obwohl ich sehe, dass es hauptsächlich für die Augmentation im Mixin-Stil verwendet wird.values.map{|v| v*v if v > 15}.compact
. IMHO, das ist noch ausdrucksvoller (und sicherlich klarer) als Ihr Python-Beispiel.values.map{|v| v*v if v > 15}.compact!
. Dies bedeutet, dass nur die Eingabeliste und die resultierende Liste im Speicher vorhanden sind. Siehe # 4 hier: igvita.com/2008/07/08/6-optimization-tips-for-ruby-mriIch habe gerade ein paar Monate damit verbracht, Python nach 6 Jahren Ruby zu lernen. Es gab wirklich keinen großartigen Vergleich für die beiden Sprachen, also beschloss ich, selbst eine zu schreiben. Nun, es ist in erster Linie mit der funktionalen Programmierung betrifft, aber da Sie Rubys erwähnen
inject
Methode, ich vermute , wir auf der gleichen Wellenlänge sind.Ich hoffe das hilft: Die 'Hässlichkeit' von Python
Ein paar Punkte, die Sie in die richtige Richtung bringen:
Die gesamte funktionale Programmiergüte, die Sie in Ruby verwenden, ist in Python und noch einfacher. Beispielsweise können Sie Funktionen genau so zuordnen, wie Sie es erwarten:
Python hat keine Methode, die sich so verhält
each
. Da Sie nureach
für Nebenwirkungen verwenden, ist das Äquivalent in Python die for-Schleife:Das Listenverständnis ist großartig, wenn a) Sie Funktionen und Objektsammlungen gemeinsam bearbeiten müssen und b) wenn Sie mehrere Indizes verwenden müssen. Um beispielsweise alle Palindrome in einer Zeichenfolge zu finden (vorausgesetzt, Sie haben eine Funktion
p()
, die für Palindrome true zurückgibt), benötigen Sie lediglich ein einziges Listenverständnis:quelle
Class.method
, ist die Methode "ungebunden" und das erste Argument sollte eineClass
Instanz sein. Wenn Sie schreibenobject.method
, ist die Methode an dieobject
Instanz von "gebunden"Class
. Auf diese Weise können Sie auswählen, ob Sie map (usw.) verwenden möchten, um die Methode jedes Mal für eine Differenzinstanz aufzurufen (eine ungebundene Methode zu übergeben) oder die Instanz fest zu halten und jedes Mal ein anderes zweites Argument zu übergeben. Beides ist nützlich.[s[x:y] for x in range(l) for y in range(x,l+1) if p(s[x:y])]
- Diese Zeile zeigt, wie schwer Python zum Lesen ist. Wenn Sie Ruby-Code lesen, bewegen Sie Ihre Augen von links nach rechts, ohne zurückzukehren. Aber um Python-Code zu lesen, müssen Sie links-rechts-links-rechts-links-rechts ... und Klammern, Klammern, Klammern, Klammern ... gehen. Auch in Python müssen Sie häufig Methoden und Funktionen mischen. Es ist Wahnsinn:E(C(A.B()).D())
anstelle von Ruby'sA.B.C.D.E
Mein Vorschlag: Versuchen Sie nicht, die Unterschiede zu lernen. Erfahren Sie, wie Sie das Problem in Python angehen. Genauso wie es für jedes Problem einen Ruby-Ansatz gibt (der angesichts der Einschränkungen und Stärken der Sprache sehr gut funktioniert), gibt es für das Problem einen Python-Ansatz. sie sind beide unterschiedlich. Um das Beste aus jeder Sprache herauszuholen, sollten Sie wirklich die Sprache selbst lernen und nicht nur die "Übersetzung" von einer zur anderen.
Nachdem dies gesagt wurde, hilft Ihnen der Unterschied dabei, sich schneller anzupassen und einmalige Änderungen an einem Python-Programm vorzunehmen. Und das ist gut für den Anfang, um mit dem Schreiben zu beginnen. Aber versuchen Sie aus anderen Projekten das Warum hinter den Architektur- und Designentscheidungen zu lernen und nicht das Wie hinter der Semantik der Sprache ...
quelle
each
Methode?" Ich frage: "Wie werden die Dinge in Python anders gemacht als in Ruby und wo werden sie gleich richtig gemacht?" Wenn Pythonfalse
tatsächlichFalse
ist, ist es genauso wichtig zu wissen, wo und wann ich Dinge auf Rubyesque-Weise tun sollte und wo und wann ich es nicht tun sollte.Ich kenne den kleinen Ruby, aber hier sind ein paar Punkte zu den Dingen, die Sie erwähnt haben:
nil
Der Wert, der auf das Fehlen eines Werts hinweist, wäreNone
(beachten Sie, dass Sie ihn wiex is None
oderx is not None
nicht mit==
- oder durch Zwang zum Booleschen Wert prüfen , siehe nächster Punkt).None
Null-artige Zahlen (0
,0.0
,0j
(komplexe Zahl)) und leere Sammlungen ([]
,{}
,set()
, die leere Zeichenfolge""
, etc.) sind falsy, alles andere gilt als truthy.for
Schleife ( -) explizit wiederholt. Verwenden Sie zum Generieren eines neuen Bündels von Dingen ohne Nebenwirkungen Listenverständnisse (oder deren Verwandte - Generatorausdrücke für faule einmalige Iteratoren, Diktat- / Satzverständnisse für diese Sammlungen).In Bezug auf Schleifen: Sie haben
for
, die auf einer iterierbaren (! Keine Zählung) arbeitet, undwhile
die tut, was Sie erwarten würden. Der Fromer ist dank der umfassenden Unterstützung für Iteratoren weitaus leistungsfähiger. Nicht nur fast alles, was ein Iterator anstelle einer Liste sein kann, ist ein Iterator (zumindest in Python 3 - in Python 2 haben Sie beides und der Standard ist leider eine Liste). Es gibt zahlreiche Tools für die Arbeit mit Iteratoren -zip
iteriert eine beliebige Anzahl von Iterablen parallel,enumerate
gibt Ihnen(index, item)
(auf jedem Iterierbaren, nicht nur auf Listen) sogar das Schneiden von abritären (möglicherweise großen oder unendlichen) Iterablen! Ich fand, dass dies viele, viele Schleifenaufgaben viel einfacher macht. Unnötig zu erwähnen, dass sie sich gut in Listenverständnisse, Generatorausdrücke usw. integrieren lassen.quelle
x is None
oderx is not None
? Ich überprüfe immer mitx == None
undx != None
.x
definiert__eq__
in eine dumme Art und Weise, es könnte ein falsch positives geben. Wenn das__eq__
nicht sorgfältig genug programmiert ist, kann es abstürzen (z. B.AttributeError
), wenn bestimmte Werte angegeben werden (z. B.None
). Im Gegenteil,is
kann nicht überschrieben werden - es vergleicht immer die Objektidentität. Dies ist die richtige (robusteste, einfachste und sauberste) Methode, um nach einem Singleton zu suchen.In Ruby sind Instanzvariablen und -methoden völlig unabhängig voneinander, es sei denn, Sie verknüpfen sie explizit mit attr_accessor oder ähnlichem.
In Python sind Methoden nur eine spezielle Attributklasse: eine, die ausführbar ist.
Also zum Beispiel:
Dieser Unterschied hat viele Auswirkungen, wie zum Beispiel, dass sich das Verweisen auf fx auf das Methodenobjekt bezieht, anstatt es aufzurufen. Wie Sie sehen, ist fx standardmäßig öffentlich, während in Ruby Instanzvariablen standardmäßig privat sind.
quelle