Reputation: 24811
Usually while writing code, I tend to make mistakes with some function as those functions signatures dont follow my intuition. Or more appropriately my intuition do not follow the design thinking behind these functions. I always wondered if python APIs have some inconsistencies.
For example, in python, we have:
>>> ','.join(['1','2','3'])
'1,2,3'
>>> '1,2,3'.split(',')
['1', '2', '3']
Many times I find myself doing:
['1','2','3'].join(',')
and some times (/ very rarely):
','.split('1,2,3')
Similarly I find this somewhat frustrating:
>>> sorted([1,2,3])
[1, 2, 3]
>>> reversed([1,2,3])
<list_reverseiterator object at 0x000002008932A95
That is, one list function returns list, while other returns an iterator. To save me some time (usually in timed coding competition), I usually end up doing extra list()
:
>>> list(reversed([1,2,3]))
[3, 2, 1]
>>> list(sorted([1,2,3]))
[1, 2, 3]
I believe there must be some API design standards or technical considerations behind these and am unaware of them. Can someone please share their understanding regarding these, so that it will become part of my intuition and I will do less mistakes. Or is it just the coding practice that will help me make less mistakes? Also, these are just couple of the things that I can recall now, which I usually make mistakes at. Can you share similar API confusions and intuitions behind them that you face (if you face them at all)?
Upvotes: 2
Views: 58
Reputation: 522519
You need to understand the reasoning behind each one.
','.join(['1','2','3'])
Any iterable can be joined by a string. Not just lists. If you'd design it like [...].join(',')
, each possible iterable would need to implement its own join
method. You'd need list.join
, tuple.join
, dict.join
etc. Your own classes would all need to implement their own join
method.
Thus is makes more sense for join
to be a method of str
which accepts any arbitrary iterable.
'1,2,3'.split(',')
Conversely, it only makes sense to split a string, so split
is a method on str
. You may be able to split other types as well, but how that works would differ per type, so it makes sense for each type to define its own split
method as makes sense.
sorted([1,2,3])
You must treat the entire list as a whole in order to sort it, all the list contents get shuffled around inside it during the sort operation. So you get a list as return value, as the operation intrinsically produces one anyway.
reversed([1,2,3])
Conversely, you do not need to produce a complete reversed copy of the list in memory in order to reverse it; you can just go through it one item at a time. Often you want to iterate over a collection in the reverse order, not store a reversed collection. So to make it efficient and save memory, it returns an efficient iterator which allows you to do this, instead of forcing you to double your memory usage. If you need to store this as a reversed list, you can do it yourself with list(reversed(...))
.
Upvotes: 1