My point is that the docs list and describe it as a method that only exists for
MUTABLE sequences. Why only for mutables? The class of objects I would expect it
to cover would be all ordered sequences, or, to phrase it a little more
pointedly, anything that supports ordered INDEXing. My understanding is that
dict's don't fall into that class of objects since their ordering is not
documented or to be depended on. However, tuple's do support ordered indexing,
so why don't tuple's have an index method?
P.S.: I know I haven't yet gotten an answer to my "why" question yet, but,
assuming it's just an oversight or an example of design without the big picture
in mind, an added benefit to fixing that oversight would be that the "index"
method's documentation could be moved from the currently odd seeming location on
the "Mutable Sequence Types" page to a place someone would look for it logically.
P.P.S.: As much as the elementary nature of my question would make it seem, this
isn't my first day using Python. I've used it on and off for several years and I
LOVE Python. It is only because of my love for the language that I question its
ways, so please don't be overly defensive when I guess that the cause for this
possible oversight is a lack of design.
Corey Lubin
Looking around google a little bit, people have been asking that same
questions since at least 1992. Here is what the BDFL has to say:
Guido van Rossum (Guido.va...@cwi.nl)
Wed, 04 Dec 91 18:48:34 +0100
>In reply to: Steven D. Majewski: "Why no index for tuples or strings ?"
>
>Most of the functions that operate on mutable sequences but NOT on
>immutable ones are obviously there because they DO CHANGE the sequence.
>BUT: why no string.index() or tuple.index() ?
>
>Is this just an oversight ?
>If not, what is the reason?
Umm, there isn't a real good reason. One thing I can say in my
defense is that string and tuple objects have no methods at all, all
operations on these are done with built-in operations like "+" and
"[...]", so adding an "index" method would be a bit of a change in the
structure.
For tuples, I suspect such a function would rarely be used; I think
that is most cases where x.index() would be useful, x is generally a
list, whose contents varies in time, rather than a tuple (which cannot
change easily).
For strings, there is a built-in module "string" which exports a
function "index" which searches for substrings, so you can say
string.index('one two three', 'two')
--Guido van Rossum, CWI, Amsterdam <gu...@cwi.nl>
The amount of typing wasted to defend design decisions such as this can
boggle one's mind. Just use lists unless you have on overwhelming reason
to do otherwise.
James
Read the quote. I *am* using a list.
That doesn't change the fact that this is unfriendly design. It's an ugly
inconsistent chunk of a Python's past in which built-in types didn't behave like
objects. It sticks out like a sore thumb, maybe just not very often.
Oh, and thanks for the insulting tone of your anticipated response. Have you
anything better to do with your time than wasting bytes writing empty responses
to what you already deem a waste of typing?
*sighs* just what I expected: another idle troll defending something just for
the sake of defending it. On the other hand, thanks 7stud, for the truly helpful
response.
Of course much has changed since then, and nowadays the world goes in
for tuple-abuse. Consequently the majority don't appear to understand
why tuple doesn't become simply an immutable list. But you have clearly
found the preferred solution on your own, so this is basically just a
history lesson.
Glad you asked? Is your thumb any less sore.
> Oh, and thanks for the insulting tone of your anticipated response. Have you
> anything better to do with your time than wasting bytes writing empty responses
> to what you already deem a waste of typing?
>
I'd have thought you would have saved time simply by refusing to rise to
what you clearly see as bait.
> *sighs* just what I expected: another idle troll defending something just for
> the sake of defending it. On the other hand, thanks 7stud, for the truly helpful
> response.
>
Get over it. This is Usenet, abuse is next door.
regards
Steve
--
Steve Holden +44 150 684 7255 +1 800 494 3119
Holden Web LLC/Ltd http://www.holdenweb.com
Skype: holdenweb http://del.icio.us/steve.holden
Recent Ramblings http://holdenweb.blogspot.com
When this topic last appeared on my radar, I ended up writing a long
message about it:
http://groups.google.com/group/comp.lang.python/msg/30e89128bdeb59c0
[...]
> *sighs* just what I expected: another idle troll defending something just for
> the sake of defending it. On the other hand, thanks 7stud, for the truly helpful
> response.
The problem with 7stud's quote from GvR is that it's out of date:
tuples do have methods now, as you've noticed, but just not the index
method. Previously, I've missed that method, and it wouldn't be hard
to add it to the tuple class (in CPython's own source code), but one
has to wonder whether it's really necessary, or at least as necessary
as for other classes. Certainly, there's a trade-off between essential
functionality and having, say, 100 methods which are all useful to
someone but which make interactive introspection a rather tedious and
confusing business.
Paul
I would argue that it shows the very guy who invented the language
stated publicly there was no good reason for tuples not to have an
index method---except for consistency; tuples had no other methods.
Now that tuples have other methods, the only justification he stated
no longer exists.
I think you misinterpreted my post, I agree with you. Please read it
again. You have touched on a very old topic. Many people have fought
tooth and nail to defend arbitrary design decisions such as a tuple not
having an index. It boils down to the fact that tuples are useless as a
result unless you know you really need them--and you never really NEED them.
James
Except that that wasn't the only justification. GvR also said:
"""
For tuples, I suspect such a function would rarely be used; I think
that is most cases where x.index() would be useful, x is generally a
list, whose contents varies in time, rather than a tuple (which cannot
change easily).
"""
The lack of convincing use cases is still a pertinent reason today. Note
that the original poster on this thread did not present a use case for
tuple.index, they were only asking out of curiosity.
If you have a use case for tuple.index, please show it to me, and I'll
show you what you should be using instead of a tuple.
-Carsten
Touche.
Maybe we can add such methods to the PyPy tuples for some time, to
experimentally see if they make the language worse :-)
(Adding such methods may reduce the amound of information you have to
keep in your brain to program with Python. If tuples and lists share
more methods then you don't have to remember what methods tuples don't
have. This means less complexity.)
Bye,
bearophile
Adding useless features always makes a product worse. What's your use
case for tuple.index?
-Carsten
Ruby is a bit younger than Python, it has shown that few things may be
better done in a different way. An advantage of PyPy is that it allows
faster and simpler ways to perform language experiments. So you can
even try things first and judge them later. You can find usercases
later. This may help rejuvenate Python a bit :-)
Bye,
bearophile
I'll trade you an index method for tuples for the whole complex number
facility.
I find this question odd for the following reason:
I doubt that *anyone* who programs in Python
has not encountered the situation where they change
a tuple to a list *solely* for the purpose of getting
access to the index method. There is simply no
conflict between the index method and immutability,
but at the moment you are forced to choose.
Anyway, for a simple use case, consider a game,
where the fixed set p of players have a fixed order.
A tuple is natural. Now for a player you want to
construct the opponents. If I had the index i it wd
be p[:i]+p[i+1:], but how to get the index?
Cheers,
Alan Isaac
opponents = tuple(x for x in p if x is not current_player)
-Carsten
I think the Ruby way is just to add a ton of methods to every class
and to give them all aliases as well. Then you let the programmer
"monkey patch" those classes in their own code, too.
> An advantage of PyPy is that it allows faster and simpler ways to perform language experiments. So you can
> even try things first and judge them later. You can find usercases later. This may help rejuvenate Python a bit :-)
It's virtually a matter of copy and paste to do this with CPython.
Here's a patch against the SVN trunk:
http://sourceforge.net/tracker/index.php?func=detail&aid=1696444&group_id=5470&atid=305470
Paul
Do you not see the gratuituous inconsistency between tuples and lists
as a useless feature? What is the use case for keeping it?
> I'll trade you an index method for tuples for the whole complex number
> facility.
Actually, I've found the use cases for list.index to be kind of thin.
Long before I think "Which one of these items is a 3?", I seem to
have thought "dictionary".
Cheers, Mel.
When a new feature is requested, the burden of proof is on the requester
to show that it has uses. The use case for not having tuple.index is
that there are no use cases for having it. If that answer sounds absurd,
it is because your question is absurd.
-Carsten
The use case has already been discussed. Removing the pointless
inconsistency between lists and tuples means you can stop having to
remember it, so you can free up brain cells for implementing useful
things. That increases your programming productivity.
Could you clarify that for me? I use tuples *a lot* and I really *NEED*
them - I'm building a lot of multi-tier reports where detail-level data
is pulled out of a dictionary based on a composed key. It is impossible
to build those dictionaries *without* using tuples.
So, I *need* those tuples, and they're far from useless to me.
For the rare, rare, rare cases where I *would* need an index function on
a tuple (I've never needed it):
class IndexTuple(tuple):
def index(n):
# your code goes here
would be sufficient, wouldn't it?
Best regards,
Bart
Will tuples also get a sort method? What about append and extend? pop?
__iadd__? __delslice__?
How many brain cells are actually freed up by not having to remember
that *one* method that you'd never use doesn't exist?
-Carsten
They are immutable so they won't get .sort() etc. sorted(...) already
works on them.
> How many brain cells are actually freed up by not having to remember
> that *one* method that you'd never use doesn't exist?
I dunno but I do know that Ruby is attracting a lot of potential Python
users because it apparently has fewer of these inconsistencies. A big
web site I hang out on decided to do a software rewrite (currently using
a huge perl script) and evaluated a bunch of possible approaches. In
the final decision, Ruby/Rails won out over Python/Django.
> On Sun, 2007-04-08 at 13:10 -0700, Paul Rubin wrote:
>> Carsten Haese <car...@uniqsys.com> writes:
>> > > Do you not see the gratuituous inconsistency between tuples and lists
>> > > as a useless feature? What is the use case for keeping it?
>> >
>> > When a new feature is requested, the burden of proof is on the requester
>> > to show that it has uses. The use case for not having tuple.index is
>> > that there are no use cases for having it. If that answer sounds absurd,
>> > it is because your question is absurd.
>>
>> The use case has already been discussed. Removing the pointless
>> inconsistency between lists and tuples means you can stop having to
>> remember it, so you can free up brain cells for implementing useful
>> things. That increases your programming productivity.
>
> Will tuples also get a sort method? What about append and extend? pop?
> __iadd__? __delslice__?
Since tuples are immutable, no.
And before you ask, since they aren't strings, they won't get upper,
lower, split or strip either.
> How many brain cells are actually freed up by not having to remember
> that *one* method that you'd never use doesn't exist?
74,972,561.
I think the problem is that Python developers are split between those who
see tuples as immutable lists, and those who see them as records/structs.
Neither of them is wrong -- tuples are multi-use. Guido may or may not
have designed them to be used as structs (short and heterogeneous, as
opposed to long and homogeneous) but designers are often surprised by the
uses people find for their creations, and the designer doesn't get the
final say as to what is the "right" usage.
If you see tuples as an immutable list, having an index method is quite
useful. If you see them as structs, an index method is useless.
--
Steven.
I think the construction
def f(*a): ...
shows that the "immutable list" interpretation is firmly ensconced in
the language.
"Impossible" is a strong word, as is "need" (especially when in all caps).
py> import md5
py> class HashedList(list):
... def __hash__(self):
... h = md5.new()
... for item in self:
... h.update(str(hash(item)))
... return int(h.hexdigest(), 16)
...
py> hl = HashedList('bob', 'carol', 'ted')
py> {hl:3}
{['bob', 'carol', 'ted']: 3}
Impossible? I wouldn't even say that this was all that difficult.
James
Possible, if by possible you mean "broken".
>>> D = {hl: 3}
>>> D
{['bob', 'carol', 'ted']: 3}
>>> hl[0] = 'Bob'
>>> D
{['Bob', 'carol', 'ted']: 3}
>>> D.keys()[0] is hl
True
>>> D[hl]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: ['Bob', 'carol', 'ted']
--
Steven.
def __setitem__(self, *args):
raise TypeError, '%s doesn't support item assignment.' %
self.__class__.__name__
Problem fixed. Next?
By the way, this would be analagous to the tedious
class Something(object):
def __init__(self, value):
self._value = value
value = property(lambda: self._value)
just to make sure users don't change the value of value so they don't
"break" the instance.
I don't think Bart is changing the items in his keys anyway--so the
problem which was stated as impossible is still possible. The solution
was not to code to your personal expectations but to show how tuples are
never essential. Any number of solutions could fix the problem you have
invented.
James
It remains to be proven that it is an inconsistency, rather than a design
decision.
> A big
> web site I hang out on decided to do a software rewrite (currently using
> a huge perl script) and evaluated a bunch of possible approaches. In
> the final decision, Ruby/Rails won out over Python/Django.
Given that so many web sites still decide to (re)write in PHP, I don't think
that is much of an argument.
Georg
IIRC, for this use case of tuples there was a practical reason rather than
an interpretation one. It is also on the list of potential changes for
Python 3000.
Georg
hl.reverse()
hl.sort() # if the list isn't already sorted
del hl[0]
hl.append()
etc.
Yes, you can block those as well... but by the time you've finished making
your HashedList immutable, it is just a slower tuple with a different
name.
In other words... you can avoid using tuples by using a tuple with a
different name. You might as well just do this:
HashedList = tuple
--
Steven.
Let's recall what GvR said:
"""
For tuples, I suspect such a function would rarely be used; I think
that is most cases where x.index() would be useful, x is generally a
list, whose contents varies in time, rather than a tuple (which cannot
change easily).
"""
In Guido's opinion, it's not the "structness" of tuples that negates the
need for tuple.index, it's their inability to be mutated easily. So
Guido seems to disagree with your notion that an index method is quite
useful for immutable lists.
I won't presume to speak for Guido, but if I had to connect the dots
between "tuples are immutable" and "tuples will rarely need an index
method", I'd do it like this: Consider an object X and a tuple T. Tuples
have "X in T" tests, so you can check if there exists some N such that
T[N]==X. The lack of the index method means you won't know the value of
N, but what would knowing N give you? You can't modify T, so all you can
do is read T[N], but you already know that that's going to return X, so
you might as well just use X.
Any use case for actually having to know N would have to involve an
operation where you end up explicitly using an index other than N, such
as slicing T from 0 to N-1, or looking at T[2*N] or something like that.
Of course such operations might be useful, but algorithms that need an
operation like that would self-document their design more clearly by
using a list instead of a tuple.
I hope this explains at least to some people how this seemingly
gratuitous inconsistency can actually be viewed as a justified design
decision.
-Carsten
> I won't presume to speak for Guido, but if I had to connect the
> dots between "tuples are immutable" and "tuples will rarely need an
> index method", I'd do it like this: Consider an object X and a
> tuple T. Tuples have "X in T" tests, so you can check if there
> exists some N such that T[N]==X. The lack of the index method means
> you won't know the value of N, but what would knowing N give you?
> You can't modify T, so all you can do is read T[N], but you already
> know that that's going to return X, so you might as well just use
> X.
>
> Any use case for actually having to know N would have to involve an
> operation where you end up explicitly using an index other than N,
> such as slicing T from 0 to N-1, or looking at T[2*N] or something
> like that. Of course such operations might be useful, but
> algorithms that need an operation like that would self-document
> their design more clearly by using a list instead of a tuple.
This is a reasonable argument, but all such arguments miss what I
think is an important use case for tuples: you want a list, but you need
to use it as a dictionary key.
--
--OKB (not okblacke)
Brendan Barnwell
"Do not follow where the path may lead. Go, instead, where there is
no path, and leave a trail."
--author unknown
To prevent abuse.
but by the time you've finished making
> your HashedList immutable, it is just a slower tuple with a different
> name.
But has an index() method.
> In other words... you can avoid using tuples by using a tuple with a
> different name. You might as well just do this:
>
> HashedList = tuple
You can avoid using tuples any number of ways. For example, you can
catenate strings.
You seem to be under the misapprehension that I authored the Subjet
line. Please read the original quote:
> It boils down to the fact that tuples are useless as a result unless
> you know you really need them--and you never really NEED them.
Bear in mind that this was also a response to someone admittedly less
familiar to the language--to encourage him to use lists in favor of
tuples to avoid inconveniences later.
The HashedList is to show that you can always get around the requirement
for a tuple and thus an absolute need for a tuple doesn't exist, as
implied by the quote. I make no assertions as to the HashedLists
efficiency. I use tuples all of the time, but I could just as well
catenate strings etc. They are a language convenience that are
ultimately dispensible.
James
No wonder no convincing use cases for tuples have shown up. You just
defined use cases of tuples as unconvincing.
My personal opinion is that lack of use cases are used too much as an
excuse. Limiting the development of your language to use cases makes
your language less consistent and so makes your language less easy to
learn.
Of course it also limits the language to what the developers can think off.
I once thought it would be usefull to have something like a slice but
with extended functionality. So I first tried this:
class Islice(slice):
...
and I got:
type 'slice' is not an acceptable base type
then I just tried:
class Islice:
...
But an instance of such a class can't be used as an index, despited the
propoganda that is made for duck typing in this news group.
I guess the developers just couldn't see the use case of this.
But you do have to wonder when the developers started to unify classes
and types, why they just didn't go the whole wayr?. Making all types
subclassable, means you have only one case to code and the user doesn't
has to wonder whether a particular type is subclassable or not. I think
that is a bigger gain, than the potential loss one may experience
because some type that now are subclassable will never actually be
subclassed.
--
Antoon Pardon
I don't agree. Good or bad design is not dependant on what is
implemented and what is not.
> The use case for not having tuple.index is
> that there are no use cases for having it. If that answer sounds absurd,
> it is because your question is absurd.
You mean that those who are against tuple.index won't find any use case
convincing enough.
--
Antoon Pardon
The two don't contradict. A design decision can introduce an
inconsistency. AFAICS having an index method on tuples seems
rather natural. Looking for the index of a particular item in
your sequence seems just as usefull independant of the nature
of your sequence. So unless there is some rather forcefull
argument it seems inconsistent to have some sequences lacking
this method.
--
Antoon Pardon
>> When a new feature is requested, the burden of proof is on the requester
>> to show that it has uses.
>
> I don't agree. Good or bad design is not dependant on what is
> implemented and what is not.
There is a cost to every new language feature: it has to be implemented,
documented, maintained, and above all learned by the users. Good design
involves, in part, not adding to these burdens except where there is a
benefit at least equal to the cost.
>> The use case for not having tuple.index is
>> that there are no use cases for having it. If that answer sounds absurd,
>> it is because your question is absurd.
>
> You mean that those who are against tuple.index won't find any use case
> convincing enough.
>
Why not try them? Pose a few useful cases where the existence of
tuple.index() would actually give a benefit and see what response you get.
You would have to meet a few obvious conditions: the use case would need to
be one where a tuple was preferable to a list (the obvious one being where
you need to hash it), the tuple would have to be sufficiently long or the
calls to 'index' sufficiently frequent to make casting to a list so you can
call 'list(obj).index(...)' unattractive, and you actually need a reason to
be using 'index' rather than just the 'in' operator.
So what is the easiest to learn: "All sequences have an index method" or
"Such and so sequences have an index method and others don't"
Which of the above is the easiest to document?
Now with implementation and maintaining. If you would start with a class
of sequence which classes like tuple and list would inherit from, then
there also would be a single function to be implemented and maintained.
It would just be usable in more types.
>>> The use case for not having tuple.index is
>>> that there are no use cases for having it. If that answer sounds absurd,
>>> it is because your question is absurd.
>>
>> You mean that those who are against tuple.index won't find any use case
>> convincing enough.
>>
> Why not try them? Pose a few useful cases where the existence of
> tuple.index() would actually give a benefit and see what response you get.
>
> You would have to meet a few obvious conditions: the use case would need to
> be one where a tuple was preferable to a list (the obvious one being where
> you need to hash it), the tuple would have to be sufficiently long or the
> calls to 'index' sufficiently frequent to make casting to a list so you can
> call 'list(obj).index(...)' unattractive, and you actually need a reason to
> be using 'index' rather than just the 'in' operator.
If someone states: "Show me your use case for using tuple.index and I
will show you how to avoid it." or words to that effect I think there
is little use trying.
Besides I have seen how such things evolve here before. Every use case
that will be presented, will be rewritten in a way that doesn't need
tuple.index and these rewritals will be used as an argument for not
having tuple.index. If you need to hash it, you can simply subclass
list and provide a hash with your class or you can simply use tuples
and write an index function yourself.
The same happened with the ternary operator. Every use case someone
could come up with was rejected by rewriting the code without using
a ternary operator. AFAICS the only reason the ternary operator
finaly got introduced was because a python developer was bitten by an
illusive bug, introduced by one of the idioms that was often used as a
way to simulate a ternary operator.
--
Antoon Pardon
I think this observation leads to insights both at the end-user level
and at the implementer level. Tuples and lists are sequences; the
index method can be defined generically for all sequences; adding such
a method to the tuple type can be done with barely any changes to the
implementation taken from the list type. This leads to the observation
that a generic index method (defined as a function in the
implementation) could be made to work with both lists and tuples, and
that various other methods might also be defined similarly, although
things like append, extend and other mutating methods wouldn't be
appropriate for a tuple.
> Which of the above is the easiest to document?
>
> Now with implementation and maintaining. If you would start with a class
> of sequence which classes like tuple and list would inherit from, then
> there also would be a single function to be implemented and maintained.
> It would just be usable in more types.
There isn't a "big win" in this case: the intersection of useful
methods between mutable and immutable sequence types is rather small.
Nevertheless, providing a slightly deeper abstract class hierarchy
might be appropriate, and this is being considered for Python 3000.
[...]
> The same happened with the ternary operator. Every use case someone
> could come up with was rejected by rewriting the code without using
> a ternary operator. AFAICS the only reason the ternary operator
> finaly got introduced was because a python developer was bitten by an
> illusive bug, introduced by one of the idioms that was often used as a
> way to simulate a ternary operator.
The ternary operator, whilst providing new and occasionally useful
functionality, is rather "badly phrased" in my opinion: when used,
it's a bit like reading one natural language and suddenly having the
grammar of another in use for the rest of the sentence.
Paul
>> Now with implementation and maintaining. If you would start with a class
>> of sequence which classes like tuple and list would inherit from, then
>> there also would be a single function to be implemented and maintained.
>> It would just be usable in more types.
>
> There isn't a "big win" in this case: the intersection of useful
> methods between mutable and immutable sequence types is rather small.
> Nevertheless, providing a slightly deeper abstract class hierarchy
> might be appropriate, and this is being considered for Python 3000.
Well I wasn't trying to show this aspect as a big win. Just illustrating
it doesn't have to be a big cost in this case.
>> The same happened with the ternary operator. Every use case someone
>> could come up with was rejected by rewriting the code without using
>> a ternary operator. AFAICS the only reason the ternary operator
>> finaly got introduced was because a python developer was bitten by an
>> illusive bug, introduced by one of the idioms that was often used as a
>> way to simulate a ternary operator.
>
> The ternary operator, whilst providing new and occasionally useful
> functionality, is rather "badly phrased" in my opinion: when used,
> it's a bit like reading one natural language and suddenly having the
> grammar of another in use for the rest of the sentence.
I agree. The structure of the if-expression doesn't resemble the
structure of the if-statement. I think it was a bad choice to
have the two so dissimilar.
--
Antoon Pardon
It's not a definition, it's an observation. I'm simply saying that all use
cases I've seen for tuple.index could be written in a clearer fashion by using
something else. Please prove me wrong by supplying a use case of tuple.index
that can not be improved by rewriting.
Note that I have proved elsewhere on this thread that any real use case for
tuple.index will involve an operation to explicitly use an index different
from the one obtained by the call to tuple.index(). I'd like to hear your
opinion on this.
> My personal opinion is that lack of use cases are used too much as an
> excuse. Limiting the development of your language to use cases makes
> your language less consistent and so makes your language less easy to
> learn.
That is your opinion, and you are entitled to your opinion. My opinion is that
adding features that don't have any uses just weigh the language down
unnecessarily, and they distract programmers from finding the best solution to
their problem.
> Of course it also limits the language to what the developers can
> think off.
Initially, yes, but if enough use cases exist for a feature that the
developers didn't think of, it will be implemented.
-Carsten
Or maybe you just can't think of any good use cases, and that's annoying you
because it proves my point. Please, prove me wrong by showing use cases for
tuple.index that can't be rewritten.
-Carsten
No it is a defintion because it states this can be done for every
possible case, even cases you have no idea about.
> Note that I have proved elsewhere on this thread that any real use case for
> tuple.index will involve an operation to explicitly use an index different
> from the one obtained by the call to tuple.index(). I'd like to hear your
> opinion on this.
And what relevance would such a proof have?
>> My personal opinion is that lack of use cases are used too much as an
>> excuse. Limiting the development of your language to use cases makes
>> your language less consistent and so makes your language less easy to
>> learn.
>
> That is your opinion, and you are entitled to your opinion. My opinion is that
> adding features that don't have any uses just weigh the language down
> unnecessarily, and they distract programmers from finding the best solution to
> their problem.
Adding the index method to tuples is not adding a feature. It is
removing a limitation. Writing an index function in python that
works with whatever sequence is dead easy. So if the python
core implementation only works with a specific sequence that
is putting on unnecessary limitations.
>> Of course it also limits the language to what the developers can
>> think off.
>
> Initially, yes, but if enough use cases exist for a feature that the
> developers didn't think of, it will be implemented.
Which means your language will not be that usefull for a number of
things until you have frustrated enough people.
--
Antoon Pardon
> On 2007-04-10, Duncan Booth <duncan...@invalid.invalid> wrote:
>> There is a cost to every new language feature: it has to be
>> implemented, documented, maintained, and above all learned by the
>> users. Good design involves, in part, not adding to these burdens
>> except where there is a benefit at least equal to the cost.
>
> So what is the easiest to learn: "All sequences have an index method"
> or "Such and so sequences have an index method and others don't"
>
> Which of the above is the easiest to document?
The second would be if it were true. However it would mean you would have
to add an index method to *all* sequences.
FWIW, The current documentation says that 's.index' is a method defined on
all *mutable* sequence types: almost as simple as your second wording but
unfortunately misleading since strings also have index.
> If someone states: "Show me your use case for using tuple.index and I
> will show you how to avoid it." or words to that effect I think there
> is little use trying.
I genuinely cannot think of a use case. I didn't ask you to suggest one so
I could show you how to avoid it, I asked you to suggest one so that we
could take the discussion from the purely hypothetical to a more concrete
discussion of whether it would be a worthwhile enhancement.
Fair enough though. I'll assume you cannot think of a suitable use case
either.
That would be a theorem or conjecture, not a definition. You can call it
definition or banana or screwdriver if you like, but that's not going to
disprove it.
> > Note that I have proved elsewhere on this thread that any real use case for
> > tuple.index will involve an operation to explicitly use an index different
> > from the one obtained by the call to tuple.index(). I'd like to hear your
> > opinion on this.
>
> And what relevance would such a proof have?
It proves at that every conceivable use case for tuple.index, including
the ones I am not thinking of, will never directly use the index
obtained from calling tuple.index(). Such a use case will be poorly
self-documented, and a clearer implementation can be found by avoiding
tuple.index().
I'll illustrate this on the one concrete use case that was suggested on
this thread: In a game where the sequence of players is given by the
tuple p, find the opponents of the current player.
One hypothetical solution is to find the index if the current player and
then slice and reassemble the tuple:
i = p.index(current_player)
opponents = p[:i-1] + p[i+1:]
An alternative is this:
opponents = tuple(x for x in p if x is not current_player)
You may disagree, but in my opinion, the alternative is better because
it is a more natural translation of the concept that the opponents of
the current player are all players that are not the current player.
> Adding the index method to tuples is not adding a feature. It is
> removing a limitation.
The non-existence of tuple.index is only a limitation if there is a need
for the method to exist. Please prove that this need exists.
-Carsten
No you just have proven my point. I predicted that whatever use case
would be given, people would stand ready to rewrite is and use those
rewritals as argument againt the use case. Here you are ready to do
just that.
Since you can just write an index function that works with any sequence
or you could simply write something like list(tup).index('...'), any
code that would use tupple.index can be rewritten to do without.
But that is not such a strong argument. Should the case be reversed
and tuples have an index method and lists not, you would be able
to rewrite any code that would use list.index into code that
wouldn't. But if you are so eager to rewrite, how about the following:
I am using the struct module to get binary data from a file.
Sometimes I want to skip until I find a particular binary
number. Somewhat simplified it looks like this:
class Itemfile:
def __init__(self, fn):
self.fl = open(fn)
self.ix = 80
def nextitem(self):
if self.ix == 80:
self.buf = struct.unpack("80i", self.fl.read(320))
self.ix = 0
result = self.buf[self.ix]
self.ix += 1
return result
def skipuntil(self, val):
done = False
while not done:
try:
self.ix = self.buf.index(val, self.ix)
done = True
except ValueError:
self.ix = 0
self.buf = struct.unpack("80i", self.fl.read(320))
Now I'm sure you can rewrite this without the need of tuple.index.
It just seems odd that I have to go through extra hoops here to
get the effect of tuple.index because struct.unpack returns its result
in a tuple and a tuple doesn't provide index.
--
Antoon Pardon
Which illustrate that the mutable unmutable distinction is not very
usefull to decide whether a sequence could use "index" or not.
>> If someone states: "Show me your use case for using tuple.index and I
>> will show you how to avoid it." or words to that effect I think there
>> is little use trying.
>
> I genuinely cannot think of a use case. I didn't ask you to suggest one so
> I could show you how to avoid it, I asked you to suggest one so that we
> could take the discussion from the purely hypothetical to a more concrete
> discussion of whether it would be a worthwhile enhancement.
I have given a use case in an other article in this thread. Feel free to
comment.
--
Antoon Pardon
It doesn't because "need" is such a strong word, that just the fact that
you can write your own index function means the method isn't needed.
--
Antoon Pardon
"men" in "three good men"
to succeed where formerly only single characters could be checked for.
One might perversely allow extension to lists and tuples to allow
[3, 4] in [1, 2, 3, 4, 5, 6]
to succeed, but that's forcing the use case beyond normal limits. The
point I am trying to make is that circumstances alter cases, and that we
can't always rely on our intuition to determine how specific methods
work, let alone whether they are available.
I hear the screams of "just add the index() method to tuples and have
done with it" and, to an extent, can sympathize with them. But that way
lies creeping featurism and the next thing you know we'll have a ternary
operator in the language - oh wait, we do now!
>> Which of the above is the easiest to document?
>>
>> Now with implementation and maintaining. If you would start with a class
>> of sequence which classes like tuple and list would inherit from, then
>> there also would be a single function to be implemented and maintained.
>> It would just be usable in more types.
>
> There isn't a "big win" in this case: the intersection of useful
> methods between mutable and immutable sequence types is rather small.
> Nevertheless, providing a slightly deeper abstract class hierarchy
> might be appropriate, and this is being considered for Python 3000.
>
> [...]
>
>> The same happened with the ternary operator. Every use case someone
>> could come up with was rejected by rewriting the code without using
>> a ternary operator. AFAICS the only reason the ternary operator
>> finaly got introduced was because a python developer was bitten by an
>> illusive bug, introduced by one of the idioms that was often used as a
>> way to simulate a ternary operator.
>
> The ternary operator, whilst providing new and occasionally useful
> functionality, is rather "badly phrased" in my opinion: when used,
> it's a bit like reading one natural language and suddenly having the
> grammar of another in use for the rest of the sentence.
>
Indeed the syntax is deliberately "crippled" - Guido's reasoning being,
I believe, that if it were too easy and natural to use then people would
use it inappropriately and too frequently.
regards
Steve
--
Steve Holden +44 150 684 7255 +1 800 494 3119
Holden Web LLC/Ltd http://www.holdenweb.com
Skype: holdenweb http://del.icio.us/steve.holden
Recent Ramblings http://holdenweb.blogspot.com
Your data is an array. Choosing a data structure that doesn't fit your
data is always going to cause pain. Instead of using struct.unpack, you
should use array.array, and voila!, you get an index method.
-Carsten
It would indeed be much easier to just give up. However, the resistance
to tuple.index is more than a generic resistance to feature creep. As I
have demonstrated elsewhere on this thread, any use case for tuple.index
will be inherently obfuscated. Code clarity is a major design goal of
Python, and adding tuple.index would be contrary to this goal.
I'm just a user with no influence on the development of Python itself,
but in my humble opinion, the non-existence of tuple.index is more
pythonic than its existence would be.
-Carsten
But it's telling that by adopting precisely the implementation that we
currently have for lists, we can have a tuple method which does what
most people would reasonably expect. "Why are we suddenly getting
single characters instead of whole strings?" people have presumably
exclaimed often enough, illustrating that the sequence nature of
strings is a controversial topic. Lists and tuples, however, don't
have such controversial baggage.
> I hear the screams of "just add the index() method to tuples and have
> done with it" and, to an extent, can sympathize with them. But that way
> lies creeping featurism and the next thing you know we'll have a ternary
> operator in the language - oh wait, we do now!
Yes, but the cost of adding index to tuples is minimal, and the mental
cost to programmers is arguably negative. Meanwhile, we now have to
put up with the syntactic bodge that is the ternary operator until the
time comes when it gets deprecated as something that didn't work out
or wasn't really necessary (in Python 4000, perhaps), meaning that we
now have to read third-party code more carefully, the people writing
editors and tools have to change their lexers/parsers again, and so
on.
Paul
Your alternative is wrong because it wont raise ValueError if
current_player is not present in the tuple. Please revise your
"solution."
--
mvh Björn
I'd love to have that! There are at least one million use cases for
finding a sequence in a sequence and implementing it yourself is
non-trivial. Plus then both list and tuple's index methods would work
*exactly* like string's. It would be easier to document and more
useful. A big win.
> Indeed the syntax is deliberately "crippled" - Guido's reasoning being,
> I believe, that if it were too easy and natural to use then people would
> use it inappropriately and too frequently.
There are no appropriate use cases for that feature. Maybe not for
tuple.index either, but increasing consistency and being able to say
"ALL sequences have an index method that works like THIS" would be a
big win. Unfortunately, it really is the string type that screws up
the symmetry.
--
mvh Björn
>> I hear the screams of "just add the index() method to tuples and have
>> done with it" and, to an extent, can sympathize with them. But that way
>> lies creeping featurism and the next thing you know we'll have a ternary
>> operator in the language - oh wait, we do now!
>
> Yes, but the cost of adding index to tuples is minimal, and the mental
> cost to programmers is arguably negative. Meanwhile, we now have to
> put up with the syntactic bodge that is the ternary operator until the
> time comes when it gets deprecated as something that didn't work out
> or wasn't really necessary (in Python 4000, perhaps), meaning that we
> now have to read third-party code more carefully, the people writing
> editors and tools have to change their lexers/parsers again, and so
> on.
>
What can I say? Every language has warts. Some people were as anxious to
see if ... else (which I regard as a wart) put in as others are to see
tuple.index().
You have a point. Here is my revised solution:
assert current_player in p
opponents = tuple(x for x in p if x is not current_player)
The added advantage is that AssertionError is better than IndexError for
conveying that a severe program bug has occurred.
-Carsten
_.replace("IndexError", "ValueError"), of course.
-Carsten
The patch is already submitted:
http://sourceforge.net/tracker/index.php?func=detail&aid=1696444&group_id=5470&atid=305470
I won't miss tuple.index very often if it never gets in, but it's
always enlightening/entertaining to see the rationales given for the
rejection of this and other features, in contrast to things like "y if
x else z" which just seem to mysteriously acquire momentum and then
power their way in regardless.
Paul
Unless you're running python with the -O flag. So, instead of the
"unpythonic"...
i = p.index(current_player)
opponents = p[:i] + p[i+1:]
...we now have...
if current_player not in p:
raise ValueError, current_player
opponents = tuple(x for x in p if x is not current_player)
Sure, p would probably be a list for a lot of games, and as I've noted
previously, since you have to specify all of the elements at once to
initialise the tuple, you should know where the player is. But this
only applies to situations where you have control over the code
needing to know the index *and* the code making the tuple in the first
place.
Paul
No it is not. This is exactly what I thought was going to happen. One
simplifies a problem so that the code is not too big to discuss here
and people will use characteristics of the simplified code to suggest
how one should have solved the problem differently.
I'm not interrested in going through such a merry around again.
As I said, writing an index function that works with any kind
of sequence is easy enough and once written can be used as
often as one whishes. So although I prefer more consistency
from a language that python currently provides the language
has enough going for it to stick with it dispite these kind
of warts. So having that function is a practical enough solution
for me. And curiously, having that function makes using
tuples no longer painfull in situations where other would
argue that tuples don't fit my data. If tuples don't fit
my data, I sure find it strange that one little function
causes you to no longer experience it as such.
--
Antoon Pardon
Sublist search (and generally adding a bit of pattern matching
features to Python) looks far from being perverse, it may even become
pythonic ;-)
Bye,
bearophile
Assertions are not checked when you run scripts with -O. Furthermore,
changing the exception type and the message it produces, is quite a
big deviation from list.index.
--
mvh Björn
Right. Which is why you use assert to guard against situations that
should never happen, and you determine in unit tests that they, in fact,
don't happen. Realistically, in a game loop such as
while not game_has_ended:
for current_player in p:
player_does_something(current_player)
it's obvious that the assertion "current_player in p" will never fail.
> Furthermore,
> changing the exception type and the message it produces, is quite a
> big deviation from list.index.
What's your point? I wasn't talking about coding a drop-in replacement
for list.index. I was suggesting one possible solution to a problem that
may or may not be solved by using tuple.index.
-Carsten
I'm curious why someone would even consider using a tuple in this case
regardless. I think that much of the desire for tuple.index is because
people use a tuple where they could have a list, but either a) some
vestige of B&D language programming comes out and they want to make
sure a caller can't mutate it or b) they decide it's not going to
change and use the "immutable list" version of the tuple.
The first reason is clearly perverse, and can be discounted.
The second means this is not so much about tuple.index as it is about
appropriate data types. It's not going to be resolved by use cases,
because clearly the only use of tuple.index is when you're using it as
an immutable list, as in this case. Any use case where you'd want to
search a tuple can be rewritten (trivially) as a list.
So the solution for the dissenters is to justify the need for a frozen
list, not to justify index on tuples.
The only use case which even approaches reasonableness in this thread
is the binary parsing example (where the position of a value in an
unpacked binary blob might be something you need to know). This is a
rare enough use case and is easy enough to work around (convert it to
a list, write a helper function) that I don't think it's worth any
language change overhead at all.
Maybe someone had to much alcohol when they were coding? Maybe they
don't know better? Maybe they thought that an index method on a
sequence made sense? Who are you to spoil their fun? Could it be that
YOU are the B&D person?
--
mvh Björn
> assert current_player in p
> opponents = tuple(x for x in p if x is not current_player)
That would perform better as:
opponents = tuple(x for x in p if x is not current_player)
assert opponents
Tim Delaney
I'd love to have that! There are at least one million use cases for
finding a sequence in a sequence and implementing it yourself is
non-trivial. Plus then both list and tuple's index methods would work
*exactly* like string's. It would be easier to document and more
useful. A big win.
=======================
It would be ambiguous: [3,4] in [[1,2], [3,4], [5,6]] is True now.
Strings are special in that s[i] can only be a (sub)string of length 1.
'b' in 'abc' is True. This makes looking for longer substrings easy.
However, [2] in [1,2,3] is False. IE, list[i] is not normally a list. So
looking for sublists is different from looking for items.
Terry Jan Reedy
No mystery. It was Guido's initial proposal and he never changed his mind.
Still wrong on two counts. First, assert is a no-op if optimization
is turned on. Second, your version returns a different result from
the original if current_player occurs in p more than once.
Right. I already responded to this when Bjorn made the same objection.
Please try to keep up.
> Second, your version returns a different result from
> the original if current_player occurs in p more than once.
First of all, in the use case we're talking about, current_player
shouldn't occur in p more than once. And if it did, is it really
reasonable to demand that that player be their own opponent? I don't
think so. So yes, the result is different because it's correct, and the
tuple.index-based solution is actually incorrect in this case.
-Carsten
> I'm just a user with no influence on the development of Python itself,
> but in my humble opinion, the non-existence of tuple.index is more
> pythonic than its existence would be.
I really cannot follow the logic behind this statement.
I can write:
L = [a,b,c,d,e,f]
T= (a,b,c,d,e,f)
The difference between the two things is that I can add to
and change L, but not T.
Now it seems to me that whatever argument is used to
justify the existence of:
n = L.index(d)
can be used to justify the existence of:
n = T.index(d)
and vice versa.
Cut down to these basics, it seems to me that the arguments
against the latter construct are simply knee jerk reactions
to preserve the status quo.
If an index method for tuples is such a very bad thing,
then the same arguments can be used to justify the
removal of the list index method from the language.
I happen to agree with Antoon - there is a LOT of merit
in consistency, as it makes things easy to learn and remember.
And I would heretically go even further, and argue that it
should be possible to write stuff like:
T = T.append(x)
And get back a new tuple bound to the old name...
- Hendrik
It isn't a language change: it's a change to the interface of a data
type, and not a particularly big one, either.
Paul
> I can write:
>
> L = [a,b,c,d,e,f]
> T= (a,b,c,d,e,f)
>
> The difference between the two things is that I can add to
> and change L, but not T.
No, that's *one* difference between the two things. There are other
differences, e.g. the obvious is that they are different types (and
therefore different string representations), but also some not so obvious:
>>> hash((1,2,3))
-378539185
>>> hash([1,2,3])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: list objects are unhashable
> Now it seems to me that whatever argument is used to justify the
> existence of:
>
> n = L.index(d)
>
> can be used to justify the existence of:
>
> n = T.index(d)
>
> and vice versa.
That depends on what you the purpose of lists and tuples are. Yes, they
are both sequences, but they have different uses. Ball-peen hammers and
tack hammers are both hammers, but they have different purposes and
therefore different functionality. Likewise for tuples and lists:
Lists are designed for sequences of homogeneous items, e.g.:
L = [1, 2, 4, 8, 16, 32]
while tuples are designed to be more like structs or records, with
heterogeneous items, e.g.:
T = ("Fred", 32, 12.789, {}, None, '\t')
So according to these intended usages, it makes sense to ask for
L.index(32) because in an application you have no way of telling which
item (if any) 32 would be in. But T.index(32) is seen as meaningless,
because you know that either 32 is in the second slot or it isn't --
you're never going to find yourself in a situation knowing that 32 is
*somewhere* in the tuple without knowing where the one place it *could* be.
(There is one other option: you care that 32 is somewhere in the tuple,
but you don't care where. That's when you use the "in" operator.)
Anyway, that was the original design. When you see tuple, think struct. If
you have a struct, it doesn't make a whole lot of sense to ask "which
field contains 32?", and so according to this intended usage, giving
tuples index and count methods would be a Bad Idea: it just makes extra
work for the Python Dev team, for no benefit.
Personally, I think that tuples do double-duty as *both* immutable lists
and structs/records. So even though index and count methods don't make
sense for a struct, it does make sense for an immutable list, and I for
one would not object to seeing tuples grow those two methods.
[snip]
> And I would heretically go even further, and argue that it should be
> possible to write stuff like:
>
> T = T.append(x)
>
> And get back a new tuple bound to the old name...
That's a design decision, and one that's not likely to be accepted because
it's so easy to do:
T = T + (x,) # like T.append()
T = T + (x, y, z) # like T.extend()
T = tuple(sorted(T)) # like T.sort()
T = T[:4] + T[4:] # like del T[4]
etc.
It makes sense for lists to have these methods because lists can make the
changes in place, but tuples can't.
--
Steven.
>From another function, you receive a tuple of data that it extracted
from a stream. Within that tuple is a marker that indicates where the
head of the incoming stream's data structure is. You need to find the
marker and scan from that location on to sync your local data structure
to the incoming stream's data.
Should the external function provide the stream data in a list rather
than a tuple? Probably, but someone else wrote the function so that's
out of your control. Can you cast the tuple to a list? Sure, but for a
large tuple that's potentially a large speed and memory hit.
That probably the biggest general use case for tuple.index(). A
third-party module returns a tuple in which you need to find a piece of
data.
---
-Bill Hamilton
wha...@entergy.com
I think you are confused. Last time I heard this homogeneous items stuf,
it had nothing to do with the types being the same. They were homogeneous
because they somehow belonged together and heterogeneous because they
just happened to live together. Similarity of type played no part in
calling the data homogeneous or heterogeneous.
--
Antoon Pardon
Then you are confused. The typical use case for tuples are database
records. The columns in the table can have completely different types but
the values in a row, represented as a Python tuple, of course belong
together.
The homogeneous objects in lists must not be of the same type but share
some behavior so it makes sense to apply some operation on all the
elements. For example get the length of each item or sum them all up.
Ciao,
Marc 'BlackJack' Rintsch
Don't blame me. I don't agree with the view. But that was sort of the
explanation that was given here last time I remember this topic came
up in defending why tuples and lists differ in a number of ways that
are less obvious.
They wrote about lists containing homogeneous items and tuples
containing hetergenous items but stressed rather strongly that
this shouldn't be understood in terms of type similarities.
> The homogeneous objects in lists must not be of the same type but share
> some behavior so it makes sense to apply some operation on all the
> elements. For example get the length of each item or sum them all up.
No they don't. The counter example is using a list as a stack when
evaluating expressions. You can use one stack to store the still
to be treated numbers and operands and those two don't need
common behaviour.
--
Antoon Pardon
So, when you have a) a third party module that you cannot change and
b) it shouldn't return a tuple but it does anyway and c) it's a big
enough tuple that is large enough that conversion to a list is
prohibitive, that's a "general" use case for tuple.index?
Has this supposedly general and common use case actually happened?
If you want a language that just adds whatever methods anyone thinks
of, along with whatever aliases for it any can think of, to every data
type, you know where to find Ruby.
>> Lists are designed for sequences of homogeneous items, e.g.:
>>
>> L = [1, 2, 4, 8, 16, 32]
>> while tuples are designed to be more like structs or records, with
>> heterogeneous items, e.g.:
>>
>> T = ("Fred", 32, 12.789, {}, None, '\t')
>
> I think you are confused.
Anything is possible.
> Last time I heard this homogeneous items stuf,
> it had nothing to do with the types being the same. They were homogeneous
> because they somehow belonged together and heterogeneous because they
> just happened to live together. Similarity of type played no part in
> calling the data homogeneous or heterogeneous.
Nevertheless, regardless of whether the items have the same type or
different types, you don't need an index method for heterogeneous items.
Like I said, think of a tuple as a struct. Even if the fields of the
struct all have the same type, there is little reason to ever ask "which
field has such-and-such a value?".
Anyway, that's was the reasoning. As I've said, tuples do double-duty as
both immutable lists and struct-like objects. I wouldn't object to them
growing index and count methods -- but you won't see me volunteering to
write the code for that, because I don't care that much.
So how about it? All you people who desperately want tuples to grow an
index method -- will any of you donate your time to write and maintain the
code?
--
Steven.
Nobody is asking for Ruby, as far as I can see. I even submitted a
quick patch to provide tuple.index (a method that has already been
thought of), given the triviality of the solution, but you won't find
me asking for a bundle of different convenience methods with all their
aliases on every object, regardless of whether you can monkey-patch
them after the fact or not. For example:
http://www.ruby-doc.org/core/classes/Array.html#M002235
There's a pretty big chasm between wanting to be able to apply
existing functionality exactly to a type which for some reason never
acquired it and embracing the method proliferation and other low-
hanging fruit-picking seemingly popular in Ruby. In observing this,
one can make objective decisions about things like this...
http://wiki.python.org/moin/AbstractBaseClasses
Note that, in that document, index and count are methods of
MutableSequence. Quite why this should be from a conceptual
perspective is baffling, but don't underestimate the legacy influence
in such matters.
Paul
Note that the mail I responded to was using being drunk, not knowing
any better, and having fun as use cases for the method. That sounds
like Ruby-style method proliferation to me ;)
> Note that, in that document, index and count are methods of
> MutableSequence. Quite why this should be from a conceptual
> perspective is baffling, but don't underestimate the legacy influence
> in such matters.
>
Well, I'm not Guido obviously, but here's why I don't find it baffling.
There are 2 main reasons why you'd use an immutable sequence for something:
1) You want to make sure it's not modified by a callee. This is
unPythonic and mostly unnecessary. Pass them a copy if you're that
paranoid.
2) Because you are representing a known, structured data type. This
can be either unordered, in which case index() is meaningless (as in
frozenset), or it can be ordered, in which case the order is an
implicit part of the structure. In such a case, index() is also
meaningless, and should never be necessary.
The primary use case for index on tuple is because people use them as
immutable lists. That's fine as far as it goes, but I want to know
what the justification is for using an immutable list, and if you have
one why you need to use index() on it. There's only 2 use cases I've
heard so far for that: certain types of binary parsing, which I don't
think is common enough to justify modification to the language core,
and third party libs returning silly things, which I *certainly* don't
think justifies changes to the language core.
I'm pretty against tuples growing index() ever. I think that if there
is a real need (and just because I haven't seen one doesn't mean it's
not there) for an immutable list, the introduction of fozenlist() to
the collections module (or something) would be a better solution. On
the other hand, if tuples grew list methods and we got a new immutable
sequence that had order, unpacking, and *named fields* along the lines
of Pascal records I'd be happy with that too.
In regard to unpacking binary data and similar uses, those are
often perfomance sensitive, here is some benchmark data from
timeit.Timer on looking for an item in a list/tuple via list.index() or
list(tuple).index(). The best case scenario (short list) takes about a
20% performance hit.
run time (sec)
size runs list tuple ratio (t/l)
1000000 100 1.997614 5.526909 2.766755
100000 1000 2.049710 5.291704 2.581684
10000 10000 1.970400 2.714083 1.377428
1000 100000 2.325089 3.013624 1.296133
100 1000000 6.213748 7.661165 1.232938
10 10000000 44.970536 53.685698 1.193797
For whatever it's worth, I'm mildly in favor of index() and count() being
added to tuples.
Mike
--
Michael Zawrotny
Institute of Molecular Biophysics
Florida State University | email: zawr...@sb.fsu.edu
Tallahassee, FL 32306-4380 | phone: (850) 644-0069
To me? No. Is it reasonable to believe it could happen? Yes. Is it
reasonable to say, "We don't think this is likely to happen often, so we
won't provide a simple way to deal with it?" Well, I'm not a developer,
so it's not my decision.
---
-Bill Hamilton
wha...@entergy.com
But as far as I understood the code is already there; the code for
list.index being usable almost as it is.
It doesn't seem to be a question of where to put valuable resource.
AFAIU it is simply a question of do the developers want it or not.
--
Antoon Pardon
Why then does python itself provide immutables? I find this reasoning
more than baffling. There has been all these arguments about why
it is best to use immutables as dictionary keys. But the moment
the topic changes, someone else comes with the comment that
wanting your sequence to be immuatble is unpythonic.
I once had a problem I like to solve by having a dictionary
where the keys were multidimensional points on an integer grid.
For a number of reasons I thought it would be easier if I could
use lists, but most people argued that would be a bad idea and
that I should use tuples, because they are immutable.
Of course if I now would want to find out if the point is on an
axis and which axis that is, I cannot use index because that is
not available.
--
Antoon Pardon
Well I think this illustrates nicely what can happen if you design by
use cases.
Let us assume for a moment that finding out if one list is a sublist of
a second list gets considered something usefull enough to be included
in Python. Now the in operator can't be used for this because it
would create ambiguities. So it would become either a new operator
or a new method. But whatever the solution it would be different
from the string solution.
Now if someone would have thought about how "st1 in st2" would
generalize to other sequemce if st1 contained more than one
character they probably would have found the possible inconsistency
that could create and though about using an other way than using
the in-operator for this with strings. A way that wouldn't create
ambiguities when it was considered to be extended to other sequences.
--
Antoon Pardon
You've answered your own question. If you had a mutable dictionary
key, stored something in a dictionary using that key, then modified
the key and tried to retrieve the stored item using that same key
object, you might never find that item again. This is something of a
simplification (you'd have to look into details of things like
__hash__ and __eq__, I imagine), but this is just one area where
immutability is central to the operation of the feature concerned.
Other languages provide some control over immutability with things
like "const", and there are good reasons for having such things,
although you do need to know what you're doing as a programmer when
using them. Some people might argue that the dictionary key example
given above is contrived: "Of course it won't work if you modify the
key!" they might say. Having some idea of which objects are immutable
can provide some protection from inadvertent mutation, however.
> But the moment the topic changes, someone else comes with the comment that
> wanting your sequence to be immuatble is unpythonic.
As soon as "unpythonic" is mentioned we enter subjective territory.
Paul
Well since it was meant as a rethorical question that is hardly
surprising. But may be I should work harder on my rethorical
skill since you missed that.
--
Antoon Pardon
> Now if someone would have thought about how "st1 in st2" would
> generalize to other sequemce if st1 contained more than one
> character they probably would have found the possible inconsistency
> that could create and though about using an other way than using
> the in-operator for this with strings. A way that wouldn't create
> ambiguities when it was considered to be extended to other sequences.
>
The fact is that strings are the only sequences composed of subsequences
of length 1 - in other words the only sequences where type(s) ==
type(s[0:1]) is an invariant condition.
This was discussed (at my instigation, IIRC) on python-dev when Python
(2.4?) adopted the enhanced semantics for "in" on strings - formerly
only tests for single characters were allowed - but wasn't thought
significant enough to deny what was felt to be a "natural" usage for
strings only.
regards
Steve
--
Steve Holden +44 150 684 7255 +1 800 494 3119
Holden Web LLC/Ltd http://www.holdenweb.com
Skype: holdenweb http://del.icio.us/steve.holden
Recent Ramblings http://holdenweb.blogspot.com
> Now if someone would have thought about how "st1 in st2" would
> generalize to other sequemce if st1 contained more than one
> character they probably would have found the possible inconsistency
> that could create and though about using an other way than using
> the in-operator for this with strings. A way that wouldn't create
> ambiguities when it was considered to be extended to other sequences.
>
Yes this allows you to do some things for strings in a way that would
be impossible or ambiguous should you want to do the same things for
other kind of sequences.
The question is: should you?
if you want to provide new functionality for strings and you have
the choice between doing it
1) in a way, that will make it easy to extend this functionality
in a consistent way to other sequences
2) in a way that will make it impossible to extend this functionality
in a consistent way to other sequences.
then I think that unless you have very good arguments you should pick (1).
Because if you pick (2) even if this functionality is never extened in
the language itself, you make it more difficult for programmers to add
this functionality in a consistent way to a subclass of list themselves.
People are always defending duck-typing in this news group and now python
has chosen to choose the option that makes duck-typing more difficult.
> This was discussed (at my instigation, IIRC) on python-dev when Python
> (2.4?) adopted the enhanced semantics for "in" on strings - formerly
> only tests for single characters were allowed - but wasn't thought
> significant enough to deny what was felt to be a "natural" usage for
> strings only.
Which I consider a pity.
--
Antoon Pardon
Au contraire! The "inconsistent" behavior of "in" is precisely what
duck-typing is all about: Making the operator behave in a way that makes
sense in its context. Nobody seems to be complaining about "+" behaving
"inconsistently" depending on whether you're adding numbers or
sequences.
-Carsten
We can learn a bit from the D language too, it uses ~ for array/string
concatenation, look for the "Array Concatenation" here:
http://www.digitalmars.com/d/arrays.html
Bye,
bearophile
As I said:
I doubt that *anyone* who programs in Python
has not encountered the situation where they change
a tuple to a list *solely* for the purpose of getting
access to the index method. This suggests a missing
method, does it not? Who has not done this?
Name yourself!
There is simply no conflict between the index method and immutability,
but at the moment one is forced to choose. Why? Nobody has
offered a real explanation of this.
I offered a simple use case. Consider a game,
where the *fixed* set p of players have a *fixed* order.
A tuple is natural. Now for a player you want to
construct the opponents. If I had the index i it wd
be p[:i]+p[i+1:], but how to get the index?
Other use cases have also been offered on this thread.
What is the basic response? "Do not worry about the
loss of immutability, just use a list." What kind of a
response is that?? This sounds to me like "I do not
really see the point of immutability", which is no
response at all.
Cheers,
Alan Isaac
Sure. I have never done this. In fact, I have only ever written code
that converted a tuple to a list once, and it was because I wanted
pop(), not index() - I had a varargs argument that iterated over it's
argument list and need to know how many arguments it had consumed, and
how many were left, in order to correctly process the current
argument. Using a list was (very) slightly more convenient for this
than counting. Note that because I needed to preserve the original
argument to compare against, *args being a list wouldn't have changed
the way I wrote it even if it was technically feasible to implement it
as one.
> There is simply no conflict between the index method and immutability,
> but at the moment one is forced to choose. Why? Nobody has
> offered a real explanation of this.
>
There have been many. The answer is, in the cases where you need
immutability, you don't need index, because an immutable structure is
either unordered, so index doesn't matter, or ordered, and the order
is then part of the structure.
> I offered a simple use case. Consider a game,
> where the *fixed* set p of players have a *fixed* order.
> A tuple is natural. Now for a player you want to
> construct the opponents. If I had the index i it wd
> be p[:i]+p[i+1:], but how to get the index?
>
I would never use a tuple for this case, I would use a list. And even
using the list, I wouldn't use index() to find the current player. I'd
get the other players via a list comp (as shown previously in the
thread) or I'd be iterating through the player list and I'd already
have the other players. I find the solution you posted to be poor and
if tuple not having index() has *no other effect* than to discourage
the writing of code in this style I'd consider the decision justified.
Depending on the exact game play, almost any data structure *except* a
tuple would be a better solution.
> Other use cases have also been offered on this thread.
I, for one, have found none of them compelling and have said why I
don't find them compelling. There is one which I think is reasonable.
Manually searching the tuple or conversion to a list addresses that
use case, which I don't expect to be common.
> What is the basic response? "Do not worry about the
> loss of immutability, just use a list." What kind of a
> response is that?? This sounds to me like "I do not
> really see the point of immutability", which is no
> response at all.
>
How about "explain why you find immutability necessary in this
context. If you can't explain it, then don't worry about".
> Cheers,
> Alan Isaac