125 ms·
I find the explanation lacking? sort also "changes the list in-place", but you can do ([3, 1, 2],)[0].sort()
by avip 7y ago
I find the explanation lacking? sort also "changes the list in-place", but you can do ([3, 1, 2],)[0].sort()
- Luyt 7y agoOf course you can. The first element of that tuple is a list, which is mutable, and can be sorted in-place.
- FartyMcFarter 7y agoSo the question is if += and sort are both "in-place", why does one throw and the other doesn't? Clearly "in-place" is not the full explanation here. I think the real explanation is that with += there are two steps: 1- The existing list gets modified. This is fine since lists are mutable. 2- The tuple's reference to the list gets updated (even though this update is unnecessary since the list object's identity is the same). The exception occurs at step 2, but this step is otherwise a no-op. Whether mutating a reference to the same value it already had is an actual mutation is an interesting semantics debate.
- Luyt 7y agoTuples are immutable, but that doesn't mean they can't contain references to mutable objects. When you want to use a tuple as a key in a dictionary, Python checks if all members of the tuple are immutable. If one or more of them aren't, you'll get an 'unhashable type' error.
- avip 7y agoPls read again https://github.com/satwikkansal/wtfpython#-mutating-the-immutable https://github.com/satwikkansal/wtfpython#-mutating-the-immu...
- bakery2k 7y ago`a += b` does something along the lines of `a = a.__iadd__(b)`. Here `__iadd__` performs the actual append, but then the assignment fails.
- avip 7y agoDoes it though? So why doesn't a += b change the object id id(a) ?
- bakery2k 7y agoBecause if `a` and `b` are lists, `a.__iadd__(b)` mutates `a` in place, then returns it.
- avip 7y agoRight, got it.
- masklinn 7y agoAs OP noted, given the existence of type(a).__iadd__[0] `a += b` essentially desugars to: `a = a.__iadd__(b)`. list.__iadd__ is (sadly) defined as something like def __iadd__(self, other): self.extend(other) return self So it's possible to have __iadd__ itself succeed modifying the list in place but then the "no-op" reassignment fail. [0] like many data model operations there's really a bunch of fallbacks depending on what is and is not implemented
- avip 7y agoI'd almost consider this a subtle bug? None of the other += operators returns a value.
- masklinn 7y ago> I'd almost consider this a subtle bug? It's not exactly a bug but it is a somewhat unexpected behaviour and IIRC Guido regretted that list.__iadd__ was overridden this way. > None of the other += operators returns a value. It's not the operator which returns a value, it's the data model hook. The data model requires that it return a value: https://docs.python.org/3/reference/datamodel.html?#object.__iadd__ https://docs.python.org/3/reference/datamodel.html?#object._... > These methods should attempt to do the operation in-place (modifying self) and return the result (which could be, but does not have to be, self). Really the issue is that the "in-place" hooks are simply weird.