Can anyone familiar with Python's internals (CPython, or other implementations) explain why list addition is required to be homogenous:
In [1]: x = [1] In [2]: x+"foo" --------------------------------------------------------------------------- TypeError Traceback (most recent call last) C:\Users\Marcin\<ipython-input-2-94cd84126ddc> in <module>() ----> 1 x+"foo" TypeError: can only concatenate list (not "str") to list In [3]: x+="foo" In [4]: x Out[4]: [1, 'f', 'o', 'o']
Why shouldn't the x+"foo"
above return the same value as the final value of x
in the above transcript?
This question follows on from NPE's question here: Is the behaviour of Python's list += iterable documented anywhere?
Update: I know it is not required that heterogenous +=
work (but it does) and likewise, it is not required that heterogenous +
be an error. This question is about why that latter choice was made.
It is too much to say that the results of adding a sequence to a list are uncertain. If that were a sufficient objection, it would make sense to prevent heterogenous +=
. Update2: In particular, python always delegates operator calls to the lefthand operand, so no issue "what is the right thing to do" arises": the left-hand object always governs (unless it delegates to the right).
Update3: For anyone arguing that this is a design decision, please explain (a) why it is not documented; or (b) where it is documented.
Update4: "what should [1] + (2, )
return?" It should return a result value equal with the value of a variable x
initially holding [1]
immediately after x+=(2, )
. This result is well-defined.
2. Does a list need to be homogeneous? NO, There is no need to be homogeneous because . List is used to store the collection of values.
It's not a rule, it's just a tradition. In many languages, lists must be homogenous and tuples must be fixed-length. This is true of C++, C#, Haskell, Rust, etc. Tuples are used as anonymous structures.
An ordered list object is an ordered sequence of zero or more elements of some type. If the all the elements are of the same type, it is a homogeneous ordered list, otherwise it is a heterogeneous ordered list. The array ADT can be used to implement a homogeneous ordered list ADT.
Python lists can be homogeneous, means they can contain the same type of objects; or heterogeneous, containing different types of objects. To access values within lists, the index of the objects inside the lists can be used.
From the Zen of Python:
In the face of ambiguity, refuse the temptation to guess.
Let's look at what happens here:
x + y
This gives us a value, but of what type? When we add things in real life, we expect the type to be the same as the input types, but what if they are disparate? Well, in the real world, we refuse to add 1
and "a"
, it doesn't make sense.
What if we have similar types? In the real world, we look at context. The computer can't do this, so it has to guess. Python picks the left operand and lets that decide. Your issue occurs because of this lack of context.
Say a programmer wants to do ["a"] + "bc"
- this could mean they want "abc"
or ["a", "b", "c"]
. Currently, the solution is to either call "".join()
on the first operand or list()
on the second, which allows the programmer to do what they want and is clear and explicit.
Your suggestion is for Python to guess (by having a built-in rule to pick a given operand), so the programmer can do the same thing by doing the addition - why is that better? It just means it's easier to get the wrong type by mistake, and we have to remember an arbitrary rule (left operand picks type). Instead, we get an error so we can give Python the information it needs to make the right call.
So why is +=
different? Well, that's because we are giving Python that context. With the in-place operation we are telling Python to modify a value, so we know that we are dealing with something of the type the value we are modifying is. This is the context Python needs to make the right call, so we don't need to guess.
When I talk about guessing, I'm talking about Python guessing the programmer's intent. This is something Python does a lot - see division in 3.x. /
does float division, correcting the error of it being integer division in 2.x.
This is because we are implicitly asking for float division when we try to divide. Python takes this into account and it's operations are done according to that. Likewise, it's about guessing intent here. When we add with +
our intent is unclear. When we use +=
, it is very clear.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With