469,310 Members | 2,445 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,310 developers. It's quick & easy.

General question about Python design goals

Sometimes I find myself stumbling over Python issues which have to do
with what I perceive as a lack of orthogonality.

For instance, I just wanted to use the index() method on a tuple which
does not work. It only works on lists and strings, for no obvious
reason. Why not on all sequence types?

Or, another example, the index() method has start and end parameters for
lists and strings. The count() method also has start and end parameters
for strings. But it has no such parameters for lists. Why?

However when I ask such things I noticed I get answers like: "Is there a
use case?" "You can do it some other way so it is not worth bothering."

Let me ask back: Do I really need to bother and justify it with a use
case in a case where the language can be easily made more consistent or
orthogonal without breaking anything?

What about design goals such as:

- orthogonality
- coherence, consistency
- principle of least astonishment ("Python fits my brain")
- simplicity ("kiss" principle)
- aesthetics, symmetry

Actually, which priority have the above design goals for Python? Are
other design goals considered more important?

If I compare them with the "Zen of Python", I find some of the above:

consistency -> Special cases aren't special enough to break the rules
simplicity -> Simple is better than complex
aesthetics -> Beautiful is better than ugly

Actually, concerning the last two, you already need to understand the
Zen of Python to decide if something is "simple" or even "beautiful", so
they are not really suitable to *define* the Zen of Python. For me, a
programming language is beautiful if it is orthogonal and coherent. But
for others, this may be different. Somehow, I'm missing a direct
allusion to the following in the Zen of Python:

- orthogonality
- principle of least astonishment

Maybe I am I lacking the satori of a real Python Zen master?

-- Christoph
Nov 28 '05
105 4700
On 2005-11-29, Bengt Richter <bo**@oz.net> wrote:
On 29 Nov 2005 08:27:43 GMT, Antoon Pardon <ap*****@forel.vub.ac.be> wrote:
On 2005-11-28, Duncan Booth <du**********@invalid.invalid> wrote:
Antoon Pardon wrote:
No I gave an example, you would implement differently. But even
if you think my example is bad, that would make it a bad argument
for tuples having list methods. That is not the same as being
a good argument against tuples having list methods.

Tuples don't have list methods, therefore any code which seems to require a
tuple with list methods should make you stop and consider whether your
design is wrong.
IMO that is a non-sequitur, because that makes what is good or bad
design dependand on the language used.

If I have a design that seems to require tuples with a count method,
then wether that is a good or bad design doesn't depend on
whether or not python allows that or not.

No, but if your requirement is to count __eq__ - matching items in a
tuple, maybe your sense of orthogonality ought to abstract out the
sequence aspect in some other way than seeing it as a seeming method
requirement for tuple. A tuple.count method has implications about
attribute access to a special object, tuple, which then you have
to deal with for every new object you introduce, unless you want to
inherit it from object, but that means object becomes a
mega swiss army knife in short order.


I'm open too other possibilties, and I'm interrested in your iterator
methods. It is just that on the one hand people talk about the
advantages of tuples as keys, (no need to copy the keys, since
they are immutable) while on the other hand when tuples lack
some functionality tell me to cast them as lists, completely
eliminating the adavantage tuples have.
So IMO the thing is not to ask for a specific solution like "why
not a count method for tuples?" You'll just get answers to that literal
question, with some elaborations. Instead, if you put it in the form
of what your general requirement really is (I'm guessing ;-) which I
assume is to be able to apply list count method _functionality_ to
anything which quacks like a list, including tuples etc. In short,
anything iterable.
Sure, A base sequence type, from which tuples and lists would inherit
that would provide for this functionality would be good too. Of
course it isn't that difficult to write a general function that works
on any iterable either.
Now the problem is to bring program and data together with some
spelling in python. data.method() is certainly one spelling, but
so is method(data). You gain something either way. The first allows
you to associate the method and data without executing the method, i.e.,
data.method is a bound method object that has the data-method association
built in, and it can be passed around.
There are other ways to get a bound method like object, so I don't
consider that a big advantage.
method(data) does the call right
away and uses a diferent name space search path to find method, and is
not necessarily associated with type(data). To ask for common methods
for all objects that exhibit some similar aspect is to entangle their
types in some way or to duplicate stuff. Sometimes it's fine to
derive from a common base etc., but

why not a built-in count function that does something like (untested)

def count(obj, match_item, eq=operator.eq):
return sum(1 for item in iter(obj) if eq(item, match_item))
Sure. The problem here is a bit about python only providing a partial
solution. If python didn't provide any count methods I think nobody
would have complained. If you needed this, you could easily provide
it your self.

But now python does provide it, but not for all classes it seems
applyable to, so people question why.
which would give a little flexibility about eq comparison as well as
wide applicability to any sequence? index too (untested)

def index(obj, match_item, eq=operator.eq):
try: return (i for i, item in enumerate(obj) if eq(item, match_item)).next()
except StopIteration: raise ValueError('index(seq, item): item not in seq')

why doesn't list have a find like str? ;-)

def find(obj, match_item, eq=operator.eq):
try: return (i for i, item in enumerate(obj) if eq(item, match_item)).next()
except StopIteration: return -1

One could create an alternate spelling for obj.count(thing) using the count function above.
You can spell it now as

count.__get__(obj, type(obj))(thing)

if you want to duplicate the effect of having the count function retrieved from type(obj)
as if it were a method defined there. Or you can spell it

count(obj)

which doesn't seem too bad ;-)
But now the problem is cluttering the __builtins__ space. So maybe it would be
better to write
from sequence_goodies import count
...
count(obj)
Sure, thanks for the suggestion, I think I'll write me a sequence module
with these and similar function. It seems just a bit stupid, because
once I wrote all of these, a number of list methods seem just a waste
that is to be carried along.
Do you really want a count method for tuple? Or is that maybe not as clean is
it seemed? All the issues aren't usually immediatly apparent, so IMO the more
we focus on abstract functionality desired, the more likely we will get
helpful solution ideas for a menu of choices, and avoid prematurely discussing
whether we should have pumpkin pie with or without whipped cream, when finally
we might all like strawberries and cream better, if someone had thought of it.


Well my preferred solution, would have been if sequence had been a mixin
class, that would provide a number of methods for subclasses that
provide the right protocol and then tuple and list being such a
subclass. I think that would have been more pythonic than your suggested
solution, but I think your suggestion is a valuable alternative.

--
Antoon Pardon
Nov 30 '05 #51
Paul Rubin <http://ph****@NOSPAM.invalid> writes:
Mike Meyer <mw*@mired.org> writes:
> An awful lot of the time in this newsgroup, "practicality beats
> purity" translates as "the programmer can just be a lazy slob". You post that as if it were a bad thing.

Yes. The idea of using a program that someone else wrote, is that
they do the work so I don't have to. If their doing less work means
that I have to do more, the program isn't as good as it might be.


No, it's not as good *for your purpose* as it might be. But they
didn't write it for your purpose, they wrote it for theirs. The latter
is really the only standard of judgement.
A program like Python intended for wide distribution and use by large
numbers of people whose needs aren't known in advance, should do as
much to help its users as development resources allow.
True. You seem to disagree about how they choose to allocate the
resources. The fix for that is well-known.
Are you familiar with R. Gabriel's piece "Worse is better"? That's
not what I see "practicality beats purity" as being intended to mean.
Why not? That seems to summarise a couple of the points in the more
successful design philosophy, most notably:

The design most not be overly inconsistent.
The design must cover as many important situations as is practical.

If these don't reflet what you think "Practicality beats purity"
means, then what do you think it means?

Actually, I've been thinking about that bit recently, and noting that
a number of things from "import this" seem to espouse the more
successful approach from that section:

Simple is better than complex.
Complex is better than complicated.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
> If following POLA costs that much, at least in the kinds of examples
> we talk about all the time here, something is probably wrong with the
> implementation (or the design) to begin with.

True, but not constructive. Knowing that something is wrong is
easy. Diagnosing the problem is harder. Curing it is even harder.

Look at the list.count() example at the start of this thread.
Diagnosing it isn't hard. Curing it isn't hard. It doesn't bloat
Python by an order of magnitude.


Did somebody actually use "Practicality beats purity" as an excuse for
not making list.count and string.count have the same arguments? If so,
I missed it. I certainly don't agree with that - count ought to work
right in this case.
A suitably factored implementation might handle lists and strings
with the exact same code and not incur any extra cost at all. That
type of thing happens all the time here.


If it happens all the time, you shouldn't have any trouble nameing a
number of things that a majority of users think are misfeatures that
aren't being fixed. Could you do that?

<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Nov 30 '05 #52
bo****@gmail.com wrote:
Paul Rubin wrote:
Look at the list.count() example at the start of this thread.
Diagnosing it isn't hard. Curing it isn't hard. It doesn't bloat
Python by an order of magnitude. A suitably factored implementation
might handle lists and strings with the exact same code and not incur
any extra cost at all. That type of thing happens all the time here.


I believe the language creator use the "lack of" as a way to
prevent/discourage that kind of usage. Just like the ternary
operator(still don't know why it is finally accepted). It is not a
problem(not having), it is a feature(to teach you program better), so
what cure are we talking about ?


Sorry, but I still do not get it. Why is it a feature if I cannot count
or find items in tuples? Why is it bad program style if I do this? So
far I haven't got any reasonable explanation and I think there is no.

-- Christoph
Nov 30 '05 #53

Christoph Zwerschke wrote:
bo****@gmail.com wrote:
Paul Rubin wrote:
Look at the list.count() example at the start of this thread.
Diagnosing it isn't hard. Curing it isn't hard. It doesn't bloat
Python by an order of magnitude. A suitably factored implementation
might handle lists and strings with the exact same code and not incur
any extra cost at all. That type of thing happens all the time here.


I believe the language creator use the "lack of" as a way to
prevent/discourage that kind of usage. Just like the ternary
operator(still don't know why it is finally accepted). It is not a
problem(not having), it is a feature(to teach you program better), so
what cure are we talking about ?


Sorry, but I still do not get it. Why is it a feature if I cannot count
or find items in tuples? Why is it bad program style if I do this? So
far I haven't got any reasonable explanation and I think there is no.

I have no idea, I can understand their view, not necessarily agree. And
reasonable explanation is not something I usually find on this group,
for issues like this.

Dec 1 '05 #54
On 11/30/05, Christoph Zwerschke <ci**@online.de> wrote:
bo****@gmail.com wrote:
Paul Rubin wrote:
Look at the list.count() example at the start of this thread.
Diagnosing it isn't hard. Curing it isn't hard. It doesn't bloat
Python by an order of magnitude. A suitably factored implementation
might handle lists and strings with the exact same code and not incur
any extra cost at all. That type of thing happens all the time here.


I believe the language creator use the "lack of" as a way to
prevent/discourage that kind of usage. Just like the ternary
operator(still don't know why it is finally accepted). It is not a
problem(not having), it is a feature(to teach you program better), so
what cure are we talking about ?


Sorry, but I still do not get it. Why is it a feature if I cannot count
or find items in tuples? Why is it bad program style if I do this? So
far I haven't got any reasonable explanation and I think there is no.

-- Christoph

I'd have to say this:

First, remember that while your idea is obvious and practical and
straightforward to you, everybodys crummy idea is like that to them.
And while I'm not saying your idea is crummy, bear in mind that not
everyone is sharing your viewpoint.

If you want to make changes to the language, you need to be prepared
to convince other people that your idea really is a good one.
Therefore:

Be prepared to present a use case. If your idea really is
straightforward, simple, and obvious this should be fairly easy. It is
possible that your idea is so simple and obvious that everyone will
agree with it, do not expect this to be the case no matter how simple
and obvious it seems to you.

Be prepared to defend your use case. If people show reasons why your
use case is invalid, be prepared to consider that you may be wrong. If
you're still sure that you aren't, present a different use case -
don't expect other people to imagine one for you.

If you *really* want a language feature changed, be prepared to
present a patch for it. If you aren't willing or able to implement it
yourself, you must convince someone else that not only is your change
a good idea, but that it's a good enough idea that they should work on
it, which is always more of an uphill battle.

There may be different subjective or conceptual reasonings at work -
like you wanting to treat tuples as first class sequences while others
(like Guido) want to treat them otherwise. There's no right answer in
a subjective argument, so be prepared to present practical support,
and, unless you're the BDFL, be prepared to be ignored. If it bothers
you enough, you know what your options are.
Dec 1 '05 #55
On 11/30/05, Christoph Zwerschke <ci**@online.de> wrote:
bo****@gmail.com wrote:
Paul Rubin wrote:
Look at the list.count() example at the start of this thread.
Diagnosing it isn't hard. Curing it isn't hard. It doesn't bloat
Python by an order of magnitude. A suitably factored implementation
might handle lists and strings with the exact same code and not incur any extra cost at all. That type of thing happens all the time here.
I believe the language creator use the "lack of" as a way to
prevent/discourage that kind of usage. Just like the ternary
operator(still don't know why it is finally accepted). It is not a
problem(not having), it is a feature(to teach you program better), so what cure are we talking about ?

Sorry, but I still do not get it. Why is it a feature if I cannot count or find items in tuples? Why is it bad program style if I do this? So far I haven't got any reasonable explanation and I think there is no.
-- Christoph


I'd have to say this:

First, remember that while your idea is obvious and practical and
straightforward to you, everybodys crummy idea is like that to them.
And while I'm not saying your idea is crummy, bear in mind that not
everyone is sharing your viewpoint.

If you want to make changes to the language, you need to be prepared
to convince other people that your idea really is a good one.
Therefore:

Be prepared to present a use case. If your idea really is
straightforward, simple, and obvious this should be fairly easy. It is
possible that your idea is so simple and obvious that everyone will
agree with it, do not expect this to be the case no matter how simple
and obvious it seems to you.

Be prepared to defend your use case. If people show reasons why your
use case is invalid, be prepared to consider that you may be wrong. If
you're still sure that you aren't, present a different use case -
don't expect other people to imagine one for you.

If you *really* want a language feature changed, be prepared to
present a patch for it. If you aren't willing or able to implement it
yourself, you must convince someone else that not only is your change
a good idea, but that it's a good enough idea that they should work on
it, which is always more of an uphill battle.

There may be different subjective or conceptual reasonings at work -
like you wanting to treat tuples as first class sequences while others
(like Guido) want to treat them otherwise. There's no right answer in
a subjective argument, so be prepared to present practical support,
and, unless you're the BDFL, be prepared to be ignored. If it bothers
you enough, you know what your options are.

Dec 1 '05 #56
Quoth bo****@gmail.com:
| Christoph Zwerschke wrote:
....
|> Sorry, but I still do not get it. Why is it a feature if I cannot count
|> or find items in tuples? Why is it bad program style if I do this? So
|> far I haven't got any reasonable explanation and I think there is no.
|
| I have no idea, I can understand their view, not necessarily agree. And
| reasonable explanation is not something I usually find on this group,
| for issues like this.

It's hard to tell from this how well you do understand it, and of
course it's hard to believe another explanation is going to make
any difference to those who are basically committed to the opposing
point of view. But what the hell.

Tuples and lists really are intended to serve two fundamentally different
purposes. We might guess that just from the fact that both are included
in Python, in fact we hear it from Guido van Rossum, and one might add
that other languages also make this distinction (more clearly than Python.)

As I'm sure everyone still reading has already heard, the natural usage
of a tuple is as a heterogenous sequence. I would like to explain this
using the concept of an "application type", by which I mean the set of
values that would be valid when applied to a particular context. For
example, os.spawnv() takes as one of its arguments a list of command
arguments, time.mktime() takes a tuple of time values. A homogeneous
sequence is one where a and a[x:y] (where x:y is not 0:-1) have
the same application type. A list of command arguments is clearly
homogeneous in this sense - any sequence of strings is a valid input,
so any slice of this sequence must also be valid. (Valid in the type
sense, obviously the value and thus the result must change.) A tuple
of time values, though, must have exactly 9 elements, so it's heterogeneous
in this sense, even though all the values are integer.

One doesn't count elements in this kind of a tuple, because it's presumed
to have a natural predefined number of elements. One doesn't search for
values in this kind of a tuple, because the occurrence of a value has
meaning only in conjunction with its location, e.g., t[4] is how many
minutes past the hour, but t[5] is how many seconds, etc.

I have to confess that this wasn't obvious to me, either, at first, and
in fact probably about half of my extant code is burdened with the idea
that a tuple is a smart way to economize on the overhead of a list.
Somewhere along the line, I guess about 5 years ago? maybe from reading
about it here, I saw the light on this, and since then my code has gotten
easier to read and more robust. Lists really are better for all the
kinds of things that lists are for -- just for example, [1] reads a lot
better than (1,) -- and the savings on overhead is not worth the cost to
exploit it. My tendency to seize on this foolish optimization is however
pretty natural, as is the human tendency to try to make two similar things
interchangeable. So we're happy to see that tuple does not have the
features it doesn't need, because it helps in a small way to make Python
code better. If only by giving us a chance to have this little chat once
in a while.

Donn Cave, do**@drizzle.com
Dec 1 '05 #57
Donn Cave <do**@drizzle.com> wrote:
Tuples and lists really are intended to serve two fundamentally
different purposes.
[...]
As I'm sure everyone still reading has already heard, the natural
usage of a tuple is as a heterogenous sequence. [...] A list of
command arguments is clearly homogeneous in this sense - any
sequence of strings is a valid input, so any slice of this sequence
must also be valid. (Valid in the type sense, obviously the value
and thus the result must change.) A tuple of time values, though,
must have exactly 9 elements, so it's heterogeneous in this sense,
even though all the values are integer.

I have to confess that this wasn't obvious to me, either, at first,
and in fact probably about half of my extant code is burdened with
the idea that a tuple is a smart way to economize on the overhead of
a list. Somewhere along the line, I guess about 5 years ago? maybe
from reading about it here, I saw the light on this, and since then
my code has gotten easier to read and more robust.


Strangely, I learned this as I was learning the language, and
understood it after reading the explanation a couple of times (I can't
remember where I was reading it, but it must have been a decent
guide).

However, in the intervening time I'd forgotten this fundamental
difference between the *purpose* of list and tuple.

Thanks very much for this reminder. You've probably stopped me from
writing a bunch of misguided code and realising 5 years too late :-)

--
\ "Timid men prefer the calm of despotism to the boisterous sea |
`\ of liberty." -- Thomas Jefferson |
_o__) |
Ben Finney
Dec 1 '05 #58
"Donn Cave" <do**@drizzle.com> writes:
Tuples and lists really are intended to serve two fundamentally different
purposes. We might guess that just from the fact that both are included
in Python, in fact we hear it from Guido van Rossum, and one might add
that other languages also make this distinction (more clearly than Python.)

As I'm sure everyone still reading has already heard, the natural usage
of a tuple is as a heterogenous sequence. I would like to explain this
using the concept of an "application type", by which I mean the set of
values that would be valid when applied to a particular context. For
example, os.spawnv() takes as one of its arguments a list of command
arguments, time.mktime() takes a tuple of time values. A homogeneous
sequence is one where a and a[x:y] (where x:y is not 0:-1) have
the same application type. A list of command arguments is clearly
homogeneous in this sense - any sequence of strings is a valid input,
so any slice of this sequence must also be valid. (Valid in the type
sense, obviously the value and thus the result must change.) A tuple
of time values, though, must have exactly 9 elements, so it's heterogeneous
in this sense, even though all the values are integer.

One doesn't count elements in this kind of a tuple, because it's presumed
to have a natural predefined number of elements. One doesn't search for
values in this kind of a tuple, because the occurrence of a value has
meaning only in conjunction with its location, e.g., t[4] is how many
minutes past the hour, but t[5] is how many seconds, etc.


I get all that, I really do. I would phrase it as "a tuple is a set of
attributes that happen to be named by integers." count doesn't make
sense on the attributes of an object - so it doesn't make sense on a
tuple. index doesn't make sense on the attributes of an object - so it
doesn't make sense on a tuple. A loop over the attributes of an object
doesn't make sense - so it doesn't make sense on a tuple.

So why the $*@& (please excuse my Perl) does "for x in 1, 2, 3" work?

Seriously. Why doesn't this have to be phrased as "for x in list((1,
2, 3))", just like you have to write list((1, 2, 3)).count(1), etc.?

<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Dec 1 '05 #59

Mike Meyer wrote:
I get all that, I really do. I would phrase it as "a tuple is a set of
attributes that happen to be named by integers." count doesn't make
sense on the attributes of an object - so it doesn't make sense on a
tuple. index doesn't make sense on the attributes of an object - so it
doesn't make sense on a tuple. A loop over the attributes of an object
doesn't make sense - so it doesn't make sense on a tuple.

So why the $*@& (please excuse my Perl) does "for x in 1, 2, 3" work?

Seriously. Why doesn't this have to be phrased as "for x in list((1,
2, 3))", just like you have to write list((1, 2, 3)).count(1), etc.?

I don't know what you use tuple for, but I do need to loop over
attributes of an object(be it tuple or dict or even set), though no
need for count(), index(), not even on list, so far.

I think why people may ask for .count() and .index() for tuple is that
if I am writing a generic function that receive such a thing, I don't
need to do a type check or try/except block, should the caller tries to
be smart and use tuple instead of list(say for optimization reason).

Dec 1 '05 #60
Mike Meyer wrote:
So why the $*@& (please excuse my Perl) does "for x in 1, 2, 3" work?
because the syntax says so:

http://docs.python.org/ref/for.html
Seriously. Why doesn't this have to be phrased as "for x in list((1,
2, 3))", just like you have to write list((1, 2, 3)).count(1), etc.?


because anything that supports [] can be iterated over.

</F>

Dec 1 '05 #61
On 29/11/05, Christoph Zwerschke <ci**@online.de> wrote:
Fredrik Lundh wrote:
on the other hand, it's also possible that there are perfectly usable ways
to keep bikes and bike seats dry where Christoph works, but that he prefers
not to use them because they're violating some design rule.


Depends on how you understand "perfectly usable." My collegue always
carries his expensive racing bike to our office in the 3rd floor out of
fear it may get wet or stolen. But I think this is not very convenient
and I want to avoid discussions with our boss about skid marks on the
carpet and things like that. Probably that collegue would not complain
as well if he had to cast tuples to lists for counting items - you see,
people are different ;-)


If you're leaving skid marks on the floor, maybe you need better underwear?

http://www.google.co.uk/search?q=skid+marks+slang

Sorry to lower the tone.

Ed
Dec 1 '05 #62
Donn Cave schrieb:
As I'm sure everyone still reading has already heard, the natural usage
of a tuple is as a heterogenous sequence. I would like to explain this
using the concept of an "application type", by which I mean the set of
values that would be valid when applied to a particular context. For
example, os.spawnv() takes as one of its arguments a list of command
arguments, time.mktime() takes a tuple of time values. A homogeneous
sequence is one where a and a[x:y] (where x:y is not 0:-1) have
the same application type. A list of command arguments is clearly
homogeneous in this sense - any sequence of strings is a valid input,
so any slice of this sequence must also be valid. (Valid in the type
sense, obviously the value and thus the result must change.) A tuple
of time values, though, must have exactly 9 elements, so it's heterogeneous
in this sense, even though all the values are integer.


I understand what you want to say, but I would not use the terms
"homogenuous" or "heterogenous" since their more obvious meaning is that
all elements of a collection have the same type.

What you are calling an "application type" is a range of values, and the
characteristic you are describing is that the range of values is not
left when you slice (or extend) an object. So what you are describing is
simply a slicable/extendable application type. It is obvious that you
would use lists for this purpose, and not tuples, I completely agree
with you here. But this is just a consequence of the immutability of
tuples which is their more fundamental characteristic.

Let me give an example: Take all nxn matrices as your application type.
That applicaiton type is clearly not slicable/extendable, because this
would change the dimension, thus not "heterogenous" in your definition.

So would you use tuples (of tuples) or lists (of lists) here? Usually
you will use lists, because you want to be able to operate on the
matrices and transform them in place. So you see the more fundamental
characteristic and reason for prefering lists over tuples is mutability.

Let us assume you want to calculate the mathematical rank of such a
matrix. You would bring it in upper echelon shape (here, you are
operating on the rows, thus you would use lists) and then you would
count the all-zero rows. Ok, this is not an example for using count() on
tuples, but it is an example for using count() on a "heterogenous"
collection in your definition.

I completely agree that you will need count() and item() much less
frequently on tuples because of their immutability. This is obvious.
(Tuples themselves are already used less frequently than lists for this
reason.) But I still cannot see why you would *never* use it or why it
would be bad style.

And I don't understand why those who smile at my insistence on design
principles of consistence - propagating practicability instead - are
insisting themselves on some very philosophical and non-obvious design
principles or characteristics of tuples.

-- Christoph
Dec 1 '05 #63
Christoph Zwerschke wrote:
I understand what you want to say, but I would not use the terms
"homogenuous" or "heterogenous" since their more obvious meaning is that
all elements of a collection have the same type.


http://www.google.com/search?q=duck+typing

</F>

Dec 1 '05 #64
On 2005-12-01, Donn Cave <do**@drizzle.com> wrote:
Quoth bo****@gmail.com:
| Christoph Zwerschke wrote:
...
|> Sorry, but I still do not get it. Why is it a feature if I cannot count
|> or find items in tuples? Why is it bad program style if I do this? So
|> far I haven't got any reasonable explanation and I think there is no.
|
| I have no idea, I can understand their view, not necessarily agree. And
| reasonable explanation is not something I usually find on this group,
| for issues like this.

It's hard to tell from this how well you do understand it, and of
course it's hard to believe another explanation is going to make
any difference to those who are basically committed to the opposing
point of view. But what the hell.

Tuples and lists really are intended to serve two fundamentally different
purposes. We might guess that just from the fact that both are included
in Python, in fact we hear it from Guido van Rossum, and one might add
that other languages also make this distinction (more clearly than Python.)

As I'm sure everyone still reading has already heard, the natural usage
of a tuple is as a heterogenous sequence. I would like to explain this
using the concept of an "application type", by which I mean the set of
values that would be valid when applied to a particular context. For
example, os.spawnv() takes as one of its arguments a list of command
arguments, time.mktime() takes a tuple of time values. A homogeneous
sequence is one where a and a[x:y] (where x:y is not 0:-1) have
the same application type. A list of command arguments is clearly
homogeneous in this sense - any sequence of strings is a valid input,
so any slice of this sequence must also be valid. (Valid in the type
sense, obviously the value and thus the result must change.) A tuple
of time values, though, must have exactly 9 elements, so it's heterogeneous
in this sense, even though all the values are integer.

One doesn't count elements in this kind of a tuple, because it's presumed
to have a natural predefined number of elements. One doesn't search for
values in this kind of a tuple, because the occurrence of a value has
meaning only in conjunction with its location, e.g., t[4] is how many
minutes past the hour, but t[5] is how many seconds, etc.


I don't agree with this. Something can be a hetergenous sequence, but
the order can be arbitrary, so that any order of the elements can work
as long as at is well defined beforehand. Points on a 2D latice are
by convention notated as (x,y) but (y,x) works just as well. When
working in such a lattice it is possible to be interested in those
points that lay on one of the axes. Since the X-axis and the Y-axis
play a symmetrical role, it is possible that it doesn't matter which
axis the point is on. So counting how many of the coordinates are
zero is natural way to check if a point is on an axe. Doing a find
is a natural way to check if a point is on an axis and at the same
time find out which one.

So that a sequence is heterogenous in this sense doesn't imply
that count, find and other methods of such kind don't make sense.

--
Antoon Pardon
Dec 1 '05 #65
On 2005-12-01, Fredrik Lundh <fr*****@pythonware.com> wrote:
Mike Meyer wrote:
So why the $*@& (please excuse my Perl) does "for x in 1, 2, 3" work?


because the syntax says so:

http://docs.python.org/ref/for.html
Seriously. Why doesn't this have to be phrased as "for x in list((1,
2, 3))", just like you have to write list((1, 2, 3)).count(1), etc.?


because anything that supports [] can be iterated over.


This just begs the question. If tuples are supposed to be such
heterogenous sequences, one could indeed question why they
support [].

And even if good arguments are given why tuples shouls support
[], the fact that the intention of tuples and list are so
different casts doubts on the argument that supporting []
is enough reason to support iteration.

One could equally also argue that since iteration is at the heart
of methods like index, find and count, that supporting iteration
is sufficient reason to support these methods.

--
Antoon Pardon
Dec 1 '05 #66
I think this all boils down to the following:

* In their most frequent use case where tuples are used as lightweight
data structures keeping together heterogenous values (values with
different types or meanings), index() and count() do not make much sense.

I completely agree that his is the most frequent case. Still there are
cases where tuples are used to keep homogenous values together (for
instance, RGB values, points in space, rows of a matrix). In these cases
it would be principally useful to have index() and count() methods.

But:

* Very frequently you will use only 2- or 3-tuples, where direct queries
may be faster than item() and count(). (That's probably why Antoon's RGB
example was rejected as use case though it was principally a good one).

* Very frequently you want to perform operations on these objects and
change their elements, so you would use lists instead of tuples anyway.
See my use case where you would determine whether a vector is zero by
count()ing its zero entries or the rank of a matrix by count()ing zero rows.

* You will use item() and count() in situations where you are dealing
with a small discrete range of values in your collection. Often you will
use strings instead of tuples in these cases, if you don't need to sum()
the items, for instance.

So, indeed, very few use cases will remain if you filter throught the
above. But this does not mean that they do not exist. And "special cases
aren't special enough to break the rules." It should be easy to imagine
use cases now.

Take for example, a chess game. You are storing the pieces in a
64-tuple, where every piece has an integer value corresponding to its
value in the game (white positive, black negative). You can approximate
the value of a position by building the sum(). You want to use the tuple
as a key for a dictionary of stored board constellations (e.g. an
opening dictionary), therefore you don't use a list.

Now you want to find the field where the king is standing. Very easy
with the index() method. Or you want to find the number of pawns on the
board. Here you could use the count() method.

-- Christoph
Dec 1 '05 #67
Christoph Zwerschke wrote:
It should be easy to imagine use cases now.

Take for example, a chess game. You are storing the pieces in a
64-tuple, where every piece has an integer value corresponding to its
value in the game (white positive, black negative). You can approximate
the value of a position by building the sum(). You want to use the tuple
as a key for a dictionary of stored board constellations (e.g. an
opening dictionary), therefore you don't use a list.

Now you want to find the field where the king is standing. Very easy
with the index() method. Or you want to find the number of pawns on the
board. Here you could use the count() method.


now, I'm no expert on data structures for chess games, but I find it hard to
believe that any chess game implementer would use a data structure that re-
quires linear searches for everything...

</F>

Dec 1 '05 #68
Chris Mellon schrieb:
First, remember that while your idea is obvious and practical and
straightforward to you, everybodys crummy idea is like that to them.
And while I'm not saying your idea is crummy, bear in mind that not
everyone is sharing your viewpoint.


That's completely ok. What I wanted to know is *why* people do not share
my viewpoint and whether I can understand their reasons. Often, there
are good reasons that I do understand after some discussion. In this
case, there were some arguments but they were not convincing for me.

I think the rest of your arguments have been already discussed in this
thread. People seem to have different opinions here.

-- Christoph
Dec 1 '05 #69
Fredrik Lundh wrote:
Christoph Zwerschke wrote:
now, I'm no expert on data structures for chess games, but I find it hard to
believe that any chess game implementer would use a data structure that re-
quires linear searches for everything...


Using linear arrays to represent chess boards is pretty common in
computer chess. Often, the array is made larger than 64 elements to make
sure moves do not go off the board but hit unbeatable pseudo pieces
standing around the borders. But in principle, linear arrays of that
kind are used, and for good reasons.

I already feared that a discussion about the details and efficiency of
this implementation would follow. But this was not the point here.

-- Christoph
Dec 1 '05 #70
Antoon Pardon wrote:
On 2005-12-01, Fredrik Lundh <fr*****@pythonware.com> wrote:
Mike Meyer wrote:

So why the $*@& (please excuse my Perl) does "for x in 1, 2, 3" work?
because the syntax says so:

http://docs.python.org/ref/for.html

Seriously. Why doesn't this have to be phrased as "for x in list((1,
2, 3))", just like you have to write list((1, 2, 3)).count(1), etc.?


because anything that supports [] can be iterated over.

This just begs the question. If tuples are supposed to be such
heterogenous sequences, one could indeed question why they
support [].

Presumably because it's necessary to extract the individual values
(though os.stat results recently became addressable by attribute name as
well as by index, and this is an indication of the originally intended
purpose of tuples).
And even if good arguments are given why tuples shouls support
[], the fact that the intention of tuples and list are so
different casts doubts on the argument that supporting []
is enough reason to support iteration.

One could equally also argue that since iteration is at the heart
of methods like index, find and count, that supporting iteration
is sufficient reason to support these methods.

One could even go so far as to prepare a patch to implement the required
methods and see if it were accepted (though wibbling is a much easier
alternative). Personally I find the collective wisdom of the Python
developers, while not infallible, a good guide as to what's pythonistic
and what's not. YMMV.

regards
Steve
--
Steve Holden +44 150 684 7255 +1 800 494 3119
Holden Web LLC www.holdenweb.com
PyCon TX 2006 www.python.org/pycon/

Dec 1 '05 #71
Christoph Zwerschke wrote:
I think this all boils down to the following:

* In their most frequent use case where tuples are used as lightweight
data structures keeping together heterogenous values (values with
different types or meanings), index() and count() do not make much sense.

I completely agree that his is the most frequent case. Still there are
cases where tuples are used to keep homogenous values together (for
instance, RGB values, points in space, rows of a matrix). In these cases
it would be principally useful to have index() and count() methods.
Why? Why does it make sense to ask whether an RGB color has a particular
value for one of red, green or blue? Why does it make sense to ask how
many elements there are in an RGB color? It doesn't, so you must be
talking about (ordered) *collections* of such items.

If you want a list of RGB colors then use a list. If you want a list of
points in space then use a list. Why is a tuple preferable? [If the
answer is "because a tuple can't be changed" go to the bottom of the class].
But:

* Very frequently you will use only 2- or 3-tuples, where direct queries
may be faster than item() and count(). (That's probably why Antoon's RGB
example was rejected as use case though it was principally a good one).

* Very frequently you want to perform operations on these objects and
change their elements, so you would use lists instead of tuples anyway.
See my use case where you would determine whether a vector is zero by
count()ing its zero entries or the rank of a matrix by count()ing zero rows.

* You will use item() and count() in situations where you are dealing
with a small discrete range of values in your collection. Often you will
use strings instead of tuples in these cases, if you don't need to sum()
the items, for instance.

So, indeed, very few use cases will remain if you filter throught the
above. But this does not mean that they do not exist. And "special cases
aren't special enough to break the rules." It should be easy to imagine
use cases now.

Take for example, a chess game. You are storing the pieces in a
64-tuple, where every piece has an integer value corresponding to its
value in the game (white positive, black negative). You can approximate
the value of a position by building the sum(). You want to use the tuple
as a key for a dictionary of stored board constellations (e.g. an
opening dictionary), therefore you don't use a list.
This is a pretty bogus use case. Seems to me like a special case it's
not worth breaking the rules for!
Now you want to find the field where the king is standing. Very easy
with the index() method. Or you want to find the number of pawns on the
board. Here you could use the count() method.

Bearing in mind the (likely) performance impact of using these items as
dict keys don't you think some other representation would be preferable?

regards
Steve
--
Steve Holden +44 150 684 7255 +1 800 494 3119
Holden Web LLC www.holdenweb.com
PyCon TX 2006 www.python.org/pycon/

Dec 1 '05 #72
Christoph Zwerschke wrote:
Christoph Zwerschke wrote:
now, I'm no expert on data structures for chess games, but I find it hard to
believe that any chess game implementer would use a data structure that re-
quires linear searches for everything...
Using linear arrays to represent chess boards is pretty common in
computer chess. Often, the array is made larger than 64 elements to make
sure moves do not go off the board but hit unbeatable pseudo pieces
standing around the borders. But in principle, linear arrays of that
kind are used, and for good reasons.


really? a quick literature search only found clever stuff like bitboards,
pregenerated move tables, incremental hash algorithms, etc. the kind
of stuff you'd expect from a problem domain like chess.
I already feared that a discussion about the details and efficiency of
this implementation would follow. But this was not the point here.


so pointing out that the use case you provided has nothing to do with
reality is besides the point ? you're quickly moving into kook-country
here.

</F>

Dec 1 '05 #73
Mike Meyer wrote:
Paul Rubin <http://ph****@NOSPAM.invalid> writes: [...] Did somebody actually use "Practicality beats purity" as an excuse for
not making list.count and string.count have the same arguments? If so,
I missed it. I certainly don't agree with that - count ought to work
right in this case.
I agree that the two methods are oddly inconsonant. But then since the
introduction of the "has substring" meaning for the "in" operator,
strings and lists are also inconsistent over that operation.
A suitably factored implementation might handle lists and strings
with the exact same code and not incur any extra cost at all. That
type of thing happens all the time here.

I don't think this would make much sense in present-day Python, mostly
because there's no such thing as a character, only a string of length
one. So a string is actually a sequence of sequences of length one. I
guess this is one of those cases where practicality beat purity. It's as
though an indexing operation on a list got you a list of length one
rather than the element at that index. Strings have always been
anomalous in this respect.

If it happens all the time, you shouldn't have any trouble nameing a
number of things that a majority of users think are misfeatures that
aren't being fixed. Could you do that?

Doubtless he could. Paul's a smart guy. The missing element will be
unanimity on the rationale.

regards
Steve
--
Steve Holden +44 150 684 7255 +1 800 494 3119
Holden Web LLC www.holdenweb.com
PyCon TX 2006 www.python.org/pycon/

Dec 1 '05 #74
On 12/1/05, Christoph Zwerschke <ci**@online.de> wrote:
I think this all boils down to the following:

* In their most frequent use case where tuples are used as lightweight
data structures keeping together heterogenous values (values with
different types or meanings), index() and count() do not make much sense.

I completely agree that his is the most frequent case. Still there are
cases where tuples are used to keep homogenous values together (for
instance, RGB values, points in space, rows of a matrix). In these cases
it would be principally useful to have index() and count() methods.

But:

* Very frequently you will use only 2- or 3-tuples, where direct queries
may be faster than item() and count(). (That's probably why Antoon's RGB
example was rejected as use case though it was principally a good one).

* Very frequently you want to perform operations on these objects and
change their elements, so you would use lists instead of tuples anyway.
See my use case where you would determine whether a vector is zero by
count()ing its zero entries or the rank of a matrix by count()ing zero rows.

* You will use item() and count() in situations where you are dealing
with a small discrete range of values in your collection. Often you will
use strings instead of tuples in these cases, if you don't need to sum()
the items, for instance.

So, indeed, very few use cases will remain if you filter throught the
above. But this does not mean that they do not exist. And "special cases
aren't special enough to break the rules." It should be easy to imagine
use cases now.

Take for example, a chess game. You are storing the pieces in a
64-tuple, where every piece has an integer value corresponding to its
value in the game (white positive, black negative). You can approximate
the value of a position by building the sum(). You want to use the tuple
as a key for a dictionary of stored board constellations (e.g. an
opening dictionary), therefore you don't use a list.

This really looks to me like you have your priorities inverted.
Practically everything you want to do with this structure is
list-like, so why not make it a list and convert it to a tuple when
you need to use it as an index? Even better, since you're doing a lot
of list operations, why not make it a list and define unique IDs or
something to use as indices?

A minor change in your design/thinking (not trying to use a tuple as a
frozen list) instead of a change in the language (making tuples more
like frozen lists) seems to be the warranted solution. But maybe thats
just me.

Now you want to find the field where the king is standing. Very easy
with the index() method. Or you want to find the number of pawns on the
board. Here you could use the count() method.

-- Christoph
--
http://mail.python.org/mailman/listinfo/python-list

Dec 1 '05 #75
Steve Holden wrote:
Christoph Zwerschke wrote:
I completely agree that his is the most frequent case. Still there are
cases where tuples are used to keep homogenous values together (for
instance, RGB values, points in space, rows of a matrix). In these
cases it would be principally useful to have index() and count() methods.

Why? Why does it make sense to ask whether an RGB color has a particular
value for one of red, green or blue? Why does it make sense to ask how
many elements there are in an RGB color? It doesn't, so you must be
talking about (ordered) *collections* of such items.

If you want a list of RGB colors then use a list. If you want a list of
points in space then use a list. Why is a tuple preferable? [If the
answer is "because a tuple can't be changed" go to the bottom of the
class].


I cannot follow you here. How would you store RGB values? I think they
are a perfect use case for tuples in the spirit of Guido's "lightweight
C structs." So, in the spirit of Guido I would store them as tuples, or
return them as tuples by a function getpixel(x,y). Why should I not be
allowed to check for getpixel(xy).count(0) == n for black pixels in an
image with n layers? Yes, you could set BLACK=(0,)*n and test against
BLACK. You can always do things differently.
Take for example, a chess game. You are storing the pieces in a
64-tuple, where every piece has an integer value corresponding to its
value in the game (white positive, black negative). You can
approximate the value of a position by building the sum(). You want to
use the tuple as a key for a dictionary of stored board constellations
(e.g. an opening dictionary), therefore you don't use a list.

This is a pretty bogus use case. Seems to me like a special case it's
not worth breaking the rules for!


I already explained why use cases for count() and index() on tuples will
principally be rare. So it will always be easy for you to call them
"special cases". But they are there, and they make sense.

Also, we are not talking about "breaking" a rule or any existing code
here, but about generalizing or *broadening* a rule. (What do you do if
a rule itself is broken?)

Here is another example illustrating the problem - coincidentally, from
Fredrik's blog, http://effbot.org/zone/image-histogram-optimization.htm
(found it when googling for getpixel):

def histogram4(image):
# wait, use the list.count operator
data = list(image.getdata())
result = []
for i in range(256):
result.append(data.count(i))
return result

Here, we could imagine the getdata() method returning a tuple. Again,
why must it be casted to a list, just to use count()? In reality,
getdata() returns a sequence. But again, wouldn't it be nice if all
sequences provided count() and index() methods? Then there would be no
need to create a list from the sequence before counting.

-- Christoph
Dec 1 '05 #76
[Since part of my post seems to have gotten lost in this thread, I
figured I would repeat it]

In article <dm**********@panix1.panix.com>, Aahz <aa**@pythoncraft.com> wrote:
In article <dm**********@online.de>,
Christoph Zwerschke <ci**@online.de> wrote:

Or, another example, the index() method has start and end parameters for
lists and strings. The count() method also has start and end parameters
for strings. But it has no such parameters for lists. Why?


That's a fair cop. Submit a patch and it'll probably get accepted.


This is one of those little things that happens in language evolution;
not everything gets done right the first time. But Python is developed
by volunteers: if you want this fixed, the first step is to submit a bug
report on SF (or go ahead and submit a patch if you have the expertise).
(I'm quite comfortable channeling Guido and other developers in saying a
patch will get accepted.)
--
Aahz (aa**@pythoncraft.com) <*> http://www.pythoncraft.com/

"Don't listen to schmucks on USENET when making legal decisions. Hire
yourself a competent schmuck." --USENET schmuck (aka Robert Kern)
Dec 1 '05 #77
Fredrik Lundh wrote:
Christoph Zwerschke wrote:

Using linear arrays to represent chess boards is pretty common in
computer chess. Often, the array is made larger than 64 elements to make
sure moves do not go off the board but hit unbeatable pseudo pieces
standing around the borders. But in principle, linear arrays of that
kind are used, and for good reasons.


really? a quick literature search only found clever stuff like bitboards,
pregenerated move tables, incremental hash algorithms, etc. the kind
of stuff you'd expect from a problem domain like chess.


I don't know where you googled, but my sources do not say that bitboards
are the *only* possible or reasonable representation:

http://chess.verhelst.org/1997/03/10/representations/
http://en.wikipedia.org/wiki/Compute...epresentations
http://www.aihorizon.com/essays/chessai/boardrep.htm
http://www.oellermann.com/cftchess/notes/boardrep.html

Many programs still use the array representation. For example:
http://www.nothingisreal.com/cheops/
http://groups.msn.com/RudolfPosch/te...cription1.msnw
Even GNU Chess did not use bitboards before version 5.
Here is an example in Python:
http://www.kolumbus.fi/jyrki.alakuijala/pychess.html

I did not say that there aren't more sophisticated and elaborate board
representations than linear or two-dimensional arrays. But they are the
simplest and most immediate and intuitive solution, and they have indeed
been used for a long time in the 8-bit aera. Bitboards may be more
performant, particularly if you are directly programming in assembler or
C on a 64 bit machine, but not necessarily in Python. But they are also
more difficult to handle. Which representation to use also depends on
the algorithms you are using. You wouldn't write a performant chess
engine in Python anyway. But assume you want to test a particular chess
tree pruning algorithm (that does not depend on board representation)
and write a prototype for that in Python, later making a performant
implementation in assembler. You would not care so much about the
effectivity of your board representation in the prototype, but rather
about how easy it can be handled.

I think it is telling that you have to resort to a debate about
bitboards vs. arrays in order to dismiss my simple use case for index()
and count() as "unreal".

-- Christoph
Dec 1 '05 #78
"Donn Cave" <do**@drizzle.com> wrote in
news:11***************@jetspin.drizzle.com:

[...]
Tuples and lists really are intended to serve two fundamentally
different purposes. We might guess that just from the fact that
both are included in Python, in fact we hear it from Guido van
Rossum, and one might add that other languages also make this
distinction (more clearly than Python.)

As I'm sure everyone still reading has already heard, the
natural usage of a tuple is as a heterogenous sequence. I would
like to explain this using the concept of an "application type",
by which I mean the set of values that would be valid when
applied to a particular context. For example, os.spawnv() takes
as one of its arguments a list of command arguments,
time.mktime() takes a tuple of time values. A homogeneous
sequence is one where a and a[x:y] (where x:y is not 0:-1)
have the same application type. A list of command arguments is
clearly homogeneous in this sense - any sequence of strings is a
valid input, so any slice of this sequence must also be valid.
(Valid in the type sense, obviously the value and thus the
result must change.) A tuple of time values, though, must have
exactly 9 elements, so it's heterogeneous in this sense, even
though all the values are integer.

One doesn't count elements in this kind of a tuple, because it's
presumed to have a natural predefined number of elements. One
doesn't search for values in this kind of a tuple, because the
occurrence of a value has meaning only in conjunction with its
location, e.g., t[4] is how many minutes past the hour, but t[5]
is how many seconds, etc.

I have to confess that this wasn't obvious to me, either, at
first, and in fact probably about half of my extant code is
burdened with the idea that a tuple is a smart way to economize
on the overhead of a list. Somewhere along the line, I guess
about 5 years ago? maybe from reading about it here, I saw the
light on this, and since then my code has gotten easier to read
and more robust. Lists really are better for all the kinds of
things that lists are for -- just for example, [1] reads a lot
better than (1,) -- and the savings on overhead is not worth the
cost to exploit it. My tendency to seize on this foolish
optimization is however pretty natural, as is the human tendency
to try to make two similar things interchangeable. So we're
happy to see that tuple does not have the features it doesn't
need, because it helps in a small way to make Python code
better. If only by giving us a chance to have this little chat
once in a while.


Donn, this is a reasonable argument, and in general I don't have a
problem with the distinction between tuples and lists. I have heard
and understand the argument that the intended purpose of tuple
creation is to mimic C structs, so it seems reasonable to suppose
that one knows what was placed in them. Lists are dynamic by
nature, so you need a little more help getting information about
their current state.

However, there is at least one area where this distinction is
bogus. Lists cannot be used as dictionary keys (as it now stands).
But in practice, it is often useful to create a list of values,
cast the list to a tuple, and use that as a dictionary key. It
makes little sense to keep a list of that same information around,
so in practice, the tuple/key is the container that retains the
original information. But that tuple was dynamically created, and
it isn't always true that items were placed in it deliberately.

In other words, the fact that the key is now a tuple is unrelated
to the essential nature of tuples. Not all of the tools used in
examining lists are available to the key as a tuple, though it is
really nothing more than a frozen list.

Sure, you can cast it to a list to use the list methods, but that
requires creating objects just to throw away, which seems a little
wasteful, especially since that's what you had to do to create the
key to begin with.

I'm sure Antoon wouldn't object if lists were to be allowed as
dictionary keys, which would eliminate the multiple castings for
that situation. I wouldn't, either.

I'd extend this a little to say that tuples are (at least
potentially) created dynamically quite often in other contexts as
well, so that despite their designed intent, in practice they are
used a little differently a good bit of the time. So why not adjust
the available features to the practice?

--
rzed
Dec 1 '05 #79
Christoph Zwerschke wrote:
I think it is telling that you have to resort to a debate about
bitboards vs. arrays in order to dismiss my simple use case for
index() and count() as "unreal".


kook.

</F>

Dec 1 '05 #80
Aahz wrote:
This is one of those little things that happens in language evolution;
not everything gets done right the first time. But Python is developed
by volunteers: if you want this fixed, the first step is to submit a bug
report on SF (or go ahead and submit a patch if you have the expertise).
(I'm quite comfortable channeling Guido and other developers in saying a
patch will get accepted.)


Ok, I submitted it as feature request #1370948. I currently don't have
the time and expertise to submit a patch.

-- Christoph
Dec 1 '05 #81
Rick Wotnaz wrote:
I'm sure Antoon wouldn't object if lists were to be allowed as
dictionary keys, which would eliminate the multiple castings for
that situation. I wouldn't, either.


so what algorithm do you suggest for the new dictionary im-
plementation?

</F>

Dec 1 '05 #82
"Fredrik Lundh" <fr*****@pythonware.com> wrote in
news:ma***************************************@pyt hon.org:
Rick Wotnaz wrote:
I'm sure Antoon wouldn't object if lists were to be allowed as
dictionary keys, which would eliminate the multiple castings for
that situation. I wouldn't, either.


so what algorithm do you suggest for the new dictionary im-
plementation?


Beats the heck outta me. I seem to remember that Antoon supplied
one awhile ago (for allowing lists to serve as dictionary keys,
that is). That's why I mentioned him in the first place. I didn't
pay much attention to it at the time, and I imagine it would raise
some issues, like everything does.

I'm fairly indifferent to the idea in any case; I'm just saying I
wouldn't object if lists could function as dictionary keys. It
would save that casting step I was talking about.

--
rzed
Dec 1 '05 #83
Steve Holden <st***@holdenweb.com> wrote:
...
Presumably because it's necessary to extract the individual values
(though os.stat results recently became addressable by attribute name as
well as by index, and this is an indication of the originally intended
purpose of tuples).


Yep -- "time tuples" have also become pseudo-tuples (each element can be
accessed by name as well as by index) a while ago, and I believe there's
one more example besides stats and times (but I can't recall which one).

Perhaps, if the tuple type _in general_ allowed naming the items in a
smooth way, that might help users see a tuple as "a kind of
``struct''... which also happens to be immutable". There are a few such
"supertuples" (with item-naming) in the cookbook, but I wonder if it
might not be worth having such functionality in the standard library
(for this clarification as well as, sometimes, helping the readability
of some user code).
Alex
Dec 1 '05 #84
Fredrik Lundh wrote:
Christoph Zwerschke wrote:
I think it is telling that you have to resort to a debate about
bitboards vs. arrays in order to dismiss my simple use case for
index() and count() as "unreal".


kook.


Thanks.

Just to clarify: I was referring to the weakness of the argument
"tuple.count() is evil" when I wrote "telling". It was not meant
derogatory towards your person in any way - if you understood it that
way I apologize. Maybe I write in a way that can be easily
misunderstood, but I would not deliberately libel others, least of all
if it is only about a petty issue of a programming language.

-- Christoph
Dec 1 '05 #85
Rick Wotnaz wrote:
Rick Wotnaz wrote:
I'm sure Antoon wouldn't object if lists were to be allowed as
dictionary keys, which would eliminate the multiple castings for
that situation. I wouldn't, either.


so what algorithm do you suggest for the new dictionary im-
plementation?


Beats the heck outta me. I seem to remember that Antoon supplied
one awhile ago (for allowing lists to serve as dictionary keys,
that is).


anyone has a pointer? all I can remember is that people have posted
various "if the key is mutated, I don't care if the value can no longer
be found" proposals (besides the usual SEP variants, of course), but
Antoon's endless stream of "I claim that it be argued that" posts
makes it easy to miss things...

</F>

Dec 1 '05 #86
Alex Martelli wrote:
Steve Holden <st***@holdenweb.com> wrote:
...
Presumably because it's necessary to extract the individual values
(though os.stat results recently became addressable by attribute name as
well as by index, and this is an indication of the originally intended
purpose of tuples).


Yep -- "time tuples" have also become pseudo-tuples (each element can be
accessed by name as well as by index) a while ago, and I believe there's
one more example besides stats and times (but I can't recall which one).

Perhaps, if the tuple type _in general_ allowed naming the items in a
smooth way, that might help users see a tuple as "a kind of
``struct''... which also happens to be immutable". There are a few such
"supertuples" (with item-naming) in the cookbook, but I wonder if it
might not be worth having such functionality in the standard library
(for this clarification as well as, sometimes, helping the readability
of some user code).


iirc, providing a python-level API to the SequenceStruct stuff
has been proposed before, and rejected.

(fwiw, I'm not sure the time and stat tuples would have been
tuples if the standard library had been designed today; the C-
level stat struct doesn't have a fixed number of members, and
the C-level time API would have been better off as a light-
weight "time" type (similar to sockets, stdio-based files, and
other C-wrapper types))

</F>

Dec 1 '05 #87
Fredrik Lundh wrote:
Rick Wotnaz wrote:

I'm sure Antoon wouldn't object if lists were to be allowed as
dictionary keys, which would eliminate the multiple castings for
that situation. I wouldn't, either.


so what algorithm do you suggest for the new dictionary im-
plementation?


<devil's_advocate> One option is to create a new "frozen list" type, a`
la frozen sets.
People who argue that "frozen list" is not needed because we already
have the tuple type, while simultaneously arguing that tuples shouldn't
grow list methods because they are conceptually different from lists
will be bludgeoned to death with a paradox. :) </devil's_advocate>
Dec 1 '05 #88
Rocco Moretti wrote:
I'm sure Antoon wouldn't object if lists were to be allowed as
dictionary keys, which would eliminate the multiple castings for
that situation. I wouldn't, either.
so what algorithm do you suggest for the new dictionary im-
plementation?


<devil's_advocate> One option is to create a new "frozen list" type, a`
la frozen sets.


doesn't frozenset make a copy?
People who argue that "frozen list" is not needed because we already
have the tuple type, while simultaneously arguing that tuples shouldn't
grow list methods because they are conceptually different from lists
will be bludgeoned to death with a paradox.


http://www.python.org/peps/pep-0351.html

This PEP describes a simple protocol for requesting a frozen,
immutable copy of a mutable object. It also defines a new
built-in function which uses this protocol to provide an
immutable copy on any cooperating object.
...

Here are some code samples which show the intended semantics

class xset(set):
def __freeze__(self):
return frozenset(self)

class xlist(list):
def __freeze__(self):
return tuple(self)

...

</F>

Dec 1 '05 #89
Fredrik Lundh wrote:
Rocco Moretti wrote:
I'm sure Antoon wouldn't object if lists were to be allowed as
dictionary keys, which would eliminate the multiple castings for
that situation. I wouldn't, either.

so what algorithm do you suggest for the new dictionary im-
plementation?
<devil's_advocate> One option is to create a new "frozen list" type, a`
la frozen sets.


doesn't frozenset make a copy?


As does the current "cast as tuple" technique. (I'm certainly not
advocating it, but ...) Certain implementations of "frozen list" could
possibly do the list->frozenlist conversion without a copy. (e.g. by
flipping an "immutable" bit)
http://www.python.org/peps/pep-0351.html

This PEP describes a simple protocol for requesting a frozen,
immutable copy of a mutable object.


Perhaps Barry has been borrowing Guido's time machine?
Dec 1 '05 #90
On 2005-12-01, Steve Holden <st***@holdenweb.com> wrote:
Antoon Pardon wrote:
On 2005-12-01, Fredrik Lundh <fr*****@pythonware.com> wrote:
Mike Meyer wrote:
So why the $*@& (please excuse my Perl) does "for x in 1, 2, 3" work?

because the syntax says so:

http://docs.python.org/ref/for.html
Seriously. Why doesn't this have to be phrased as "for x in list((1,
2, 3))", just like you have to write list((1, 2, 3)).count(1), etc.?

because anything that supports [] can be iterated over.

This just begs the question. If tuples are supposed to be such
heterogenous sequences, one could indeed question why they
support [].

Presumably because it's necessary to extract the individual values


It isn't, The stated intent of tuples seems to suggest that packing
and unpacking should be sufficient.
(though os.stat results recently became addressable by attribute name as
well as by index, and this is an indication of the originally intended
purpose of tuples).
And even if good arguments are given why tuples shouls support
[], the fact that the intention of tuples and list are so
different casts doubts on the argument that supporting []
is enough reason to support iteration.

One could equally also argue that since iteration is at the heart
of methods like index, find and count, that supporting iteration
is sufficient reason to support these methods.
One could even go so far as to prepare a patch to implement the required
methods and see if it were accepted (though wibbling is a much easier
alternative).


That has been done and it was rejected.
Personally I find the collective wisdom of the Python
developers, while not infallible, a good guide as to what's pythonistic
and what's not. YMMV.


That's because their decisions will shape python and thus decide
what is pythonic and what is not.

--
Antoon Pardon
Dec 1 '05 #91
"Fredrik Lundh" <fr*****@pythonware.com> writes:
Mike Meyer wrote:
So why the $*@& (please excuse my Perl) does "for x in 1, 2, 3" work?

because the syntax says so:
http://docs.python.org/ref/for.html


In other words, "Because that's the way we do things."
Seriously. Why doesn't this have to be phrased as "for x in list((1,
2, 3))", just like you have to write list((1, 2, 3)).count(1), etc.?

because anything that supports [] can be iterated over.


That's false. Anything that has __getitem__ supports []. To be
iterated over, it has to have __iter__, or an __getitem__ that works
on integers properly. Writing a class that meets the first without
meeting the second is easy. Dicts used to qualify, and tuples could be
iterated over at that time.

Not really very satisfactory reasons.

<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Dec 1 '05 #92
In article <ma***************************************@python. org>,
"Fredrik Lundh" <fr*****@pythonware.com> wrote:
Alex Martelli wrote:
Steve Holden <st***@holdenweb.com> wrote:
...
Presumably because it's necessary to extract the individual values
(though os.stat results recently became addressable by attribute name as
well as by index, and this is an indication of the originally intended
purpose of tuples).


Yep -- "time tuples" have also become pseudo-tuples (each element can be
accessed by name as well as by index) a while ago, and I believe there's
one more example besides stats and times (but I can't recall which one).

Perhaps, if the tuple type _in general_ allowed naming the items in a
smooth way, that might help users see a tuple as "a kind of
``struct''... which also happens to be immutable". There are a few such
"supertuples" (with item-naming) in the cookbook, but I wonder if it
might not be worth having such functionality in the standard library
(for this clarification as well as, sometimes, helping the readability
of some user code).


iirc, providing a python-level API to the SequenceStruct stuff
has been proposed before, and rejected.

(fwiw, I'm not sure the time and stat tuples would have been
tuples if the standard library had been designed today; the C-
level stat struct doesn't have a fixed number of members, and
the C-level time API would have been better off as a light-
weight "time" type (similar to sockets, stdio-based files, and
other C-wrapper types))


Right. After devoting a lengthy post to the defense of
tuples as a structured type, I have to admit that they're
not a very good one - it's hard to think of many structured
values that are ideally expressed by a fixed length vector
with elements accessed by integer index.

Another theme that occasionally comes up in advice from the
learned has been "use a class". Of course for values that
are related to some external structure, you'd want to provide
something to make tuple(a) work, serialization etc., and you'd
probably end up with something a lot like StructSequence.
Meanwhile losing a significant overhead.

I wrote a quickie Python API to SequenceStruct and used it to
make an (x, y) coord type, to compare with a Coord.x,y class.
A list of a million coords used 1/5 space, and took 1/10 the
time to create. Hm.

Donn Cave, do**@u.washington.edu
Dec 1 '05 #93
In article <dm**********@news.doit.wisc.edu>,
Rocco Moretti <ro**********@hotpop.com> wrote:
People who argue that "frozen list" is not needed because we already
have the tuple type, while simultaneously arguing that tuples shouldn't
grow list methods because they are conceptually different from lists
will be bludgeoned to death with a paradox. :) </devil's_advocate>


Maybe I can dodge the paradox by noting that the set of things
we need, is much larger than the set of things we need enough
to do what it takes to get them. So I can agree that frozen
lists are needed, without necessarily supporting the effort.

Donn Cave, do**@u.washington.edu
Dec 1 '05 #94
In article <86************@bhuda.mired.org>, Mike Meyer <mw*@mired.org>
wrote:
....
So why the $*@& (please excuse my Perl) does "for x in 1, 2, 3" work?

Seriously. Why doesn't this have to be phrased as "for x in list((1,
2, 3))", just like you have to write list((1, 2, 3)).count(1), etc.?


How could list(t) work, if for x in t didn't?
For me, conceptually, if an object can't be accessed
sequentially, then it can't be mapped to a sequence.

Anyway, it seems to me that in the end this is about
that balance between practicality and purity. Maybe
it's more like tuples have a primary intended purpose,
and some support for other applications. Not white,
but not pure black either.

Donn Cave, do**@u.washington.edu
Dec 1 '05 #95
Mike Meyer wrote:
Seriously. Why doesn't this have to be phrased as "for x in list((1,
2, 3))", just like you have to write list((1, 2, 3)).count(1), etc.? because anything that supports [] can be iterated over.


That's false. Anything that has __getitem__ supports []. To be
iterated over, it has to have __iter__, or an __getitem__ that works
on integers properly.


your arguments are getting more and more antoon-like. you can create
an iterator (using iter) for any object that supports [] (__getitem__), but
if __getitem__ doesn't do the right thing, any attempt to fetch items by
calling it will of course fail as well.
Writing a class that meets the first without
meeting the second is easy. Dicts used to qualify, and tuples could be
iterated over at that time.

Not really very satisfactory reasons.


that's how python's sequence protocol works. duck typing all the
way down.

http://www.google.com/search?q=duck+typing

</F>

Dec 1 '05 #96
Donn Cave <do**@u.washington.edu> writes:
Right. After devoting a lengthy post to the defense of
tuples as a structured type, I have to admit that they're
not a very good one ...
Another theme that occasionally comes up in advice from the
learned has been "use a class".


There's a historical issue too: when tuples started first being
used this way in Python, classes had not yet been introduced.
Dec 1 '05 #97
In article <7x************@ruckus.brouhaha.com>,
Paul Rubin <http://ph****@NOSPAM.invalid> wrote:
There's a historical issue too: when tuples started first being
used this way in Python, classes had not yet been introduced.


When was that, old-timer? According to Misc/HISTORY,
Python was first posted to alt.sources at version 0.9.0,
February 1991. It doesn't say 0.9.0 had classes, but
at 0.9.3 we see refinements like __dict__, and it's hard
to imagine that classes themselves snuck in without notice
in the interim.

If you got a copy of some older version than this, you
have some interesting historical perspectives there, but
not much of a historical issue, I'd say, without much
going on in the way of a user community.

Donn Cave, do**@u.washington.edu
Dec 1 '05 #98
Donn Cave wrote:
Paul Rubin wrote:
There's a historical issue too: when tuples started first being
used this way in Python, classes had not yet been introduced.


When was that, old-timer? According to Misc/HISTORY,
Python was first posted to alt.sources at version 0.9.0,
February 1991. It doesn't say 0.9.0 had classes, but
at 0.9.3 we see refinements like __dict__, and it's hard
to imagine that classes themselves snuck in without notice
in the interim.

If you got a copy of some older version than this, you
have some interesting historical perspectives there, but
not much of a historical issue, I'd say, without much
going on in the way of a user community.


fwiw, the tuple and class implementation were both checked into
CVS in october 1990.

maybe he's talking about ABC ? (where, judging from the language
reference, had lists, compounds, and tables which worked pretty
much like Python's lists, tuples, and dictionaries).

</F>

Dec 1 '05 #99
"Fredrik Lundh" <fr*****@pythonware.com> writes:
Mike Meyer wrote:
Seriously. Why doesn't this have to be phrased as "for x in list((1,
2, 3))", just like you have to write list((1, 2, 3)).count(1), etc.?
because anything that supports [] can be iterated over.

That's false. Anything that has __getitem__ supports []. To be
iterated over, it has to have __iter__, or an __getitem__ that works
on integers properly.

your arguments are getting more and more antoon-like. you can create
an iterator (using iter) for any object that supports [] (__getitem__), but
if __getitem__ doesn't do the right thing, any attempt to fetch items by
calling it will of course fail as well.


So you're claiming that the ability to create an iterator for an
object via iter is sufficient to claim that you can iterate over it,
never mind that actually using the iterator fails?

Or are you claiming that a __getitem__ that doesn't handle integers
the way iter expects is somehow "wrong"? If so, what's up with
dict.__getitem__?

If you're claiming something else, you'll have to clarify it.
Writing a class that meets the first without
meeting the second is easy. Dicts used to qualify, and tuples could be
iterated over at that time.
Not really very satisfactory reasons.

that's how python's sequence protocol works. duck typing all the
way down.
http://www.google.com/search?q=duck+typing


So it's an accident of implementation? Should iterating over a tuple
then be considered "abuse", because tuples aren't intended to be used
as a sequence?

I'm perfectly happy to accept that tuples aren't sequences, and that's
why they don't have sequence-like methods. But there really should be
a better explanation than "oops" for them having sequence-like
behavior elsewhere.

<mike
--
Mike Meyer <mw*@mired.org> http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.
Dec 1 '05 #100

This discussion thread is closed

Replies have been disabled for this discussion.

By using this site, you agree to our Privacy Policy and Terms of Use.