Wednesday, January 23, 2019

So a list and a tuple walk into a sum()

As a direct side effect of glom's 19.1.0 release, the authors here at PDW got to re-experience one of the more surprising behaviors of three of Python's most basic constructs:
Most experienced developers know the quickest way to combine a short list of short lists:
list_of_lists = [[1], [2], [3, 4]]
sum(list_of_lists, [])
# [1, 2, 3, 4]
Ah, nice and flat, much better.

But what happens when we throw a tuple into the mix:
list_of_seqs = [[1], [2], (3, 4)]
sum(list_of_seqs, [])
# TypeError: can only concatenate list (not "tuple") to list
This is kind of surprising! Especially when you consider this:
seq = [1, 2]
seq += (3, 4)
# [1, 2, 3, 4]
Why should sum() fail when addition succeeds?! We'll get to that.
new_list = [1, 2] + (3, 4)
# TypeError: can only concatenate list (not "tuple") to list
There's that error again!

The trick here is that Python has two addition operators. The simple "+" or "add" operator, used by sum(), and the more nuanced "+=" or "iadd" operator, add's inplace variant.

But why is ok for one addition to error and the other to succeed?

Symmetry. And maybe commutativity if you remember that math class.

"+" in Python is symmetric: A + B and B + A should always yield the same result. To do otherwise would be more surprising than any of the surprises above. list and tuple cannot be added with this operator because in a mixed-type situation, the return type would change based on ordering.

Meanwhile, "+=" is asymmetric. The left side of the statement determines the type of the return completely. A += B keeps A's type. A straightforward, Pythonic reason if there ever was one.

Going back to the start of our story, by building on operator.iadd, glom's new flatten() function avoids sum()'s error-raising behavior and works wonders on all manner of nesting iterable.

21 comments:

  1. Wow, this is new to me. Thanks for sharing it.

    ReplyDelete
  2. "+" is not very symmetric when you're adding strings... (or lists, for that matter, [1] + [2] != [2] + [1]).

    ReplyDelete
  3. >>> a=[4,6]
    >>> a += (i**2 for i in range(4))
    >>> a
    [4, 6, 0, 1, 4, 9]

    ReplyDelete
  4. Positive site, where did u come up with the information on this posting?I have read a few of the articles on your website now, and I really like your style. Thanks a million and please keep up the effective work. satta king

    ReplyDelete
  5. A round of applause for your article.Much thanks again. Really Cool. Satta king

    ReplyDelete
  6. Might as well look at itertools.chain

    ReplyDelete
  7. Such a very useful article. Very interesting to read this article. I would like to thank you for the efforts you had made for writing this awesome article.
    Data Science Course in Pune
    Data Science Training in Pune

    ReplyDelete
  8. All of these posts were incredible perfect. It would be great if you’ll post more updates.
    Data Science Course in Bangalore

    ReplyDelete
  9. These thoughts just blew my mind. I am glad you have posted this.
    Data Science Training in Bangalore

    ReplyDelete
  10. I am really enjoying reading your well written articles. It looks like you spend a lot of effort and time on your blog. I have bookmarked it and I am looking forward to reading new articles. Keep up the good work.
    Data Science Institute in Bangalore

    ReplyDelete
  11. Such a very useful article. Very interesting to read this article.I would like to thank you for the efforts you had made for writing this awesome article.
    Data Science Certification in Bangalore

    ReplyDelete
  12. Very awesome!!! When I seek for this I found this website at the top of all blogs in search engine. Oregon Business Registry

    ReplyDelete
  13. I have been searching to find a comfort or effective procedure to complete this process and I think this is the most suitable way to do it effectively. Oregon Business Registry

    ReplyDelete
  14. This is an excellent post I seen thanks to share it. It is really what I wanted to see hope in future you will continue for sharing such a excellent post.
    토토사이트

    ReplyDelete
  15. This is really very nice post you shared, i like the post, thanks for sharing.. 먹튀검증

    ReplyDelete
  16. I have a mission that I’m just now working on, and I have been at the look out for such information. 토토사이트

    ReplyDelete
  17. Suppose if someone has bet 10 rupees on a number, then if that number is opened then the user will get 10 x 90 = 900 Rupees. Similarly, users will get 1800 rupees for 20 rupees, 2700 rupees for 30 rupees, 3600 rupees for 40 rupees and 4500 rupees for 50 rupees. The user can invest as much money as he wants on one number and can play many numbers as he wants. satta 786

    ReplyDelete
  18. Super site! I am Loving it!! Will return once more, I’m taking your food additionally, Thanks. 먹튀사이트

    ReplyDelete