9

I thought one of the cornerstone of OOP is that, we have objects, which are the items we are interested in dealing with, and then we send messages to them.

So it may seem natural that, I have a collection of items, and I need to put them into one string, so to do it:

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

(Smalltalk does it the same way). The " | " is in some way thought of as an argument, one token of how to join it. It can be " " too, if the game board is to be simpler. So the joining element " | " is not particularly something we have interest in -- it is not the main objects in the program that have particular importance or significance.

If Python does it using

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

It does feel somewhat strange that it almost feels like we are passing a message to the argument, to tell the argument about something. Maybe Python is more procedural? To tell the joining string to perform some duty for us?

Is it to save implementation, so that we don't have to define a join for each collection class we have? But isn't it true that we can also just write once for any collection class, such as in Ruby:

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

(something like this, calling to_s on each item, relying on the to_s of each class to do its own proper thing, to convert to a string, and then concatenating them). So then we don't have to implement for each of String, Hash, or Set, or whatever collection class we have.

Or does Python out right doesn't go the OOP route? It uses len("abc") and type([]) instead of "abc".len() or [].type() even in Python3 too it seems. Does Python do it this way for a design reason?

  • 7
    From The Zen of Python: "There should be one-- and preferably only one --obvious way to do it. Although that way may not be obvious at first unless you're Dutch." – kdgregory Dec 27 '15 at 18:20
  • 2
    In one form, the collection knows how to convert itself to a string with a delimiter, in the other a string knows how to concatenate a collection using itself as a delimiter. They're both object-oriented, but change the subject and object of the verb. – kdgregory Dec 27 '15 at 18:21
  • Maybe Python is more procedural? Python was a procedural language with a few functional additions ("Python acquired lambda, reduce(), filter() and map(), courtesy of a Lisp hacker who missed them and submitted working patches") until what appears to be somewhere in version 2. That was about a decade and a half after it was first worked on. – user40980 Dec 27 '15 at 19:39
  • 1
    And even today Python is not even trying to be an OOP language, it's thoroughly multi-paradigm. – user7043 Dec 27 '15 at 21:30
  • Like C++, Python is a language that allows OOP. This is not the same as an OOP language like Java or Smalltalk. – Steven Burnap Dec 27 '15 at 21:48
9

Python's join is designed to work on any iterable. This means the designers had to decide where to put it. Since it works on more than just lists, but always requires(separator) and returns a string, they decided to make it part of the string type.

Armin Ronacher says it better than me:

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

"Imagine Python would not work that way. You would have to convert the iterable into an actual list first to convert it into a string. Ruby people will now argue that Ruby solves this problem with mixing in modules, and they are certainly correct that this is an option. But this is a concious design decision in the language which has many implications. Python encourages loose coupling by having these protocols where the actual implementations can be elsewhere. One object is iterable, another part in the system knows how to make it into a string."

  • 1
    OP sort of tries to address this with the module Enumerate section but Python does not work that way, there is no single superclass for all iterators where you could put this method. – user7043 Dec 27 '15 at 21:29
  • I tried in Ruby 2.0 too... Hash and String actually don't have a collection class as a superclass... their superclass are just Object. So these two class just rely on having the Enumerable mixin... something as I understand like an interface to allow for the set of behaviors of a collection – 太極者無極而生 Dec 27 '15 at 23:02
  • So it's pretty much a limitation of the fact that "iterable" isn't a class or something with actual code, but rather a duck typing pattern? Alternatively, it's simply because Python wanted to be so general as to be able to work on any collection with the same implementation (whereas many other standard libraries would just implement it for each collection if it actually applies to that collection). – Kat Jan 4 '16 at 17:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.