Sick Gaming
[Tut] string.join(list) vs list.join(string) | Why Python’s Creators Chose The Former - Printable Version

+- Sick Gaming (https://www.sickgaming.net)
+-- Forum: Programming (https://www.sickgaming.net/forum-76.html)
+--- Forum: Python (https://www.sickgaming.net/forum-83.html)
+--- Thread: [Tut] string.join(list) vs list.join(string) | Why Python’s Creators Chose The Former (/thread-95776.html)



[Tut] string.join(list) vs list.join(string) | Why Python’s Creators Chose The Former - xSicKxBot - 06-19-2020

string.join(list) vs list.join(string) | Why Python’s Creators Chose The Former

<div><p>If you’re like me, you may have asked yourself the following question:</p>
<p><strong>Why is it <code>string.join(list)</code> instead of <code>list.join(string)</code> in Python?</strong> <img src="https://s.w.org/images/core/emoji/12.0.0-1/72x72/1f644.png" alt="?" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio">
<div class="wp-block-embed__wrapper">
<div class="ast-oembed-container"><iframe title="string.join(list) vs list.join(string) | Why Python’s Creators Chose The Former" width="1400" height="788" src="https://www.youtube.com/embed/-lQlWVPOqBY?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>
</div>
</figure>
<p class="has-background has-luminous-vivid-amber-background-color"><strong>The join method works with any iterable, not just with lists. Therefore, you’d have to implement it in hundreds of classes instead of just one (in the string class). Additionally, join() works only on a string delimiter and with an iterable of strings. Thus, it’s specific to strings and shouldn’t be allowed to be applied on, say, a list of integers.</strong></p>
<p>Let’s divide the world into REALITY and FANTASY.</p>
<p><strong>REALITY</strong>: You probably know the <code><a rel="noreferrer noopener" href="https://blog.finxter.com/python-join-list/" target="_blank">string.join(list)</a></code> method in Python to concatenate all strings in the <code>list</code> using <code>string</code> as a delimiter:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># REALITY:
lst = ['a', 'b', 'c']
print('-'.join(lst))
# a-b-c</pre>
<p><strong>FANTASY</strong>: Many coders find this confusing, wouldn’t it be more intuitive to use <code>list.join(string)</code> rather than <code>string.join(list)</code>?</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># FANTASY WORLD:
lst = ['a', 'b', 'c']
print(lst.join('-'))
# a-b-c</pre>
<p>This option of joining a list to a string would feel more object-oriented:<em> you want to join the list and not the string, after all!</em> </p>
<p>So, what are the thought processes behind <a rel="noreferrer noopener" href="https://blog.finxter.com/about-guidos-fate-of-reduce-in-python-3000/" target="_blank">Python’s creators</a>? Why did they decide to create a <code>join()</code> method on the string rather than the <a rel="noreferrer noopener" href="https://blog.finxter.com/python-lists/" target="_blank">list </a>type?</p>
<p>In this article, I’ve compiled the pro and con arguments from various sources. You can find a detailed list of the sources below.</p>
<h2>Argument 1: One Method to Join ‘Em All</h2>
<p>You can join any iterable such as a <a href="https://blog.finxter.com/python-list-methods/" target="_blank" rel="noreferrer noopener">list</a>, <a href="https://blog.finxter.com/convert-tuple-to-list/" target="_blank" rel="noreferrer noopener">tuple</a>, <a href="https://blog.finxter.com/python-dictionary/" target="_blank" rel="noreferrer noopener">dictionary</a>, or <a href="https://blog.finxter.com/sets-in-python/" target="_blank" rel="noreferrer noopener">set</a>. But the delimiter must be a string. Thus, you have two options:</p>
<ul>
<li>Require that <strong>each iterable implements its own join</strong> method (such as <code><a href="https://blog.finxter.com/underscore-in-python/">__str__</a></code>).</li>
<li>Implement <strong>only one join method</strong> that works on each iterable.</li>
</ul>
<p>The latter is far less work for the language creators, and less confusing for the <a href="https://blog.finxter.com/python-crash-course/" target="_blank" rel="noreferrer noopener">programmer</a>.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># FANTASY WORLD:
['a', 'b', 'c'].join('-')
('a', 'b', 'c').join('-')
{'a', 'b', 'c'}.join('-')
...
# a-b-c</pre>
<p>In the fantasy world, you have many implementations of basically the same method.</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># FANTASY WORLD:
['a', 'b', 'c'].join('-')
('a', 'b', 'c').join('-')
{'a', 'b', 'c'}.join('-')
...
# a-b-c</pre>
<p>This would be confusing as every single iterable must implement the same method. Either there would be a lot of <a href="https://blog.finxter.com/python-profilers-how-to-speed-up-your-python-app/" target="_blank" rel="noreferrer noopener">redundant code</a>, or the method must be implemented on the iterable object which leads us to the next argument:</p>
<h2>Argument 2: Explicit is Better Than Implicit</h2>
<p>If you type into your Python shell the two words <code>import this</code>, it’ll print the “Zen of Python”:</p>
<pre class="wp-block-preformatted">The Zen of Python, by Tim Peters
Beautiful is better than ugly.
<strong>Explicit is better than implicit.</strong>
...</pre>
<p>Go ahead and try it yourself, I’ll wait:</p>
<p> <iframe src="https://trinket.io/embed/python/a2f95994ff" marginwidth="0" marginheight="0" allowfullscreen="" width="100%" height="356" frameborder="0"></iframe> </p>
<p>The <code>join()</code> method can only join iterables if they contain strings:</p>
<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">lst = [1, 'b', 'c']
print('-'.join(lst))
# TypeError: sequence item 0: expected str instance, int found</pre>
<p>Python will throw a <code>TypeError</code>, if you try to join an iterable that contains at least one non-string element.</p>
<p>Say, we live in FANTASY WORLD and the <code>iterable</code> type implements a join method that’s valid (among others) for all container types such as lists. This would be the only alternative that makes sense and doesn’t add lots of redundant code to the Python library.</p>
<p>This would mean that all iterables containing arbitrary elements could be joined to a string! Even if the elements in the iterable are not of type string. Even if they are absurd data types you created just to confuse Python. </p>
<p>You may ask: so what? But the problem is that Python would have to use an implicit string conversion scheme in case the objects are not of type string. The default string representation is often unreadable or not suitable to appear in a <a href="https://blog.finxter.com/python-list-concatenation-add-vs-inplace-add-vs-extend/" target="_blank" rel="noreferrer noopener">concatenation</a>. Surely, this would add lots and lots of confusion. </p>
<p><strong>For example</strong>: what does it, semantically, mean to join a list of integers? Adding them? Concatenating the string representations? Averaging them? There’s no clear answer and any implicit choice would lead to confusion. <a href="https://pythononeliners.com/" target="_blank" rel="noreferrer noopener">Explicit is better than implicit!</a></p>
<p><em><strong>Note</strong>: There’s another problem with implementing a join method on the iterable level! The <code>iterable</code> is not a type but an interface for any type that defines an <code>__iter__</code> method. Thus, it comes back to requiring all iterables to implement their custom <code>join</code> which is complicated and messy.</em></p>
<h2>Argument 3: Unexpected Dependency of Iterables From String and Unicode</h2>
<p>Using <code>list.join()</code> was actually <a href="https://mail.python.org/pipermail/python-dev/1999-June/095376.html" target="_blank" rel="noreferrer noopener">proposed </a>by <strong>Skip</strong> <strong>Montanaro</strong>, one of Python’s creators:</p>
<pre class="wp-block-preformatted">On Fri, 11 Jun 1999, <strong>Skip Montanaro</strong> wrote: It occurred to me just a few minutes after sending my previous message that
it might make sense to make string.join a method for lists and tuples.
They'd obviously have to make the same type checks that string.join does.
as in:
['spam!', 'eggs!'].join() 'spam! eggs!'
?</pre>
<p>But David replied that he didn’t like the implications from the generalization of <code>join()</code>: the <code><a href="https://blog.finxter.com/the-reduce-function-is-dead-long-live-the-reduce-function/">reduce()</a></code> function:</p>
<pre class="wp-block-preformatted">I like the notion, but I think it would naturally migrate towards
genericity, at which point it might be called "reduce", so that: ['spam!', 'eggs!'].reduce() 'spam!eggs!' ['spam!', 'eggs!'].reduce(' ') 'spam! eggs!' [1,2,3].reduce()
6 # 1 + 2 + 3 [1,2,3].reduce(10)
26 # 1 + 10 + 2 + 10 + 3 note that string.join(foo) == foo.reduce(' ')
and string.join(foo, '') == foo.reduce()
--david</pre>
<p>You can see that this leads to unclear semantics if you have a list of integers. Do we reduce a list of integers by <a href="https://blog.finxter.com/python-sum-list/" target="_blank" rel="noreferrer noopener">summing </a>them up or concatenating them? What if you pass the value 10 as a separator? </p>
<p>Guido, Python’s benevolent dictator for life, replied (highlights by me):</p>
<pre class="wp-block-preformatted">&gt;&gt;&gt; On Fri, 11 Jun 1999, Skip Montanaro wrote:
&gt;&gt;&gt; It occurred to me just a few minutes after sending my previous message that
&gt;&gt;&gt; it might make sense to make string.join a method for lists and tuples.
&gt;&gt;&gt; They'd obviously have to make the same type checks that string.join does.
&gt;&gt;&gt; as in:
&gt;&gt;&gt; ['spam!', 'eggs!'].join()
&gt;&gt;&gt; 'spam! eggs!' <strong>Note that this is not as powerful as string.join(); the latter works
on any sequence, not just on lists and tuples.</strong> (Though that may not
be a big deal.) <strong>I also find it slightly objectionable that this is a general list
method but only works if the list contains only strings</strong>; Dave Ascher's
generalization to reduce() is cute but strikes me are more general
than useful, and the name will forever present a mystery to most
newcomers. <strong>Perhaps join() ought to be a built-in function?</strong>
--Guido van Rossum (home page: http://www.python.org/~guido/)</pre>
<p>To summarize this conversation, Guido had two counter arguments:</p>
<ul>
<li>The <code>join()</code> method works on all iterables and not only on lists and tuples.</li>
<li>The method must be a general list method but works only if the list contains strings.</li>
</ul>
<p>The final note is interesting though: <code>join()</code> could have been built-in function, too!</p>
<h2>Where to Go From Here?</h2>
<p>Enough theory, let’s get some practice!</p>
<p>To become successful in coding, you need to get out there and solve real problems for real people. That’s how you can become a six-figure earner easily. And that’s how you polish the skills you really need in practice. After all, what’s the use of learning theory that nobody ever needs?</p>
<p><strong>Practice projects is how you sharpen your saw in coding!</strong></p>
<p>Do you want to become a code master by focusing on practical code projects that actually earn you money and solve problems for people?</p>
<p>Then become a Python freelance developer! It’s the best way of approaching the task of improving your Python skills—even if you are a complete beginner.</p>
<p>Join my free webinar <a rel="noreferrer noopener" href="https://blog.finxter.com/webinar-freelancer/" target="_blank">“How to Build Your High-Income Skill Python”</a> and watch how I grew my coding business online and how you can, too—from the comfort of your own home.</p>
<p><a href="https://blog.finxter.com/webinar-freelancer/" target="_blank" rel="noreferrer noopener">Join the free webinar now!</a></p>
<h2>Sources</h2>
<p>I combined web resources, email communications, and my own thoughts to write this comprehensive guide. I’m confident that the tutorial covers the real sources—but we’ll never know for 100%, don’t we?</p>
<ol>
<li><a rel="noreferrer noopener" href="https://stackoverflow.com/questions/493819/why-is-it-string-joinlist-instead-of-list-joinstring" target="_blank">https://stackoverflow.com/questions/493819/why-is-it-string-joinlist-instead-of-list-joinstring</a></li>
<li><a rel="noreferrer noopener" href="https://www.edureka.co/community/3899/python-join-why-is-string-join-list-instead-list-join-string" target="_blank">https://www.edureka.co/community/3899/python-join-why-is-string-join-list-instead-list-join-string</a></li>
<li><a rel="noreferrer noopener" href="https://www.edureka.co/community/12487/python-join-why-is-string-join-list-instead-list-join-string" target="_blank">https://www.edureka.co/community/12487/python-join-why-is-string-join-list-instead-list-join-string</a></li>
<li><a rel="noreferrer noopener" href="https://intellipaat.com/community/225/python-join-why-is-it-string-join-list-instead-of-list-join-string" target="_blank">https://intellipaat.com/community/225/python-join-why-is-it-string-join-list-instead-of-list-join-string</a></li>
<li><a rel="noreferrer noopener" href="https://www.wyzant.com/resources/answers/689501/python-join-why-is-it-string-join-list-instead-of-list-join-string" target="_blank">https://www.wyzant.com/resources/answers/689501/python-join-why-is-it-string-join-list-instead-of-list-join-string</a></li>
<li><a rel="noreferrer noopener" href="https://www.quora.com/Why-is-it-string-join-list-instead-of-list-join-string" target="_blank">https://www.quora.com/Why-is-it-string-join-list-instead-of-list-join-string</a></li>
<li><a href="https://mail.python.org/pipermail/python-dev/1999-June/095366.html" target="_blank" rel="noreferrer noopener">https://mail.python.org/pipermail/python-dev/1999-June/095366.html</a></li>
</ol>
</div>


https://www.sickgaming.net/blog/2020/06/18/string-joinlist-vs-list-joinstring-why-pythons-creators-chose-the-former/