Thought on PEP 204 and 276

Stephen Horne steve at lurking.demon.co.uk
Tue Jun 4 19:50:13 EDT 2002


On Tue, 4 Jun 2002 16:57:00 -0400, "Steve Holden"
<sholden at holdenweb.com> wrote:

>"Stephen Horne" <steve at lurking.demon.co.uk> wrote ...
>> On Tue, 4 Jun 2002 10:49:19 -0400, "Steve Holden"
>> <sholden at holdenweb.com> wrote:
>>
>> >"phil hunt" <philh at comuno.freeserve.co.uk> wrote in message
>> >news:slrnaf7mo4.dfe.philh at comuno.freeserve.co.uk...
>>
>> >> I think they are essentially the same. A sequence tpye is just a
>> >> mapping type where the keys are restricted to the integers from
>> >> 0 to however many elements there are minus 1.
>> >>
>> >No matter what you think, they are essentially different. Insertion into
>a
>> >mapping doesn't alter the key to which other elements are mapped, but
>> >insertion into a sequence (potentially) does that.
>>
>> What is normally referred to as insertion in dictionaries is actually
>> more like overwriting a list element. This is why handling both with
>> the 'container [key] = value' syntax is natural.
>>
>aarrgghh. So we can completely ignore the fact that the len() of a
>dictionary will change after an insertion while the len() of a list won't
>after an element is overwritten?

a = {0 : 5}
a [0] = 6
len(a) == 1

a = [5]
a[0] = 6
len(a) == 1

len(a) is unchanged - whether a is a dictionary or a list, an
overwrite is not going to change the length. The special behaviour is
the [] cannot create a new item in a list and therefore raises an
exception, whereas it can create a new item in a dictionary so does.
Nothing that inheritance and overriding cannot handle.

Please compare like with like, and therefore consider what you really
mean by 'insert'.

If you are genuinely creating a new key in the dictionary, the nearest
equivalent for a list is the append() method which creates a new item
without disturbing other items key->value mappings. It is restricted
in the items it can create (the key must be equal to the previous
length of the list) but that is fine - the list is a more specialist
container and should fail if other keys are added. It is only a shame
that 'x[len(x)] = y' is invalid, as this would be a valid list
insertion in the same way that [] for any key on dictionaries is.

>> Insertion with modification of existing keys to make room (ie list
>> insertion) simply does not exist in lists. The usefulness of list
>> insertion derives from the fact that a list is a very specialised type
>> of key-to-value mapping - in this respect, the type 'list' should
>> clearly inheret from and extend the more general key-to-value type
>> called a dictionary.
>>
>It might be clear to you. It certainly isn't to me. I believe you are
>looking to unify two fundamentally different semantics.

They are not fundamentally different semantics - they are both
semantically key-to-value mapping containers and one is semantically a
specialised form of the other. Only the implementation is
fundamentally distinct.

>Neither does it make sense in implementation terms. List insertion's
>usefulness is in fact limited to situations where performance isn't unduly
>degraded by the need to modify the representation too radically. Of course,
>where performance doesn't matter, it doesn't matter.

Of course the usefulness of particular operations on certain types
depends on the implementation of those types. That does not make the
operations fundamentally different, though.

Incidentally, if an insert was applied to a dictionary which is
actually semantically equivalent to the list insert, it would be much
slower as each item to move would need to be removed, it's key
incremented and rehashed, and then the item re-inserted into the
dictionary. That is comparing like with like - fundamentally the same
semantics rather than just the same name.

Such an operation would be absurd so is reserved for the more
specialist list.

>> In essence, you are confusing the operations on the underlying data
>> structures with the operations on the conceptual types. These are two
>> separate concepts. The implementation is distinct from the
>> user-visible abstraction.
>>
>Fine. You write your programs to delete lists element-by-element from the
>front, and don't complain about performance -- that's just an aspect of the
>implementation.

Of course I don't do that. I am perfectly aware of performance issues,
just as you apparently are. However, your argument was that these
types are 'fundamentally different' and I don't believe they are.

>While I admire your attempt to maintain theoretical purity here, Python is a
>pragmatist's language. I don't think I'll be bothering to conceptualise
>dictionary insertion as overwriting a non-existent element, thank you very
>much.

The origin of this thread was the idea of supporting the items()
method for lists in the same way as it is for dictionaries instead of
adding an enumerate function. There is no relative performance hit
whichever notation is used. Being consistent in how key-to-value
mapping types represent their functionality has no performance cost at
all.

If there was a performance hit in what I was suggesting, I'd say that
pragmatics were in your favor. Without that performance hit, perhaps
pragmatics may have more to do with the learning curve.

Someone who has written something like...

  for key, value in l_Dict.items () :

might well try to do the same for a list. Why have two ways to do the
same thing? - apparently, because the implementation of the types
within the interpreter is different. Or perhaps because there are
differences in other operations which have nothing to do with this.

I really don't think that theoretical purity and pragmatics are in
conflict at all. There is no performance issue, but there is a
learning curve issue as two key-to-value mapping containers each have
different syntax to achieve exactly the same objective - despite the
fact that for many other operations (with fundamentally different
implementations) on these types, the syntax IS consist. This
inconsistency serves no pragmatic purpose whatsoever.

Funny thing though - integers and long integers are being unified
DESPITE the performance hit. Pragmatics and performance would suggest
that basic integers should be allowed to just overflow - it should be
the programmers responsibility to ensure it doesn't happen, just as in
many other languages. Maybe sometimes theoretical purity overrides
pragmatics - but that isn't the case in my argument.

Personally, I'm sticking with the argument from much earlier in this
thread (that list.items () intuitively suggests it returns the list
itself) as still the most convincing - though that just suggests to me
that there might be a better name which could be used for the
operation on both lists and dictionaries. Perhaps list.mappings() and
key.mappings(), which to me intuitively suggests that it returns a
list of key-to-value mappings exactly as intended.




More information about the Python-list mailing list