Pythons Join scheint sich aus Designgründen nicht auf die zu verbindenden Elemente zu konzentrieren, sondern auf das Symbol im Vergleich zu Ruby oder Smalltalk?

9

Ich dachte, einer der Eckpfeiler von OOP ist, dass wir Objekte haben, mit denen wir uns befassen möchten, und dann senden wir ihnen Nachrichten.

Es mag also natürlich erscheinen, dass ich eine Sammlung von Gegenständen habe und sie in eine Zeichenfolge einfügen muss, um dies zu tun:

  ["x", "o", "o"].join(" | ")    # joining a tic-tac-toe row in Ruby

(Smalltalk macht es genauso). Das " | "ist in gewisser Weise ein Argument, ein Zeichen dafür, wie man sich ihm anschließt. Es kann auch sein " ", wenn das Spielbrett einfacher sein soll. Das Verbindungselement " | "ist also nicht besonders etwas, an dem wir interessiert sind - es sind nicht die Hauptobjekte im Programm, die eine besondere Bedeutung oder Bedeutung haben.

Wenn Python es mit macht

  " | ".join(["x", "o", "o"])

Es fühlt sich etwas seltsam an, dass es sich fast so anfühlt, als würden wir eine Nachricht an das Argument weitergeben, um das Argument über etwas zu erzählen. Vielleicht ist Python prozeduraler? Um der Verbindungskette zu sagen, dass sie eine Pflicht für uns erfüllen soll?

Soll die Implementierung gespeichert werden, damit wir nicht joinfür jede vorhandene Auflistungsklasse eine definieren müssen? Aber stimmt es nicht, dass wir auch nur einmal für eine Sammlungsklasse schreiben können, wie in Ruby:

module Enumerable
  def my_join(joiner)
    self.inject {|a,b| a.to_s + joiner + b.to_s}
  end
end

(so etwas, to_sjedes Element aufrufen , sich darauf verlassen, dass to_sjede Klasse ihre eigene Sache macht, in eine Zeichenfolge konvertiert und sie dann verkettet). Dann müssen wir nicht für jeden String, Hash oder Set oder für jede Auflistungsklasse, die wir haben, implementieren.

Oder geht Python nicht richtig die OOP-Route? Es verwendet len("abc")und type([])anstelle "abc".len()oder [].type()sogar in Python3 scheint es auch. Tut Python dies aus Designgründen so?

Unpolarität
quelle
7
Aus dem Zen von Python : "Es sollte einen - und vorzugsweise nur einen - offensichtlichen Weg geben, dies zu tun. Obwohl dieser Weg zunächst möglicherweise nicht offensichtlich ist, es sei denn, Sie sind Niederländer."
kdgregory
2
In einer Form weiß die Sammlung, wie sie sich in eine Zeichenfolge mit einem Trennzeichen konvertiert, in der anderen Form kann eine Zeichenfolge eine Sammlung mit sich selbst als Trennzeichen verketten. Sie sind beide objektorientiert, ändern jedoch das Subjekt und das Objekt des Verbs.
kdgregory
Maybe Python is more procedural?Python war eine prozedurale Sprache mit einigen funktionalen Ergänzungen ("Python hat Lambda, Reduce (), Filter () und Map () erworben, mit freundlicher Genehmigung eines Lisp-Hackers, der sie verpasst und funktionierende Patches eingereicht hat"), bis etwas in der Version zu sein scheint 2. Das war ungefähr anderthalb Jahrzehnte nach der ersten Bearbeitung.
1
Und selbst heute versucht Python nicht einmal, eine OOP-Sprache zu sein, sondern ist ein durch und durch multiparadig.
Python ist wie C ++ eine Sprache, die OOP ermöglicht. Dies ist nicht dasselbe wie eine OOP-Sprache wie Java oder Smalltalk.
Gort the Robot

Antworten:

9

Pythons Join ist so konzipiert, dass er mit jedem iterierbaren Element funktioniert . Dies bedeutet, dass die Designer entscheiden mussten, wo sie es platzieren möchten. Da es auf mehr als nur Listen funktioniert, aber immer erfordert (Separator) und liefert einen String, beschlossen sie , sie geben Sie einen Teil des Strings zu machen.

Armin Ronacher sagt es besser als ich:

http://lucumr.pocoo.org/2011/7/9/python-and-pola/#seemingly-inverse-logic

"Stellen Sie sich vor, Python würde nicht so funktionieren. Sie müssten das iterable zuerst in eine tatsächliche Liste konvertieren, um es in einen String zu konvertieren. Ruby-Leute werden jetzt argumentieren, dass Ruby dieses Problem mit dem Einmischen von Modulen löst, und sie sind sicher richtig, dass dies ist eine Option. Dies ist jedoch eine bewusste Entwurfsentscheidung in der Sprache, die viele Auswirkungen hat. Python fördert die lose Kopplung, indem es diese Protokolle verwendet, bei denen die tatsächlichen Implementierungen an anderer Stelle erfolgen können. Ein Objekt ist iterierbar, ein anderer Teil im System weiß, wie es zu erstellen ist in eine Schnur. "

Scant Roger
quelle
1
OP versucht, dies mit dem module EnumerateAbschnitt zu beheben, aber Python funktioniert nicht so. Es gibt keine einzige Oberklasse für alle Iteratoren, in die Sie diese Methode einfügen könnten.
Ich habe es auch in Ruby 2.0 versucht ... Hashund habe Stringeigentlich keine Sammlungsklasse als Oberklasse ... ihre Oberklasse ist gerecht Object. Diese beiden Klassen verlassen sich also nur auf das Enumerable-Mixin ... etwas, wie ich es verstehe, wie eine Schnittstelle, um die Verhaltensweisen einer Sammlung zu
berücksichtigen
Es ist also so ziemlich eine Einschränkung der Tatsache, dass "iterable" keine Klasse oder etwas mit tatsächlichem Code ist, sondern ein Enten-Tippmuster? Alternativ liegt es einfach daran, dass Python so allgemein sein wollte, dass es an jeder Sammlung mit derselben Implementierung arbeiten kann (während viele andere Standardbibliotheken sie nur für jede Sammlung implementieren würden, wenn sie tatsächlich für diese Sammlung gilt).
Kat