General question about Python design goals

  • Thread starter Christoph Zwerschke
  • Start date
C

Christoph Zwerschke

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
 
R

Robert Kern

Christoph said:
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?

Yes. If it's not going to be used, then there's not much point.
Practicality beats purity, and all that.

However, I will note that if you were to present us with a working patch
with documentation and unittests, then you'll probably get responses
along the lines of "Thank you!", instead.

--
Robert Kern
(e-mail address removed)

"In the fields of hell where the grass grows high
Are the graves of dreams allowed to die."
-- Richard Harter
 
P

Paul Rubin

Robert Kern said:
Yes. If it's not going to be used, then there's not much point.
Practicality beats purity, and all that.

Geez man, "practicality beats purity" only means that if maintaining
purity of something is impractical, you can judiciously let purity
slide. It doesn't mean every slapdash kludge you can throw together
is acceptable for a widely-used distro, just because it works for the
cases you happened to think of at the moment you wrote it.

Wanting to handle the .count() parameters the same way for lists and
strings does not present any practical obstacles. So purity is not in
conflict with practicality there. The lack of orthogonality for that
operation is simply a wart.
 
R

Robert Kern

Paul said:
Geez man, "practicality beats purity" only means that if maintaining
purity of something is impractical, you can judiciously let purity
slide. It doesn't mean every slapdash kludge you can throw together
is acceptable for a widely-used distro, just because it works for the
cases you happened to think of at the moment you wrote it.

Fine. Allow me to rephrase. Development is primarily motivated by
practical needs and guided by notions of purity. Use cases are the
primary tool for communicating those practical needs. If you can't think
of a single use case, what's the point of implementing something? Or
rather, why should someone else implement it if you don't know how you
would use it?

--
Robert Kern
(e-mail address removed)

"In the fields of hell where the grass grows high
Are the graves of dreams allowed to die."
-- Richard Harter
 
A

Aahz

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?

Because Guido believes that tuples should be primarily used as
lightweight replacements for C structs. Therefore they have minimal
functionality.
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.
 
C

Christoph Zwerschke

Let me ask back: Do I really need to bother and justify it with a use
Robert said:
Yes. If it's not going to be used, then there's not much point.
Practicality beats purity, and all that.

I have nothing against "practicality beats purity". But to stay with the
examples I have given, in how far is writing list(t).index(x) more
practical than t.index(x)?

And by the way, if we are speaking about practicality here, are we
speaking about practicality for the Python developers or for the Python
users? This may be sometimes be in opposition.

Let me give an extreme example: Assume the count() method for strings
would have been called "numberofsubstringsinthestring()" and I argue it
should be called "count()" because that is shorter and how it is called
for lists. What should I give as a "use case" here? Must I give "use
cases" if the issue is about convenience/simplicity/elegance?
However, I will note that if you were to present us with a working patch
with documentation and unittests, then you'll probably get responses
along the lines of "Thank you!", instead.

Not everybody has the time and skills to provide that. Ordinary people
from the Python user base should be given the opportunity to make
suggestions for improvement - of course not in the tone of "I
demand...", but they should not be automatically regarded as "demanding"
if they just utter their opinion or make a suggestion either.

Even if I had the time and skills, before starting to work on a patch,
unittests etc. I still would first discuss with others whether my
suggestion is reasonable and would be appreciated by the "user base",
developers and the BDFL. Just take the example of the following patch:
https://sourceforge.net/tracker/?func=detail&atid=305470&aid=403693&group_id=5470

It was not rejected by reason of missing unittests or documentation, but
the very idea was rejected.

Actually, I'm not keen on being a protagonist for this issue or starting
a hard-bitten discussion about this and defend the idea if everybody is
against or nobody cares. It does not bother me that much either.

But it just led me to the general question: Which significance actually
have design features such as orthogonality for Python?

-- Christoph
 
R

Robert Kern

Christoph said:
I have nothing against "practicality beats purity". But to stay with the
examples I have given, in how far is writing list(t).index(x) more
practical than t.index(x)?

I'm not arguing that the things you mentioned shouldn't be changed. I'm
saying that use cases really are important in making design decisions.
You just provided one. Congratulations.
And by the way, if we are speaking about practicality here, are we
speaking about practicality for the Python developers or for the Python
users? This may be sometimes be in opposition.

As Paul noted, it was a misuse of the phrase. I withdraw it.
Not everybody has the time and skills to provide that. Ordinary people
from the Python user base should be given the opportunity to make
suggestions for improvement - of course not in the tone of "I
demand...", but they should not be automatically regarded as "demanding"
if they just utter their opinion or make a suggestion either.

Even if I had the time and skills, before starting to work on a patch,
unittests etc. I still would first discuss with others whether my
suggestion is reasonable and would be appreciated by the "user base",
developers and the BDFL. Just take the example of the following patch:
https://sourceforge.net/tracker/?func=detail&atid=305470&aid=403693&group_id=5470

It was not rejected by reason of missing unittests or documentation, but
the very idea was rejected.

And it also appears to have nothing to do with the lack of proffered use
cases but (primarily) Guido's thoughts about how the different objects
are supposed to be used. That's why use cases are so important. They
allow developers to talk about real, concrete issues.

--
Robert Kern
(e-mail address removed)

"In the fields of hell where the grass grows high
Are the graves of dreams allowed to die."
-- Richard Harter
 
C

Christoph Zwerschke

For instance, I just wanted to use the index() method on a tuple which
Because Guido believes that tuples should be primarily used as
lightweight replacements for C structs. Therefore they have minimal
functionality.

But the problem is that the tutorials and manuals give the impression
that the difference between lists and tuples is only mutablity versus
immutability. They don't talk about such considerations and honestly
speaking even now I know that it does seem more plausible for me.

-- Christoph
 
P

Peter Hansen

Christoph said:
But it just led me to the general question: Which significance actually
have design features such as orthogonality for Python?

Probably very little. Python has not so much been designed as evolved.
Plus it's a fairly mature language (over 14 years old), and I think in
such a case that elements of design tend to be obscured by the many
changes layered on top. (For example, I hardly recognize the C++ that I
learned in the language that struggles on today.)

While the goal of orthogonality may factor into some people's reasons
for implementing certain changes, it's not (apparently) a primary
motivation for many of the ones doing work on the Python core. If more
people with such motivations had been working on the core, it's likely
Python would have more of these sorts of "gaps" filled in.

(The corollary, of course, is that there would be other gaps, and they
would be more practical ones, so other people would probably be
suggesting things like "wouldn't it be good if Python had a Unicode type
instead of all these little-used functions that make the language nice
and orthogonal but aren't really necessary". ;-) )

-Peter
 
B

bonono

Christoph said:
But the problem is that the tutorials and manuals give the impression
that the difference between lists and tuples is only mutablity versus
immutability. They don't talk about such considerations and honestly
speaking even now I know that it does seem more plausible for me.
That is the problem of the tutorial or manual, don't read them as if
they are ISO specs.
 
P

Paul Rubin

Robert Kern said:
Fine. Allow me to rephrase. Development is primarily motivated by
practical needs and guided by notions of purity.

That's bogus; if there was a discrepancy someone noticed and had to
work around, there's already been a practical failure, just not a
severe one. Development should be guided by doing things right when
possible, making allowances for practical considerations that
sometimes call for compromise. It's generally far better to do
something right the first time than to do something broken and have to
fix it later. Those XP platitudes about prototyping and refactoring
are for when the program is still under development and the
requirements have not yet been discovered, and unfixed bogosity
affects just a few people (developers and testers). When a program
has been declared finished and shipped to millions of users, any
bogosity remaining in it has a much larger effect, so bogosity should
be minimized.
Use cases are the primary tool for communicating those practical
needs. If you can't think of a single use case, what's the point of
implementing something? Or rather, why should someone else implement
it if you don't know how you would use it?

I can't think of a single use case for the addition (+) operator
working where either of the operands happens to be the number
0x15f1ef02d9f0c2297e37d44236d8e8ddde4a34c96a8200561de00492cb94b82 (a
random number I just got out of /dev/urandom). I've never heard of
any application using that number, and the chances of it happening by
coincidence are impossibly low. But if Python were coded in a way
that made the interpreter crash on seeing that number, I'd call that
a bug needing fixing.
 
A

Aahz

But the problem is that the tutorials and manuals give the impression
that the difference between lists and tuples is only mutablity versus
immutability. They don't talk about such considerations and honestly
speaking even now I know that it does seem more plausible for me.

Then feel free to submit patches for the docs.

PS: If you want further responses from me, please follow standard Usenet
quoting conventions (like those above).
 
A

Antoon Pardon

Op 2005-11-28 said:
Because Guido believes that tuples should be primarily used as
lightweight replacements for C structs. Therefore they have minimal
functionality.

I find that a bit contradictory with the fact that if you want list like
structures as a dictionary key, you are mostly advised to cast them
as tuples.

So suppose I want a dictionary, where the keys are colours, represented
as RGB triplets of integers from 0 to 255. A number of things can be
checked by index-like methods.

e.g.

def iswhite(col):
return col.count(255) == 3

def primary(col):
return col.count(255) == 1 and col.count(0) == 2

def secondary(col):
return col.count(255) == 2 and col.count(0) == 1


So, what should I use to implement this? Whether I choose
lists or tuples, I will end up either copying a lot from
lists to tuples or vice versa, to get the functionality
I need, or I will have to implement functionality myself
that basically is already in the language.

I also find the use of C-structs and tuples completly different.
If I need a C-struct like object, I go for Bunch, Rec or something
similar. Something that uses field identifiers to address components,
Not something that uses indexing.
 
F

Fredrik Lundh

Christoph said:
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?

- A Foolish Consistency is the Hobgoblin of Little Minds
- Hypergeneralization Sucks

</F>
 
A

Antoon Pardon

Op 2005-11-28 said:
- A Foolish Consistency is the Hobgoblin of Little Minds

What is so foolish about the consistency that all sequence types
have a count method?

The way this "pearl of wisdom" is used in this newsgroup, I expect
one day someone to use "+" for substraction and '-" for addition and
then when people complain about that not being consistent they get
answered by the above quote.
 
S

Sebastien Douche

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

I use this thread to asking on python conception : why python have so
many builtins ?
I cannot understand why we use a builtins for open a file. Is it a old
decision ? If anyone have a pointer of this or can explain me.

Regards.
 
D

Duncan Booth

Antoon said:
So suppose I want a dictionary, where the keys are colours, represented
as RGB triplets of integers from 0 to 255. A number of things can be
checked by index-like methods.

e.g.

def iswhite(col):
return col.count(255) == 3

def primary(col):
return col.count(255) == 1 and col.count(0) == 2

def secondary(col):
return col.count(255) == 2 and col.count(0) == 1

Just because you *can* implement these by treating your colour like a list
doesn't make it a good idea. Treating them as opaque values makes these
particular tests clearer:

def iswhite(col):
return col==WHITE

def primary(col):
return col in (RED,GREEN,BLUE)

def secondary(col):
return col in (CYAN,MAGENTA,YELLOW)

If you relax your definition of primary to simply require that two planes
are black then you may have a case where you want to treat the colour
planes as a list, but if you convert it explicitly then you'll be better
placed to keep the code working when someone decides to add an alpha
channel or to switch the representation to CMYK.

def anyshadeprimary(col):
return [col.red, col.green, col.blue].count(0)==2
# or
return col.toRGB().count(0)==2

So it looks to me as though you want col to be a type (which might be a
subclass of tuple) but a list would be a mistake.
 
A

Antoon Pardon

Op 2005-11-28 said:
Just because you *can* implement these by treating your colour like a list
doesn't make it a good idea. Treating them as opaque values makes these
particular tests clearer:

You are getting sidetracked. Whether this is the best possible
implementation here is not the issue. This example is just
to illustrate.

I'm sure I could come up with an other example where I would like
to have both some list method and use it as a dictionary key and
again people could start about that implementation having some
flaws and give better implementations.

I'm just illustrating that some list-like methods with tuples
could be usefull.
 
D

Duncan Booth

Antoon said:
I'm sure I could come up with an other example where I would like
to have both some list method and use it as a dictionary key and
again people could start about that implementation having some
flaws and give better implementations.

I'm just illustrating that some list-like methods with tuples
could be usefull.
But you aren't illustrating that at all. You came up with an example which
showed, at least to me, a good argument why tuples should *not* have list
methods.

If you can come up with a better example that would be good; if any other
example is as flawed then perhaps it shows that your basic assumption is
wrong.
 
A

Antoon Pardon

Op 2005-11-28 said:
But you aren't illustrating that at all. You came up with an example which
showed, at least to me, a good argument why tuples should *not* have list
methods.

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. The trouble is
to really convince would probably require a complete worked out module,
but then I don't have the time to come up with a complete worked out
module just to illustrate something. So I come up with just a skeleton
of something to get the idea across and what happens is that the
attention goes to how the skeleton could be approved in other ways,
instead of trying to understand what ideas are trying to be
communicated.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top