473,408 Members | 1,951 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,408 software developers and data experts.

"index" method only for mutable sequences??

I was looking for a function or method that would return the index to the first
matching element in a list. Coming from a C++ STL background, I thought it might
be called "find". My first stop was the Sequence Types page of the Library
Reference (http://docs.python.org/lib/typesseq.html); it wasn't there. A search
of the Library Reference's index seemed to confirm that the function did not
exist. A little later I realized it might be called "index" instead. Voila.

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
Apr 6 '07
122 5394
Paul Boddie wrote:
On 10 Apr, 11:48, Antoon Pardon <apar...@forel.vub.ac.bewrote:
>On 2007-04-10, Duncan Booth <duncan.bo...@invalid.invalidwrote:
>>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"

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.
A generic definition of index would be tricky, though, if you wanted to
include strings as sequences. In that case you aren't testing for the
presence of a single element but a sub-sequence - I think this change
was introduced in 2.4 to allow checks like

"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

Apr 10 '07 #51
On Tue, 2007-04-10 at 13:21 +0000, Antoon Pardon wrote:
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.
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
Apr 10 '07 #52
On Tue, 2007-04-10 at 09:57 -0400, Steve Holden wrote:
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!
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
Apr 10 '07 #53
On 10 Apr, 15:57, Steve Holden <s...@holdenweb.comwrote:
>
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.
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

Apr 10 '07 #54
Carsten Haese wrote:
On Tue, 2007-04-10 at 09:57 -0400, Steve Holden wrote:
>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!

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.
I quite agree. I was not advocating it as a serious course of action,
more admiring its noise-reduction potential. I'm no great fan of the if
.... else expression either, come to that.

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

Apr 10 '07 #55
On 4/10/07, Carsten Haese <ca*****@uniqsys.comwrote:
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.
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
Apr 10 '07 #56
On 4/10/07, Steve Holden <st***@holdenweb.comwrote:
Paul Boddie wrote:
On 10 Apr, 11:48, Antoon Pardon <apar...@forel.vub.ac.bewrote:
On 2007-04-10, Duncan Booth <duncan.bo...@invalid.invalidwrote:

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"
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.
A generic definition of index would be tricky, though, if you wanted to
include strings as sequences. In that case you aren't testing for the
presence of a single element but a sub-sequence - I think this change
was introduced in 2.4 to allow checks like

"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'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
Apr 10 '07 #57
Paul Boddie wrote:
On 10 Apr, 15:57, Steve Holden <s...@holdenweb.comwrote:
>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.

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.
You can call something non-controversial when it generates a thread like
this? :-) It's really a storm in a teacup. The acid test would be to
generate a patch that added the method and then see if you could get a
committer to commit it. All else (including my own contributions) is
mere hot air.
>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().

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

Apr 10 '07 #58
On Tue, 2007-04-10 at 17:10 +0200, BJörn Lindqvist wrote:
On 4/10/07, Carsten Haese <ca*****@uniqsys.comwrote:
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.

Your alternative is wrong because it wont raise ValueError if
current_player is not present in the tuple. Please revise your
"solution."
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
Apr 10 '07 #59
On Tue, 2007-04-10 at 11:44 -0400, Carsten Haese wrote:
On Tue, 2007-04-10 at 17:10 +0200, BJörn Lindqvist wrote:
On 4/10/07, Carsten Haese <ca*****@uniqsys.comwrote:
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.
Your alternative is wrong because it wont raise ValueError if
current_player is not present in the tuple. Please revise your
"solution."

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.
_.replace("IndexError", "ValueError"), of course.

-Carsten
Apr 10 '07 #60
On 10 Apr, 17:29, Steve Holden <s...@holdenweb.comwrote:
>
You can call something non-controversial when it generates a thread like
this? :-) It's really a storm in a teacup. The acid test would be to
generate a patch that added the method and then see if you could get a
committer to commit it. All else (including my own contributions) is
mere hot air.
The patch is already submitted:

http://sourceforge.net/tracker/index...70&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

Apr 10 '07 #61
On 10 Apr, 17:44, Carsten Haese <cars...@uniqsys.comwrote:
>
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.
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

Apr 10 '07 #62
On 2007-04-10, Carsten Haese <ca*****@uniqsys.comwrote:
On Tue, 2007-04-10 at 13:21 +0000, Antoon Pardon wrote:
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.

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.
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
Apr 10 '07 #63
BJörn Lindqvist:
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'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.
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

Apr 10 '07 #64
On 4/10/07, Carsten Haese <ca*****@uniqsys.comwrote:
opponents = tuple(x for x in p if x is not current_player)
>
Your alternative is wrong because it wont raise ValueError if
current_player is not present in the tuple. Please revise your
"solution."

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.
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
Apr 10 '07 #65
On Tue, 2007-04-10 at 19:21 +0200, BJörn Lindqvist wrote:
On 4/10/07, Carsten Haese <ca*****@uniqsys.comwrote:
opponents = tuple(x for x in p if x is not current_player)

Your alternative is wrong because it wont raise ValueError if
current_player is not present in the tuple. Please revise your
"solution."
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.

Assertions are not checked when you run scripts with -O.
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
Apr 10 '07 #66
On 4/10/07, Carsten Haese <ca*****@uniqsys.comwrote:
On Tue, 2007-04-10 at 19:21 +0200, BJörn Lindqvist wrote:
On 4/10/07, Carsten Haese <ca*****@uniqsys.comwrote:
opponents = tuple(x for x in p if x is not current_player)
>
Your alternative is wrong because it wont raise ValueError if
current_player is not present in the tuple. Please revise your
"solution."
>
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.
Assertions are not checked when you run scripts with -O.

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)
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.
Apr 10 '07 #67
while not game_has_ended:
for current_player in p:
player_does_something(current_player)

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
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
Apr 10 '07 #68

"BJörn Lindqvist" <bj*****@gmail.comwrote in message
news:74******************************************@ mail.gmail.com...
On 4/10/07, Steve Holden <st***@holdenweb.comwrote:
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.
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

Apr 11 '07 #69

"Paul Boddie" <pa**@boddie.org.ukwrote in message
news:11*********************@o5g2000hsb.googlegrou ps.com...
| 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.

No mystery. It was Guido's initial proposal and he never changed his mind.

Apr 11 '07 #70
Carsten Haese <ca*****@uniqsys.comwrites:
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)
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.
Apr 11 '07 #71
On Tue, 2007-04-10 at 21:23 -0700, Paul Rubin wrote:
Carsten Haese <ca*****@uniqsys.comwrites:
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)

Still wrong on two counts. First, assert is a no-op if optimization
is turned on.
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
Apr 11 '07 #72
"Carsten Haese" <ca*****@uniqsys.comwrote:

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
Apr 11 '07 #73
On 10 Apr, 20:04, "Chris Mellon" <arka...@gmail.comwrote:
>
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.
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

Apr 11 '07 #74
On Wed, 11 Apr 2007 08:57:43 +0200, Hendrik van Rooyen wrote:
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.

Apr 11 '07 #75
On 2007-04-11, Steven D'Aprano <st***@REMOVE.THIS.cybersource.com.auwrote:
On Wed, 11 Apr 2007 08:57:43 +0200, Hendrik van Rooyen wrote:
>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')
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
Apr 11 '07 #76
In <sl********************@rcpc42.vub.ac.be>, Antoon Pardon wrote:
On 2007-04-11, Steven D'Aprano <st***@REMOVE.THIS.cybersource.com.auwrote:
>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. 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.
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
Apr 11 '07 #77
On 2007-04-11, Marc 'BlackJack' Rintsch <bj****@gmx.netwrote:
In <sl********************@rcpc42.vub.ac.be>, Antoon Pardon wrote:
>On 2007-04-11, Steven D'Aprano <st***@REMOVE.THIS.cybersource.com.auwrote:
>>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. 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.

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.
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
Apr 11 '07 #78
On 4/11/07, Hamilton, William <wh*****@entergy.comwrote:
-----Original Message-----
From: py*************************************@python.org
[mailto:python-
li******************************@python.org] On Behalf Of Steven
D'Aprano
Sent: Wednesday, April 11, 2007 7:49 AM
To: py*********@python.org
Subject: Re: tuples, index method, Python's design

(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.

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.
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?
Apr 11 '07 #79
On 4/10/07, BJörn Lindqvist <bj*****@gmail.comwrote:
while not game_has_ended:
for current_player in p:
player_does_something(current_player)
>
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

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?
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.
Apr 11 '07 #80
On Wed, 11 Apr 2007 13:13:20 +0000, Antoon Pardon wrote:
>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.

Apr 11 '07 #81
On 11 Apr, 16:14, "Chris Mellon" <arka...@gmail.comwrote:
>
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.
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

Apr 11 '07 #82
On 11 Apr 2007 08:37:39 -0700, Paul Boddie <pa**@boddie.org.ukwrote:
On 11 Apr, 16:14, "Chris Mellon" <arka...@gmail.comwrote:

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.

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:
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.
Apr 11 '07 #83
On Wed, 11 Apr 2007 10:57:19 -0500, Chris Mellon <ar*****@gmail.comwrote:
>
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.
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: za******@sb.fsu.edu
Tallahassee, FL 32306-4380 | phone: (850) 644-0069
Apr 11 '07 #84
On 2007-04-11, Steven D'Aprano <st***@REMOVE.THIS.cybersource.com.auwrote:
>
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?
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
Apr 12 '07 #85
On 2007-04-11, Chris Mellon <ar*****@gmail.comwrote:
On 11 Apr 2007 08:37:39 -0700, Paul Boddie <pa**@boddie.org.ukwrote:
>On 11 Apr, 16:14, "Chris Mellon" <arka...@gmail.comwrote:
>
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.

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:

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.
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
Apr 12 '07 #86
On 2007-04-11, Terry Reedy <tj*****@udel.eduwrote:
>
"BJrn Lindqvist" <bj*****@gmail.comwrote in message
news:74******************************************@ mail.gmail.com...
On 4/10/07, Steve Holden <st***@holdenweb.comwrote:
>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.

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.
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
Apr 12 '07 #87
On 12 Apr, 09:37, Antoon Pardon <apar...@forel.vub.ac.bewrote:
>
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.
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

Apr 12 '07 #88
On 2007-04-12, Paul Boddie <pa**@boddie.org.ukwrote:
On 12 Apr, 09:37, Antoon Pardon <apar...@forel.vub.ac.bewrote:
>>
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.

You've answered your own question.
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
Apr 12 '07 #89
Antoon Pardon wrote:
On 2007-04-11, Terry Reedy <tj*****@udel.eduwrote:
>"BJrn Lindqvist" <bj*****@gmail.comwrote in message
news:74****************************************** @mail.gmail.com...
On 4/10/07, Steve Holden <st***@holdenweb.comwrote:
>>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.
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.

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.
That's because strings are different from other sequences. See below.
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

Apr 12 '07 #90
Antoon Pardon wrote:
On 2007-04-11, Terry Reedy <tj*****@udel.eduwrote:
>"BJrn Lindqvist" <bj*****@gmail.comwrote in message
news:74****************************************** @mail.gmail.com...
On 4/10/07, Steve Holden <st***@holdenweb.comwrote:
>>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.
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.

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.
That's because strings are different from other sequences. See below.
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

Apr 12 '07 #91
On 2007-04-12, Steve Holden <st***@holdenweb.comwrote:
Antoon Pardon wrote:
>On 2007-04-11, Terry Reedy <tj*****@udel.eduwrote:
>>"BJrn Lindqvist" <bj*****@gmail.comwrote in message
news:74***************************************** *@mail.gmail.com...
On 4/10/07, Steve Holden <st***@holdenweb.comwrote:
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.
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.

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.
That's because strings are different from other sequences. See below.
>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.
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
Apr 12 '07 #92
On Thu, 2007-04-12 at 14:10 +0000, Antoon Pardon wrote:
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.
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
Apr 12 '07 #93
Carsten Haese:
Nobody seems to be complaining about "+" behaving
"inconsistently" depending on whether you're adding numbers or
sequences.
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

Apr 12 '07 #94
On Thu, 12 Apr 2007 07:37:38 +0000, Antoon Pardon wrote:
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.
Also because code that raises "TypeError: list objects are unhashable" is
probably not going to work very well.

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.
If memory is more important to you than speed:

class IndexTuple(tuple):
def index(self, target):
for i, x in enumerate(self):
if x == target: return i
raise ValueError

Or if speed is more important to you than memory:

class IndexTuple2(tuple):
def index(self, target):
return list(self).index(target)

If you prefer not to subclass, you can write an index function:

def index(sequence_or_mapping, target):
try:
return sequence_or_mapping.index(target)
except AttributeError:
return list(sequence_or_mapping).index(target)
So much fuss over such a little thing... yes it would be nice if tuples
grew an index method, but it isn't hard to work around the lack.

--
Steven.

Apr 12 '07 #95
In article <sl********************@rcpc42.vub.ac.be>,
Antoon Pardon <ap*****@forel.vub.ac.bewrote:
On 2007-04-11, Marc 'BlackJack' Rintsch <bj****@gmx.netwrote:
In <sl********************@rcpc42.vub.ac.be>, Antoon Pardon wrote:
On 2007-04-11, Steven D'Aprano <st***@REMOVE.THIS.cybersource.com.au>
wrote:
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. 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.
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.

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.
Well, yes - consider for example the "tm" tuple returned
from time.localtime() - it's all integers, but heterogeneous
as could be - tm[0] is Year, tm[1] is Month, etc., and it
turns out that not one of them is alike. The point is exactly
that we can't discover these differences from the items itself -
so it isn't about Python types - but rather from the position
of the item in the struct/tuple. (For the person who is about
to write to me that localtime() doesn't exactly return a tuple: QED)

Donn Cave, do**@u.washington.edu
Apr 12 '07 #96
On 2007-04-12, Carsten Haese <ca*****@uniqsys.comwrote:
On Thu, 2007-04-12 at 14:10 +0000, Antoon Pardon wrote:
>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.

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.
No it isn't. Ducktyping is about similar objects using a similar
interface to invoke similar behaviour and getting similar result.

So that if you write a function you don't concern yourself with
the type of the arguments but depend on the similar behaviour.

Suppose someone writes a function that acts on a sequence.
The algorithm used depending on the following invariant.

i = s.index(e) =s[i] = e

Then this algorithm is no longer guaranteed to work with strings.
On the other hand I subclass list and add a sub method
to check for the argument being a sublist of the object.
Now I write a function that depends on this functionality.
But although strings have the functionality I can't use
them as argument because the functionality is invoked
in a different way.
Nobody seems to be complaining about "+" behaving
"inconsistently" depending on whether you're adding numbers or
sequences.
You are wrong. I already mentioned problems with it. The
problem is that there are structures that are numbers and
sequences at the same time. So I have a choice. Either I
overload the "+" to get an addition or to get a concatanation.

In the first case I can't trust my structure to work with
functions that expect a general sequence because they
may depend on the fact that "+" concatenates. In the
other case I can't trust my structure to work with
numbers because they may depend on the fact that "+"
behaves like an addition.

--
Antoon Pardon
Apr 13 '07 #97
On 2007-04-12, Steven D'Aprano <st***@REMOVE.THIS.cybersource.com.auwrote:
On Thu, 12 Apr 2007 07:37:38 +0000, Antoon Pardon wrote:
>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.

Also because code that raises "TypeError: list objects are unhashable" is
probably not going to work very well.

>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.

If memory is more important to you than speed:

class IndexTuple(tuple):
def index(self, target):
for i, x in enumerate(self):
if x == target: return i
raise ValueError

Or if speed is more important to you than memory:

class IndexTuple2(tuple):
def index(self, target):
return list(self).index(target)

If you prefer not to subclass, you can write an index function:

def index(sequence_or_mapping, target):
try:
return sequence_or_mapping.index(target)
except AttributeError:
return list(sequence_or_mapping).index(target)
So much fuss over such a little thing... yes it would be nice if tuples
grew an index method, but it isn't hard to work around the lack.
Yes it is a little thing. But if it is such a little thing why do
the developers don't simply add it?

Python like any other human product has it shortcomings. I can live
with them. If a wart turns up and the general answer would be, yes
we know it is a wart but it is the result of how python grew or
it was the best compromise we could think of and too much depends
on it now to change it. This kind of threads would die quickly.

Instead we often enough see the warts getting defended as good design.

--
Antoon Pardon
Apr 13 '07 #98
On Fri, 13 Apr 2007 07:46:58 +0000, Antoon Pardon wrote:
>So much fuss over such a little thing... yes it would be nice if tuples
grew an index method, but it isn't hard to work around the lack.

Yes it is a little thing. But if it is such a little thing why do
the developers don't simply add it?
Perhaps because they've got better things to do than spend all their time
adding little things that are the work of thirty seconds for a developer
like yourself to create when you need it.
--
Steven.

Apr 13 '07 #99
Antoon Pardon wrote:
On 2007-04-12, Carsten Haese <ca*****@uniqsys.comwrote:
>On Thu, 2007-04-12 at 14:10 +0000, Antoon Pardon wrote:
>>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.
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.

No it isn't. Ducktyping is about similar objects using a similar
interface to invoke similar behaviour and getting similar result.

So that if you write a function you don't concern yourself with
the type of the arguments but depend on the similar behaviour.
Please note that "similar" does not mean "exact".

The behavior of str.__contains__ and list.__contains__ is similar.

Duck-typing allows natural access to polymorphism. You appear to be
making semantic distinctions merely for the sake of continuing this
rather fatuous thread.
Suppose someone writes a function that acts on a sequence.
The algorithm used depending on the following invariant.

i = s.index(e) =s[i] = e

Then this algorithm is no longer guaranteed to work with strings.
Because strings have different properties than other sequences. I can't
help pointing out that your invariant is invalid for tuples also,
because tuples don't have a .index() method.
>
On the other hand I subclass list and add a sub method
to check for the argument being a sublist of the object.
Now I write a function that depends on this functionality.
But although strings have the functionality I can't use
them as argument because the functionality is invoked
in a different way.
>Nobody seems to be complaining about "+" behaving
"inconsistently" depending on whether you're adding numbers or
sequences.

You are wrong. I already mentioned problems with it. The
problem is that there are structures that are numbers and
sequences at the same time. So I have a choice. Either I
overload the "+" to get an addition or to get a concatanation.

In the first case I can't trust my structure to work with
functions that expect a general sequence because they
may depend on the fact that "+" concatenates. In the
other case I can't trust my structure to work with
numbers because they may depend on the fact that "+"
behaves like an addition.
Good grief.
--
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

Apr 13 '07 #100

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: kim | last post by:
Scenario (I'm a newbie): I have a datagrid with countries listed and 5 parameters in each row. I want to add a row to this datagrid via an Event Handler. Very basic stuff. This method then call a...
2
by: Tor Inge Rislaa | last post by:
Name of "index.aspx" Hi I have just published my first ASP.NET home page, but as I always does with HTML (index.htm) files I named the first webform to appear on the domain index.aspx but It...
1
by: Clark Choi | last post by:
I ran the sample application called Petstore from msdn. Everything went fine until I tested Update button on the web form to update the database through Datagrid. I have been searching the web to...
1
by: Dave | last post by:
I'm getting the following error on an EditCommand event. This code is running on production web farm and the thing is it doesn't happen all the time. If I get this error, click the back button,...
4
by: Antoine | last post by:
Herfried and Cor:- I used tracing and actually tracked down the code that was causing the problem most likely. I wonder if you wanted to comment on it. Also I wonder if there is a better way...
15
by: bill | last post by:
I am trying to write clean code but keep having trouble deciding when to quote an array index and when not to. sometimes when I quote an array index inside of double quotes I get an error about...
5
by: Pseudonyme | last post by:
Dear All : Ever had an httpd error_log bigger than the httpd access log ? We are using Linux-Apache-Fedora-Httpd 2006 configuration. The PHP lines code that lead too tons of errors are : ...
1
BeemerBiker
by: BeemerBiker | last post by:
Using GridView and SqlDataSource I found that an index field defaults to "ReadOnly=True" and I have to change it to False and then hide it before my sql UPDATE command works. This seems awkward and...
0
BeemerBiker
by: BeemerBiker | last post by:
I was wondering if a command like "SqlDataSource1.insert()" can somehow give me the new index that was created when the insert took place. If the insert always occurs at the end of the dataset then...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.