[Python-ideas] Python Isn't Perfect: adding a 'gotchas' section to the tutorial

42 views
Skip to first unread message

Richard Prosser

unread,
Dec 10, 2011, 9:16:21 AM12/10/11
to python...@python.org
Although I love Python there are some aspects of the language design which are disappointing and which can even lead to problems in some cases.

A classic example is a mutable default argument having the potential to produce unexpected side-effects, as a consequence of the non-intuitive scoping rules.

Another awkward 'feature' is the requirement for a trailing comma in singleton tuples, due I believe to the use of expression parentheses rather than (say) the use of special brackets like chevrons.

Something that I personally wish for is the ability to declare variable types 'up front' but that facility is missing from Python.


This is an important issue, so I propose that the Python tutorial be updated to highlight such problems. I would be willing to write a draft section myself but obviously it would need to be reviewed.

I am not sure if this is the appropriate place to make such a comment but it seems to be a good starting point. Any advice on making a more formal proposal would be welcome.


Cheers,

Richard Prosser
PS Is it too late to fix such warts in version 3?



Masklinn

unread,
Dec 10, 2011, 9:41:14 AM12/10/11
to Richard Prosser, python...@python.org
On 2011-12-10, at 15:16 , Richard Prosser wrote:
>
> A classic example is a mutable default argument having the potential to
> produce unexpected side-effects, as a consequence of the non-intuitive
> scoping rules.
As far as I know, mutable default arguments have nothing to do with
scoping, they have to do with the "toplevel" being evaluated fully, so
as the function declaration is evaluated (to create the function
object) so are its default arguments. This is independent from
Python's scoping issues unless I misunderstood what you meant by
"scoping".

But this is definitely something which trips people. However, there is
already a note (though a pretty low-key one, it should probably use an
actual warning directive instead of just bolding it, you should submit
a documentation patch) in the tutorial on that subject[0].

> Another awkward 'feature' is the requirement for a trailing comma in
> singleton tuples, due I believe to the use of expression parentheses rather
> than (say) the use of special brackets like chevrons.

For tuples, there are no matching operators left, as literal sets have
been added.

And technically, the irregularity with tuples is probably the empty
tuple `()` as parens in other tuple arities are only necessary for
disambiguation (much like parens around generator expressions): the
"tuple constructor" is the comma, not the parens,

a = 1,
b = 1, 2
c = 1, 2, 3

are all valid and generate respectively a singleton, a pair and a
triple. In that context, the trailing comma for singletons makes
sense. If you want regularity, you can even add a trailing comma to
the pair and the triple (as you can in e.g. a list or a dict):

a = 1,
b = 1, 2,
c = 1, 2, 3,

I'd rather have a lone comma (with or without parens, depending on the
context) create a null tuple.

> Something that I personally wish for is the ability to declare variable
> types 'up front' but that facility is missing from Python.

I fail to see how this is a "gotcha": since Python is dynamically
typed names don't have types (well technically Python 3 added
documentary type specs to arguments, but they're not used by any
implementation I know of though some third-party tools may already
have started using them)

[0] http://docs.python.org/tutorial/controlflow.html#default-argument-values
_______________________________________________
Python-ideas mailing list
Python...@python.org
http://mail.python.org/mailman/listinfo/python-ideas

Michael Foord

unread,
Dec 10, 2011, 10:27:20 AM12/10/11
to Richard Prosser, python...@python.org
On 10 December 2011 14:16, Richard Prosser <richard...@mail.com> wrote:
Although I love Python there are some aspects of the language design which are disappointing and which can even lead to problems in some cases.

A classic example is a mutable default argument having the potential to produce unexpected side-effects, as a consequence of the non-intuitive scoping rules.

The default argument "problem" is not intuitive (and does need highlighting to people new to Python). But it is still better than the alternatives. It isn't to do with scoping but when the default arguments are evaluated. If instead the default values were evaluated at call time, what would the following code do:

a = 3
def function(arg=a):
    pass
del a
function()

In addition you have added extra overhead cost to each function call (argument evaluation). Plus Python exposes the default arguments to introspection. If the default arguments aren't evaluated until call time you lose that capability.
 

Another awkward 'feature' is the requirement for a trailing comma in singleton tuples, due I believe to the use of expression parentheses rather than (say) the use of special brackets like chevrons.


Well, parentheses are only part of the syntax for an empty tuple: ()

For non-empty tuple literals it is *only* the commas that are significant.

    single = 1,
    double = 2, 3

So although the syntax for a single member tuple does feel a bit awkward I wonder what alternative you would suggest?

 
Something that I personally wish for is the ability to declare variable types 'up front' but that facility is missing from Python.


That runs counter to the basic principles of Python where types are determined at runtime. What effect would declaring types have and how would that interact with the rest of the language? (Do you want every assignment to do a runtime type check?)
 

This is an important issue, so I propose that the Python tutorial be updated to highlight such problems. I would be willing to write a draft section myself but obviously it would need to be reviewed.


This is a good idea however. :-) Just do it. Create a documentation patch (for Python 3) and attach it to an issue in the bug tracker:

    http://bugs.python.org/
 
I am not sure if this is the appropriate place to make such a comment but it seems to be a good starting point. Any advice on making a more formal proposal would be welcome.


Cheers,

Richard Prosser
PS Is it too late to fix such warts in version 3?

For the issues you've raised, yes. Unless you have specific proposals that don't break backwards compatibility.

All the best,

Michael Foord

 




_______________________________________________
Python-ideas mailing list
Python...@python.org
http://mail.python.org/mailman/listinfo/python-ideas




--
http://www.voidspace.org.uk/

May you do good and not evil
May you find forgiveness for yourself and forgive others
May you share freely, never taking more than you give.
-- the sqlite blessing http://www.sqlite.org/different.html

Antoine Pitrou

unread,
Dec 10, 2011, 12:45:54 PM12/10/11
to python...@python.org

Hello Richard,

On Sat, 10 Dec 2011 14:16:21 +0000
Richard Prosser <richard...@mail.com> wrote:
>
> This is an important issue, so I propose that the Python tutorial be
> updated to highlight such problems. I would be willing to write a draft
> section myself but obviously it would need to be reviewed.

I think documenting "gotchas" can be useful indeed. However, I'm not
sure the tutorial is the right place: it should present an easy to
grasp view of the language, not digress about edge cases.

So perhaps a FAQ, for example, would be more appropriate.

In any case, feel free to propose a draft on http://bugs.python.org
You can take a look at http://docs.python.org/dev/documenting/ if you
are not familiar with the process.

Regards

Antoine.

Ned Batchelder

unread,
Dec 10, 2011, 1:34:15 PM12/10/11
to Richard Prosser, python...@python.org
On 12/10/2011 9:16 AM, Richard Prosser wrote:
> Although I love Python there are some aspects of the language design
> which are disappointing and which can even lead to problems in some cases.
>
> A classic example is a mutable default argument having the potential
> to produce unexpected side-effects, as a consequence of the
> non-intuitive scoping rules.
>
> Another awkward 'feature' is the requirement for a trailing comma in
> singleton tuples, due I believe to the use of expression parentheses
> rather than (say) the use of special brackets like chevrons.
>
> Something that I personally wish for is the ability to declare
> variable types 'up front' but that facility is missing from Python.
>
One of these things is not like the others. Mutable default arguments,
and singleton tuples are surprises that make sense once you understand
things on a deeper level. It makes sense to call them out as a
"gotcha": a common stumbling block for learners. But "no type
declarations" is not a wart, it's a fundamental feature of the language
that is immediately apparent from the first lesson.

--Ned.

Richard Prosser

unread,
Dec 11, 2011, 4:30:54 PM12/11/11
to python...@python.org
Ned,

I accept your comment about the tutorial - I wasn't sure about that. Thanks.

However I still feel that there are some aspects of the language which are not in the true spirit of Python (i.e. 'intuitive').

The discussion about default mutable types is one of these. It seems to me that the essential problem is that of assignment in general, which (I believe) creates a reference on the LHS to the object on the RHS, rather than having a copy operation to make the two objects completely separate. That can be confusing in other contexts, not just with default parameters.

If I am to write a 'gotchas' FAQ or whatever then I would like to understand the reasoning behind such design decisions but I can't find any 'deep' explanations at present - just several posts about people being puzzled! A similar comment applies to the lack of type declarations.

So if you or anyone else can explain exactly why such odditties are implemented I would be grateful.

Unfortunately it is almost certainly too late to propose fixes (if appropriate) for such quirks in Python 3 but at least I should be able provide arguments as to why things are done the way they are.


Richard


On 11 December 2011 01:21, <python-ide...@python.org> wrote:
Message: 2
Date: Sat, 10 Dec 2011 13:34:15 -0500
From: Ned Batchelder <n...@nedbatchelder.com>
To: Richard Prosser <richard...@mail.com>
Cc: python...@python.org
Subject: Re: [Python-ideas] Python Isn't Perfect: adding a 'gotchas'
       section to the tutorial
Message-ID: <4EE3A627...@nedbatchelder.com>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed

Masklinn

unread,
Dec 11, 2011, 6:31:11 PM12/11/11
to Richard Prosser, python...@python.org
On 2011-12-11, at 22:30 , Richard Prosser wrote:
> However I still feel that there are some aspects of the language which are
> not in the true spirit of Python (i.e. 'intuitive').
I have to note that, as far as I know, "intuitive" is not quite part of the
"true spirit of Python". The Zen even has a stanza on the subject:

> Although that way may not be obvious at first unless you're Dutch.

> It seems to me
> that the essential problem is that of assignment in general, which (I
> believe) creates a reference on the LHS to the object on the RHS, rather
> than having a copy operation to make the two objects completely separate.

I don't see this as a problem, it's the normal semantics of languages using
reference-values for object types.

> A similar comment applies to the lack of type declarations.
>
> So if you or anyone else can explain exactly why such odditties are
> implemented I would be grateful.

I don't understand, why do you consider dynamic typing to be "an
oddity"? There is nothing odd about it, and it's in fact older than
computer science itself.

The default arguments issue is an unfortunate interaction of Python's
core reference-value semantics and default arguments being implemented
as attributes to the function object, evaluated when said function
object is created (the feature itself is as old as Python, according to
the logs it was added for the 1.0.2 release back in 1994, the changelog
seems to peg it to April 14, so your only chance for an explanation of
why it was implemented with these semantics is hoping Guido has a very,
very good memory. Numerous post-hoc rationalization exist, but only him
may hold the true reason).

> Unfortunately it is almost certainly too late to propose fixes (if
> appropriate) for such quirks in Python 3

Most of these have been core semantic attributes of the language for
almost two decades now, so even if you had proposed these changes
during the Python 3 design cycle I think it's very unlikely they'd
have passed: they don't just change Python, they create a very
different language with a syntax similar to Python's.

Terry Reedy

unread,
Dec 11, 2011, 7:13:23 PM12/11/11
to python...@python.org
On 12/11/2011 4:30 PM, Richard Prosser wrote:

> However I still feel that there are some aspects of the language which
> are not in the true spirit of Python (i.e. 'intuitive').

While 'intuitive' may be part of the 'true spirit of Python', it is not
included in the Zen of Python, perhaps because it it so slippery and
person dependent. Python is more in tune with everyday life and
therefore with naive intuition than some other languages.

> The discussion about default mutable types is one of these. It seems to
> me that the essential problem is that of assignment in general, which (I
> believe) creates a reference on the LHS to the object on the RHS, rather
> than having a copy operation to make the two objects completely
> separate. That can be confusing in other contexts, not just with default
> parameters.

When an organization reassign the role 'president' to a new person, they
do not copy the person. Neither does Python. We use aliases (multiple
ways to refer to the same entity) all the time in real life.

Python is quite consistent. Expressions evaluate to objects, either
pre-existing or new. "Target = expression" binds the target to the
object resulting from evaluating the expression. "f(expression)" binds
the first parameter name of f to the expression object.

> If I am to write a 'gotchas' FAQ or whatever then I would like to
> understand the reasoning behind such design decisions but I can't find
> any 'deep' explanations at present - just several posts about people
> being puzzled! A similar comment applies to the lack of type declarations.

Both behaviors reflect the fact that Python is a named object language,
rather than a named memory block language, and that in Python types are
a property of objects rather than of names. This is similar to at least
some uses of names in everyday life. For instance, the name Buddy could
be bound by a particular person to a person, dog, other pet, story,
boat, or even a rifle.

--
Terry Jan Reedy

Ned Batchelder

unread,
Dec 11, 2011, 7:34:07 PM12/11/11
to Richard Prosser, python...@python.org
Richard, I don't think I can provide you with a "why" for dynamic typing.  It's a choice Guido made early on, one that is central to the language, and one that I think pays off in the long run.  Values are objects, which are typed.  Names are untyped, and can refer to any value, regardless of what value they referred to in the past.  Therefore, it doesn't make sense to talk about the type of a name, which is all that a type declaration could do.

This is very different than some other programming languages, but I don't know if it could be called unintuitive.  I'm not sure anything about programming could truly be called intuitive, I think the closest we can get is "familiar".  Certainly if you've worked with statically typed languages before, then dynamic typing is unfamiliar.

I worry that you are still placing dynamic typing into a category you call "gotchas" or "quirks", with the word "fixes" nearby.  Dynamic typing cannot be "fixed", it is central to the language.  I think it is great to write something to help those new to Python, but you should be sure that you fully understand Python before you undertake it.

--Ned.


On 12/11/2011 4:30 PM, Richard Prosser wrote:

Mike Meyer

unread,
Dec 12, 2011, 12:59:54 AM12/12/11
to python...@python.org, n...@nedbatchelder.com
On Sun, 11 Dec 2011 19:34:07 -0500
Ned Batchelder <n...@nedbatchelder.com> wrote:

> Richard, I don't think I can provide you with a "why" for dynamic
> typing.

And this is the wrong place to ask. Dynamic typing and naming objects
dates back to the precursors to LISP in the mid 50s. You should be
asking the people who made that decision.

By the same token, have you asked anyone why C/Java/etc. have static
typing and name locations? It's an equally valid question.

<mike
--
Mike Meyer <m...@mired.org> http://www.mired.org/
Independent Software developer/SCM consultant, email for more information.

O< ascii ribbon campaign - stop html mail - www.asciiribbon.org

Greg Ewing

unread,
Dec 12, 2011, 12:11:32 AM12/12/11
to python...@python.org
Richard Prosser wrote:
> It seems to
> me that the essential problem is that of assignment in general, which (I
> believe) creates a reference on the LHS to the object on the RHS,
>
> I would like to
> understand the reasoning behind such design decisions but I can't find
> any 'deep' explanations at present
>
> So if you or anyone else can explain exactly why such odditties are
> implemented I would be grateful.

Python's assignment semantics are only an "oddity" to people
whose prior exposure to programming languages is very limited.
To anyone familiar with almost any other dynamic language --
such as Lisp, Scheme, Smalltalk, or Javascript -- it's not
only unsurprising, it's the *obvious* thing to do. So I wouldn't
class it as a "gotcha" in the same sense as truly Python-specific
features like default argument evaluation and list comprehension
variable scope.

As for rationale, it comes down to something like this: Copying
large chunks of data is expensive, so it makes sense to do it
only when you really need to. And experience shows that most of
the time you *don't* need to copy things.

Furthermore, copying some kinds of things automatically and not
others (as some other languages such as VB and Java do) makes the
rules needlessly complicated and difficult to remember.

So Python does the simplest possible thing and doesn't copy
anything by default. If you want a copy, you need to do something
explicit to make it happen.

> Unfortunately it is almost certainly too late to propose fixes
> (if appropriate) for such quirks in Python 3

Python's assignment behaviour is most definitely *not* something
that needs "fixing"!

--
Greg

Terry Reedy

unread,
Dec 12, 2011, 3:55:57 AM12/12/11
to python...@python.org
On 12/12/2011 12:59 AM, Mike Meyer wrote:
> On Sun, 11 Dec 2011 19:34:07 -0500
> Ned Batchelder<n...@nedbatchelder.com> wrote:
>
>> Richard, I don't think I can provide you with a "why" for dynamic
>> typing.
>
> And this is the wrong place to ask. Dynamic typing and naming objects
> dates back to the precursors to LISP in the mid 50s. You should be
> asking the people who made that decision.

List was designed for writing algorithms.

> By the same token, have you asked anyone why C/Java/etc. have static
> typing and name locations? It's an equally valid question.

C was designed for writing a computing machine operating system with
mutable sequential memory slots numbered from 0 to 2**n - 1.

In this respect, Python is much more like List than C, even though its
syntax is more like C.

--
Terry Jan Reedy

Masklinn

unread,
Dec 12, 2011, 3:59:16 AM12/12/11
to Greg Ewing, python...@python.org
On 2011-12-12, at 06:11 , Greg Ewing wrote:
> Richard Prosser wrote:
>> It seems to me that the essential problem is that of assignment in general, which (I believe) creates a reference on the LHS to the object on the RHS,
>> I would like to understand the reasoning behind such design decisions but I can't find any 'deep' explanations at present
>> So if you or anyone else can explain exactly why such odditties are implemented I would be grateful.
>
> Python's assignment semantics are only an "oddity" to people
> whose prior exposure to programming languages is very limited.
> To anyone familiar with almost any other dynamic language --
> such as Lisp, Scheme, Smalltalk, or Javascript -- it's not
> only unsurprising
It's not even a question of "dynamic languages", Java and C#
reference types have exactly the same semantics (assignment copies
the value part of a type, which is the reference itself).

The only people I'd see confused by this are those with significant
C++ experience, where assignment of references does indeed go through
a copy of the object itself.

> As for rationale, it comes down to something like this: Copying
> large chunks of data is expensive, so it makes sense to do it
> only when you really need to. And experience shows that most of
> the time you *don't* need to copy things.

Of course technically that copy could very well be performed
"on write". This would significantly complexify the runtime as well.

Masklinn

unread,
Dec 12, 2011, 4:00:59 AM12/12/11
to Terry Reedy, python...@python.org
On 2011-12-12, at 09:55 , Terry Reedy wrote:
> On 12/12/2011 12:59 AM, Mike Meyer wrote:
>> On Sun, 11 Dec 2011 19:34:07 -0500
>> Ned Batchelder<n...@nedbatchelder.com> wrote:
>>> Richard, I don't think I can provide you with a "why" for dynamic
>>> typing.
>>
>> And this is the wrong place to ask. Dynamic typing and naming objects
>> dates back to the precursors to LISP in the mid 50s. You should be
>> asking the people who made that decision.
> List was designed for writing algorithms.
I think you meant "lisp" here ;)

>> By the same token, have you asked anyone why C/Java/etc. have static
>> typing and name locations? It's an equally valid question.
> C was designed for writing a computing machine operating system with mutable sequential memory slots numbered from 0 to 2**n - 1.

On the other hand, there are very few typed assemblies.

Oleg Broytman

unread,
Dec 10, 2011, 9:42:30 AM12/10/11
to python...@python.org
On Sat, Dec 10, 2011 at 02:16:21PM +0000, Richard Prosser wrote:
> Although I love Python there are some aspects of the language design which
> are disappointing and which can even lead to problems in some cases.

What really is disappointing is the number of people who criticize
Python without knowing it.

> Another awkward 'feature' is the requirement for a trailing comma in
> singleton tuples, due I believe to the use of expression parentheses rather
> than (say) the use of special brackets like chevrons.

You do not understand the syntax. Parens do not construct tuples -
commas do. So for every tuple - even of length 1 - you must have a
comma. The only exception is an empty tuple (of length 0).

> Something that I personally wish for is the ability to declare variable
> types 'up front' but that facility is missing from Python.

You can use annotations. See PEP 3107. Twas implemented in Python 3.0.

Oleg.
--
Oleg Broytman http://phdru.name/ p...@phdru.name
Programmers don't die, they just GOSUB without RETURN.

Masklinn

unread,
Dec 12, 2011, 7:38:29 AM12/12/11
to Oleg Broytman, python...@python.org
On 2011-12-10, at 15:42 , Oleg Broytman wrote:
> You can use annotations. See PEP 3107. Twas implemented in Python 3.0.
It's not used by the runtime though (I think IDEA/PyCharm uses it, but
I wouldn't bet on it), so it's mostly documentary at this point.

Yuval Greenfield

unread,
Dec 12, 2011, 7:41:26 AM12/12/11
to Masklinn, python...@python.org
On Mon, Dec 12, 2011 at 2:38 PM, Masklinn <mask...@masklinn.net> wrote:
On 2011-12-10, at 15:42 , Oleg Broytman wrote:
>   You can use annotations. See PEP 3107. Twas implemented in Python 3.0.
It's not used by the runtime though (I think IDEA/PyCharm uses it, but
I wouldn't bet on it), so it's mostly documentary at this point.


<shameless>
pyopt uses annotations as types for parsing command line options if that counts:


</shameless>

--Yuval

Ned Batchelder

unread,
Dec 12, 2011, 8:00:28 AM12/12/11
to python...@python.org
On 12/10/2011 9:42 AM, Oleg Broytman wrote:
> On Sat, Dec 10, 2011 at 02:16:21PM +0000, Richard Prosser wrote:
>> Although I love Python there are some aspects of the language design which
>> are disappointing and which can even lead to problems in some cases.
> What really is disappointing is the number of people who criticize
> Python without knowing it.
>
>> Another awkward 'feature' is the requirement for a trailing comma in
>> singleton tuples, due I believe to the use of expression parentheses rather
>> than (say) the use of special brackets like chevrons.
> You do not understand the syntax. Parens do not construct tuples -
> commas do. So for every tuple - even of length 1 - you must have a
> comma. The only exception is an empty tuple (of length 0).
I don't think we have to go as far as blaming the user. Tuple syntax is
a little tricky, people often trip up on (x,) as a single-item tuple.
You and I understand why it is, and there isn't a better alternative,
but that one-item syntax sticks out when compared to the others: (), (x,
y), (x, y, z), etc. This is a true "gotcha" as Richard originally
expressed it.
> Oleg.
--Ned.

Matt Joiner

unread,
Dec 12, 2011, 8:06:07 AM12/12/11
to Ned Batchelder, python...@python.org
(a,) is the real gotcha, not ()

--
ಠ_ಠ

Antoine Pitrou

unread,
Dec 12, 2011, 8:07:58 AM12/12/11
to python...@python.org
On Mon, 12 Dec 2011 08:00:28 -0500
Ned Batchelder <n...@nedbatchelder.com>
wrote:

> On 12/10/2011 9:42 AM, Oleg Broytman wrote:
> > On Sat, Dec 10, 2011 at 02:16:21PM +0000, Richard Prosser wrote:
> >> Although I love Python there are some aspects of the language design which
> >> are disappointing and which can even lead to problems in some cases.
> > What really is disappointing is the number of people who criticize
> > Python without knowing it.
> >
> >> Another awkward 'feature' is the requirement for a trailing comma in
> >> singleton tuples, due I believe to the use of expression parentheses rather
> >> than (say) the use of special brackets like chevrons.
> > You do not understand the syntax. Parens do not construct tuples -
> > commas do. So for every tuple - even of length 1 - you must have a
> > comma. The only exception is an empty tuple (of length 0).
> I don't think we have to go as far as blaming the user. Tuple syntax is
> a little tricky, people often trip up on (x,) as a single-item tuple.
> You and I understand why it is, and there isn't a better alternative,
> but that one-item syntax sticks out when compared to the others: (), (x,
> y), (x, y, z), etc. This is a true "gotcha" as Richard originally
> expressed it.

I think it would be more of a gotcha if parentheses were enough to
create a tuple, though. Parentheses are useful to group operations,
either for stylistic / syntactic support (think multi-line statements),
or to work around operator precedence. Creating a tuple by mistake
because you put some parentheses where not necessary would be really
annoying.

Regards

Antoine.

Ned Batchelder

unread,
Dec 12, 2011, 8:15:45 AM12/12/11
to Antoine Pitrou, python...@python.org
Believe me, I understand the issues. It is true, though that the
single-element tuple syntax is often a surprise to people, and often
well into their Python learning experience. We often repeat, "it isn't
parens that make a tuple, but a comma." Then why when displaying a
tuple does Python insist on using parens around it?

>>> 1, 2, 3
(1, 2, 3)

I'm not saying it shouldn't, it's a rhetorical question. The repr of a
tuple always includes parens, even though "parens don't make a tuple."
It's the best of all the options, but let's face it: it's confusing.

--Ned.

Antoine Pitrou

unread,
Dec 12, 2011, 8:19:19 AM12/12/11
to Python-Ideas
Le lundi 12 décembre 2011 à 08:15 -0500, Ned Batchelder a écrit :
> Believe me, I understand the issues. It is true, though that the
> single-element tuple syntax is often a surprise to people, and often
> well into their Python learning experience. We often repeat, "it isn't
> parens that make a tuple, but a comma." Then why when displaying a
> tuple does Python insist on using parens around it?
>
> >>> 1, 2, 3
> (1, 2, 3)

I would say:
- because it's easier to read (subjectively so, I guess)
- because it's easier to copy/paste into an expression without running
into precedence problems

Masklinn

unread,
Dec 12, 2011, 8:25:42 AM12/12/11
to Ned Batchelder, Antoine Pitrou, python...@python.org
On 2011-12-12, at 14:15 , Ned Batchelder wrote:
>
> Believe me, I understand the issues. It is true, though that the single-element tuple syntax is often a surprise to people, and often well into their Python learning experience. We often repeat, "it isn't parens that make a tuple, but a comma." Then why when displaying a tuple does Python insist on using parens around it?
>
> >>> 1, 2, 3
> (1, 2, 3)
>
> I'm not saying it shouldn't, it's a rhetorical question. The repr of a tuple always includes parens, even though "parens don't make a tuple." It's the best of all the options, but let's face it: it's confusing.
An alternative would be to just drop the literal unary tuple. I would be kind-of sad as I'd lose the ability to unpack singleton iterables, but it would "fix" the issue.

FWIW, Haskell does not have a literal singleton (the standard defines "unit" `()` and 2-tuple through 15-tuple)

Ned Batchelder

unread,
Dec 12, 2011, 8:26:16 AM12/12/11
to Antoine Pitrou, Python-Ideas
On 12/12/2011 8:19 AM, Antoine Pitrou wrote:
> Le lundi 12 décembre 2011 à 08:15 -0500, Ned Batchelder a écrit :
>> Believe me, I understand the issues. It is true, though that the
>> single-element tuple syntax is often a surprise to people, and often
>> well into their Python learning experience. We often repeat, "it isn't
>> parens that make a tuple, but a comma." Then why when displaying a
>> tuple does Python insist on using parens around it?
>>
>> >>> 1, 2, 3
>> (1, 2, 3)
> I would say:
> - because it's easier to read (subjectively so, I guess)
> - because it's easier to copy/paste into an expression without running
> into precedence problems
Yes, those are good reasons. And you can see why Python's insistence on
showing tuples with parens contributes to the gotcha that the parens are
a red herring, and it's the commas that are important. Also, who hasn't
said this to a beginner: "lists and tuples are very similar, lists use
square brackets, tuples use parens"? Somehow, in a list, the commas
don't make a tuple... It's complicated.

I welcome Richard's help in explaining this issue to beginners.

--Ned.

Matt Joiner

unread,
Dec 12, 2011, 8:41:41 AM12/12/11
to Ned Batchelder, Antoine Pitrou, Python-Ideas
Here's some crazy ideas:
* Don't allow iteration on tuples. for i in tuple
* Make the singleton tuple the default object representation: (), a,
(a, b), (a, b, c), ...
* Steal STM, Channels, and sparks from Haskell
* Profit.

--
ಠ_ಠ

Matt Joiner

unread,
Dec 12, 2011, 8:44:46 AM12/12/11
to Masklinn, python...@python.org
> The only people I'd see confused by this are those with significant> C++ experience, where assignment of references does indeed go through> a copy of the object itself.

ಠ_ಠ

--
ಠ_ಠ

Terry Reedy

unread,
Dec 12, 2011, 11:27:08 AM12/12/11
to python...@python.org
On 12/12/2011 8:15 AM, Ned Batchelder wrote:

> parens that make a tuple, but a comma." Then why when displaying a tuple
> does Python insist on using parens around it?
>
> >>> 1, 2, 3
> (1, 2, 3)
>
> I'm not saying it shouldn't, it's a rhetorical question.

Actually, I would agree that it would be better to not mislead by not
printing the parens unless necessary. (If done from the beginning.)
For something like
>>> t = 1,2
>>> l = list(t)
>>> t,l
((1, 2), [1, 2])

the outer parens are also unnecessary (while the inner ones are needed)
and make the result less easy to read. But the easiest way to not print
them would probably be to test the output string after it is constructed
for beginning with '(' and ending with ')' and strip them off if so.

--
Terry Jan Reedy

Terry Reedy

unread,
Dec 12, 2011, 11:40:03 AM12/12/11
to python...@python.org
On 12/12/2011 4:00 AM, Masklinn wrote:
> On 2011-12-12, at 09:55 , Terry Reedy wrote:
>> On 12/12/2011 12:59 AM, Mike Meyer wrote:
>>> On Sun, 11 Dec 2011 19:34:07 -0500
>>> Ned Batchelder<n...@nedbatchelder.com> wrote:
>>>> Richard, I don't think I can provide you with a "why" for dynamic
>>>> typing.
>>>
>>> And this is the wrong place to ask. Dynamic typing and naming objects
>>> dates back to the precursors to LISP in the mid 50s. You should be
>>> asking the people who made that decision.
>> List was designed for writing algorithms.
> I think you meant "lisp" here ;)

Definitely.

>>> By the same token, have you asked anyone why C/Java/etc. have static
>>> typing and name locations? It's an equally valid question.
>> C was designed for writing a computing machine operating system with mutable sequential memory slots numbered from 0 to 2**n - 1.
> On the other hand, there are very few typed assemblies.

The question of typing is somewhat orthogonal to that of naming value
objects versus storage locations. There are strong stactic typed named
value languages like ML. They even require different operators for int
and float arithmetic, just like assembler.

Assemblers also type data versus address registers and may have signed
versus unsigned int operations. But most typing has to be done by the
programmer, just as C requires the programmer to do garbage collection.

--
Terry Jan Reedy

Masklinn

unread,
Dec 12, 2011, 11:49:10 AM12/12/11
to Terry Reedy, python...@python.org
On 2011-12-12, at 17:40 , Terry Reedy wrote:
>>>> By the same token, have you asked anyone why C/Java/etc. have static
>>>> typing and name locations? It's an equally valid question.
>>> C was designed for writing a computing machine operating system with mutable sequential memory slots numbered from 0 to 2**n - 1.
>> On the other hand, there are very few typed assemblies.
> The question of typing is somewhat orthogonal to that of naming value objects versus storage locations. There are strong stactic typed named value languages like ML.
I know, hence my quoting the part about typing, not the part about variable semantics.

> They even require different operators for int and float arithmetic, just like assembler.

That's got nothing to do with the typing or binding disciplines though, it's an issue of ML's type system. Haskell does not have that issue and is arguably more statically typed than MLs.

> Assemblers also type data versus address registers and may have signed versus unsigned int operations. But most typing has to be done by the programmer

Which is the point I was trying to make, a point which kind-of goes against the justification used for C being statically typed, as assemblies are also designed for driving systems with mutable sequential memory slots.

Terry Reedy

unread,
Dec 12, 2011, 12:21:49 PM12/12/11
to python...@python.org
On 12/12/2011 11:49 AM, Masklinn wrote:

> Which is the point I was trying to make, a point which kind-of goes
> against the justification used for C being statically typed, as
> assemblies are also designed for driving systems with mutable
> sequential memory slots.

C was designed to remove some, but just some, of the burden of managing
blocks of memory. One of the unfortunate ironies of C is that C
programmers tend to forget that they *are* working with contiguous
mutable blocks and not with isolated Python-like objects. Hence
buffer-run exploits by malware writers who *do* remember and study the
exact order of memory blocks in particular binaries.

--
Terry Jan Reedy

Mike Meyer

unread,
Dec 12, 2011, 12:37:22 PM12/12/11
to python...@python.org
On Mon, 12 Dec 2011 11:40:03 -0500
Terry Reedy <tjr...@udel.edu> wrote:
> On 12/12/2011 4:00 AM, Masklinn wrote:
> > On 2011-12-12, at 09:55 , Terry Reedy wrote:
> >> On 12/12/2011 12:59 AM, Mike Meyer wrote:
> >>> By the same token, have you asked anyone why C/Java/etc. have
> >>> static typing and name locations? It's an equally valid question.
> >> C was designed for writing a computing machine operating system
> >> with mutable sequential memory slots numbered from 0 to 2**n - 1.
> > On the other hand, there are very few typed assemblies.
> The question of typing is somewhat orthogonal to that of naming value
> objects versus storage locations. There are strong stactic typed
> named value languages like ML. They even require different operators
> for int and float arithmetic, just like assembler.

Yup. You can also find dynamically typed named locations languages,
like BCPL (though "untyped" might be more descriptive). It also has
different operators for int and float arithmetic, because the
locations don't have type information, so it has to come from the
operator.

<mike

Greg Ewing

unread,
Dec 12, 2011, 4:13:22 PM12/12/11
to python...@python.org
Masklinn wrote:

> Of course technically that copy could very well be performed
> "on write". This would significantly complexify the runtime as well.

It could also lead to a lot of gratuitous inefficiency
in programs, as people got into the habit of modifying
anything passed to them in the knowledge that it
wouldn't do any harm, but without considering the cost
of all the implicit copying that it caused.

--
Greg

Greg Ewing

unread,
Dec 12, 2011, 4:21:11 PM12/12/11
to python...@python.org
Masklinn wrote:

> FWIW, Haskell does not have a literal singleton (the standard defines
> "unit" `()` and 2-tuple through 15-tuple)

That's because, due to its static typing, there is no
reason you would ever need to use a 1-tuple rather than
a bare value. We're not that lucky in Python, though.

--
Greg

Stephen J. Turnbull

unread,
Dec 12, 2011, 9:44:29 PM12/12/11
to Greg Ewing, python...@python.org
Greg Ewing writes:
> Masklinn wrote:
>
> > FWIW, Haskell does not have a literal singleton (the standard defines
> > "unit" `()` and 2-tuple through 15-tuple)
>
> That's because, due to its static typing, there is no
> reason you would ever need to use a 1-tuple rather than
> a bare value. We're not that lucky in Python, though.

I think you have misstated your point? That's not due to static
typing, that's because you may *always* identify 1-factor products
with the only factor, and Haskell made a deliberate decision to
consistently represent the isomorphism class by the factor rather than
the product. Eg, Python uses the same strategy for characters and
strings (characters as a category are isomorphic to one-element
strings), but chose a different representative (the one-element string
rather than the character).

As for Python's relative lack of luck, I think that's unlikely to be
the reason why things are as they are. I'm pretty sure that Python's
omission of character objects was deliberate<wink/>. I think it was
the right choice, given that (1) despite category theory, I believe we
think of tuples as composite objects (at least I do), but strings seem
to be more "monolithic" in some sense, and (2) pretty much all
languages have chosen to leave identifiers unmarked (I guess Perl and
many template languages should be considered exceptions), and mark
strings and characters (often both with quotation marks, sometimes
characters with a prefix) -- may as well go with the familiar if
there's no good reason otherwise.

Georg Brandl

unread,
Dec 15, 2011, 3:24:27 PM12/15/11
to python...@python.org
On 12/13/2011 03:44 AM, Stephen J. Turnbull wrote:
> Greg Ewing writes:
> > Masklinn wrote:
> >
> > > FWIW, Haskell does not have a literal singleton (the standard defines
> > > "unit" `()` and 2-tuple through 15-tuple)
> >
> > That's because, due to its static typing, there is no
> > reason you would ever need to use a 1-tuple rather than
> > a bare value. We're not that lucky in Python, though.
>
> I think you have misstated your point? That's not due to static
> typing, that's because you may *always* identify 1-factor products
> with the only factor, and Haskell made a deliberate decision to
> consistently represent the isomorphism class by the factor rather than
> the product.

Well, I would say the reason is that the type "tuple of any length" does
not exist in Haskell. So there's no way you will have to pass a 1-tuple
to a function that operates on tuples only.

But of course, if we all used tuples as tuples only, we wouldn't have to do
that either. It's only because we use tuples as sequences every so often.

Georg

Ned Batchelder

unread,
Dec 15, 2011, 3:42:42 PM12/15/11
to Georg Brandl, python...@python.org
On 12/15/2011 3:24 PM, Georg Brandl wrote:
> On 12/13/2011 03:44 AM, Stephen J. Turnbull wrote:
>> Greg Ewing writes:
>> > Masklinn wrote:
>> >
>> > > FWIW, Haskell does not have a literal singleton (the standard defines
>> > > "unit" `()` and 2-tuple through 15-tuple)
>> >
>> > That's because, due to its static typing, there is no
>> > reason you would ever need to use a 1-tuple rather than
>> > a bare value. We're not that lucky in Python, though.
>>
>> I think you have misstated your point? That's not due to static
>> typing, that's because you may *always* identify 1-factor products
>> with the only factor, and Haskell made a deliberate decision to
>> consistently represent the isomorphism class by the factor rather than
>> the product.
> Well, I would say the reason is that the type "tuple of any length" does
> not exist in Haskell. So there's no way you will have to pass a 1-tuple
> to a function that operates on tuples only.
>
> But of course, if we all used tuples as tuples only, we wouldn't have to do
> that either. It's only because we use tuples as sequences every so often.
This is another place where Python is inconsistent. We're told, "lists
are for homogenous sequences of varying length, like a C array; tuples
are for heterogenous aggregations of known length, like a C struct."
Then we define a function foo(*args), and Python gives us a tuple! :-(

--Ned.

Georg Brandl

unread,
Dec 15, 2011, 3:51:01 PM12/15/11
to python...@python.org
On 12/15/2011 09:42 PM, Ned Batchelder wrote:
> On 12/15/2011 3:24 PM, Georg Brandl wrote:
>> On 12/13/2011 03:44 AM, Stephen J. Turnbull wrote:
>>> Greg Ewing writes:
>>> > Masklinn wrote:
>>> >
>>> > > FWIW, Haskell does not have a literal singleton (the standard defines
>>> > > "unit" `()` and 2-tuple through 15-tuple)
>>> >
>>> > That's because, due to its static typing, there is no
>>> > reason you would ever need to use a 1-tuple rather than
>>> > a bare value. We're not that lucky in Python, though.
>>>
>>> I think you have misstated your point? That's not due to static
>>> typing, that's because you may *always* identify 1-factor products
>>> with the only factor, and Haskell made a deliberate decision to
>>> consistently represent the isomorphism class by the factor rather than
>>> the product.
>> Well, I would say the reason is that the type "tuple of any length" does
>> not exist in Haskell. So there's no way you will have to pass a 1-tuple
>> to a function that operates on tuples only.
>>
>> But of course, if we all used tuples as tuples only, we wouldn't have to do
>> that either. It's only because we use tuples as sequences every so often.
> This is another place where Python is inconsistent. We're told, "lists
> are for homogenous sequences of varying length, like a C array; tuples
> are for heterogenous aggregations of known length, like a C struct."
> Then we define a function foo(*args), and Python gives us a tuple! :-(

Yep. To be consistent, we'd need an "immutable list" type...
another thing that Haskell has no need for :)

Antoine Pitrou

unread,
Dec 15, 2011, 3:51:47 PM12/15/11
to python...@python.org
On Thu, 15 Dec 2011 15:42:42 -0500
Ned Batchelder <n...@nedbatchelder.com>
wrote:

> On 12/15/2011 3:24 PM, Georg Brandl wrote:
> > On 12/13/2011 03:44 AM, Stephen J. Turnbull wrote:
> >> Greg Ewing writes:
> >> > Masklinn wrote:
> >> >
> >> > > FWIW, Haskell does not have a literal singleton (the standard defines
> >> > > "unit" `()` and 2-tuple through 15-tuple)
> >> >
> >> > That's because, due to its static typing, there is no
> >> > reason you would ever need to use a 1-tuple rather than
> >> > a bare value. We're not that lucky in Python, though.
> >>
> >> I think you have misstated your point? That's not due to static
> >> typing, that's because you may *always* identify 1-factor products
> >> with the only factor, and Haskell made a deliberate decision to
> >> consistently represent the isomorphism class by the factor rather than
> >> the product.
> > Well, I would say the reason is that the type "tuple of any length" does
> > not exist in Haskell. So there's no way you will have to pass a 1-tuple
> > to a function that operates on tuples only.
> >
> > But of course, if we all used tuples as tuples only, we wouldn't have to do
> > that either. It's only because we use tuples as sequences every so often.
> This is another place where Python is inconsistent. We're told, "lists
> are for homogenous sequences of varying length, like a C array; tuples
> are for heterogenous aggregations of known length, like a C struct."
> Then we define a function foo(*args), and Python gives us a tuple! :-(

How is it inconsistent? Function signatures generally have a fixed (or
mostly fixed) number of heterogenous arguments.

Regards

Antoine.

Tim Delaney

unread,
Dec 15, 2011, 3:59:26 PM12/15/11
to python...@python.org
On 16 December 2011 07:42, Ned Batchelder <n...@nedbatchelder.com> wrote:
This is another place where Python is inconsistent.  We're told, "lists are for homogenous sequences of varying length, like a C array; tuples are for heterogenous aggregations of known length, like a C struct."   Then we define a function foo(*args), and Python gives us a tuple!  :-(

How is that inconsistent? At the point where the tuple is constructed, it has a known length. And it's definitely a heterogenous aggregation.

I think where you're getting confused is that you're thinking of a *single* struct definition for every tuple. But the concept you should have is that each tuple has its own struct definition. And with functions, the structure is defined at function call time.

Tim Delaney 

Ned Batchelder

unread,
Dec 15, 2011, 4:00:03 PM12/15/11
to Antoine Pitrou, python...@python.org
What? The whole point of the "def foo(*args)" syntax is so a function
can take an unknown-length list of arguments, which will be treated
uniformly.

--Ned.

Masklinn

unread,
Dec 15, 2011, 4:05:26 PM12/15/11
to Antoine Pitrou, python...@python.org
But *args is mostly dedicated to an arbitrary (non-fixed) number of homogenous arguments. In statically typed languages with varargs, they're generally represented as an array-type collection.

It's either that or a "rest of that crap" catchall used to forward arguments without caring much for what they are.

Masklinn

unread,
Dec 15, 2011, 4:06:43 PM12/15/11
to Ned Batchelder, Antoine Pitrou, python...@python.org
On 2011-12-15, at 22:00 , Ned Batchelder wrote:
>
> What? The whole point of the "def foo(*args)" syntax is so a function can take an unknown-length list of arguments, which will be treated uniformly.
That's not *entirely* true, it's also used for proxy functions, in order to just pass a bunch of arguments (positional or keywords) along to the next level without having to unpack and repack them one by one.

Ned Batchelder

unread,
Dec 15, 2011, 4:06:59 PM12/15/11
to Ethan Furman, python...@python.org
On 12/15/2011 4:00 PM, Ethan Furman wrote:
Ned Batchelder wrote:
This is another place where Python is inconsistent.  We're told, "lists are for homogenous sequences of varying length, like a C array; tuples are for heterogenous aggregations of known length, like a C struct."   Then we define a function foo(*args), and Python gives us a tuple!  :-(

Where is that in the docs?  Sounds like a patch is needed:

"lists are for sequences where items need to be added/removed; tuples are for sequences/aggregations where items will not be added/removed once the tuple is created"

I don't know if it appears in the docs, but I hear it all the time, and Guido has said it (http://mail.python.org/pipermail/python-dev/2003-March/033964.html):
Tuples are for heterogeneous data, list are for homogeneous data.
Tuples are *not* read-only lists.
I don't want to get too far off the original point, which was: Python isn't as simple as we'd like to thing, and even smart beginners can be tripped up by things we've provided to them.

--Ned.

~Ethan~

PS
As Antoine noted, a tuple for 'args' is appropriate, as once args is created at function call time, we won't be adding or removing from it.

Ned Batchelder

unread,
Dec 15, 2011, 4:09:31 PM12/15/11
to Tim Delaney, python...@python.org
Tim, this seems misguided to me.  Finish that foo function definition: it will *have* to have  "for a in args:"   Since I don't know the length of args when I write the function, I have to treat it as an unknown length.  What good is a "structure" that changes length and definition with every instance?  I think you're trying too hard to fit the reality into the theory.

--Ned.

Tim Delaney 

Ned Batchelder

unread,
Dec 15, 2011, 4:11:10 PM12/15/11
to Masklinn, Antoine Pitrou, python...@python.org
On 12/15/2011 4:06 PM, Masklinn wrote:
> On 2011-12-15, at 22:00 , Ned Batchelder wrote:
>> What? The whole point of the "def foo(*args)" syntax is so a function can take an unknown-length list of arguments, which will be treated uniformly.
> That's not *entirely* true, it's also used for proxy functions, in order to just pass a bunch of arguments (positional or keywords) along to the next level without having to unpack and repack them one by one.
We are in agreement: I don't know the length, and I will treat them
uniformly (pass them all through to the next function).

--Ned.

Ethan Furman

unread,
Dec 15, 2011, 4:00:03 PM12/15/11
to python...@python.org
Ned Batchelder wrote:
> This is another place where Python is inconsistent. We're told, "lists
> are for homogenous sequences of varying length, like a C array; tuples
> are for heterogenous aggregations of known length, like a C struct."
> Then we define a function foo(*args), and Python gives us a tuple! :-(

Where is that in the docs? Sounds like a patch is needed:

"lists are for sequences where items need to be added/removed; tuples
are for sequences/aggregations where items will not be added/removed
once the tuple is created"

~Ethan~

PS
As Antoine noted, a tuple for 'args' is appropriate, as once args is
created at function call time, we won't be adding or removing from it.

Ethan Furman

unread,
Dec 15, 2011, 4:24:26 PM12/15/11
to python...@python.org
Ned Batchelder wrote:
> On 12/15/2011 3:59 PM, Tim Delaney wrote:
>> On 16 December 2011 07:42, Ned Batchelder wrote:
>>
>> This is another place where Python is inconsistent. We're told,
>> "lists are for homogenous sequences of varying length, like a C
>> array; tuples are for heterogenous aggregations of known length,
>> like a C struct." Then we define a function foo(*args), and
>> Python gives us a tuple! :-(
>>
>>
>> How is that inconsistent? At the point where the tuple is constructed,
>> it has a known length. And it's definitely a heterogenous aggregation.
>>
>> I think where you're getting confused is that you're thinking of a
>> *single* struct definition for every tuple. But the concept you should
>> have is that each tuple has its own struct definition. And with
>> functions, the structure is defined at function call time.
>>
> Tim, this seems misguided to me. Finish that foo function definition:
> it will *have* to have "for a in args:" Since I don't know the length
> of args when I write the function, I have to treat it as an unknown
> length. What good is a "structure" that changes length and definition
> with every instance? I think you're trying too hard to fit the reality
> into the theory.

Python is a dynamic language -- why can't it have dynamic structs?

~Ethan~

Ned Batchelder

unread,
Dec 15, 2011, 4:54:16 PM12/15/11
to Ethan Furman, python...@python.org
On 12/15/2011 4:24 PM, Ethan Furman wrote:
> Ned Batchelder wrote:
>> On 12/15/2011 3:59 PM, Tim Delaney wrote:
>>> On 16 December 2011 07:42, Ned Batchelder wrote:
>>>
>>> This is another place where Python is inconsistent. We're told,
>>> "lists are for homogenous sequences of varying length, like a C
>>> array; tuples are for heterogenous aggregations of known length,
>>> like a C struct." Then we define a function foo(*args), and
>>> Python gives us a tuple! :-(
>>>
>>>
>>> How is that inconsistent? At the point where the tuple is
>>> constructed, it has a known length. And it's definitely a
>>> heterogenous aggregation.
>>>
>>> I think where you're getting confused is that you're thinking of a
>>> *single* struct definition for every tuple. But the concept you
>>> should have is that each tuple has its own struct definition. And
>>> with functions, the structure is defined at function call time.
>>>
>> Tim, this seems misguided to me. Finish that foo function
>> definition: it will *have* to have "for a in args:" Since I don't
>> know the length of args when I write the function, I have to treat it
>> as an unknown length. What good is a "structure" that changes length
>> and definition with every instance? I think you're trying too hard
>> to fit the reality into the theory.
>
> Python is a dynamic language -- why can't it have dynamic structs?
>
I honestly don't know how to interpret this. In what way is it a
"struct" if I have no idea how many fields it has, or how they might
differ from each other? I think we've lost the utility of this discussion.

--Ned.

Masklinn

unread,
Dec 15, 2011, 4:55:54 PM12/15/11
to Ned Batchelder, Antoine Pitrou, python...@python.org
On 15 déc. 2011, at 22:11, Ned Batchelder <n...@nedbatchelder.com> wrote:
> On 12/15/2011 4:06 PM, Masklinn wrote:
>> On 2011-12-15, at 22:00 , Ned Batchelder wrote:
>>> What? The whole point of the "def foo(*args)" syntax is so a function can take an unknown-length list of arguments, which will be treated uniformly.
>> That's not *entirely* true, it's also used for proxy functions, in order to just pass a bunch of arguments (positional or keywords) along to the next level without having to unpack and repack them one by one.
> We are in agreement: I don't know the length, and I will treat them uniformly (pass them all through to the next function).
Ah yes, you're right, I had not considered this use case under that angle.

Nick Coghlan

unread,
Dec 15, 2011, 6:06:01 PM12/15/11
to Ned Batchelder, python...@python.org
On Fri, Dec 16, 2011 at 7:06 AM, Ned Batchelder <n...@nedbatchelder.com> wrote:
> Where is that in the docs?  Sounds like a patch is needed:
>
> "lists are for sequences where items need to be added/removed; tuples are
> for sequences/aggregations where items will not be added/removed once the
> tuple is created"
>
> I don't know if it appears in the docs, but I hear it all the time, and
> Guido has said it
> (http://mail.python.org/pipermail/python-dev/2003-March/033964.html):
>
> Tuples are for heterogeneous data, list are for homogeneous data.
> Tuples are *not* read-only lists.
>
> I don't want to get too far off the original point, which was: Python isn't
> as simple as we'd like to thing, and even smart beginners can be tripped up
> by things we've provided to them.

Guido has softened his stance on that point over the years (IIRC, the
question came up explicitly in the discussion over making tuple()
fully conform to the Sequence ABC - you can guess the outcome from the
fact that tuple these days in fact *does* fully conform to that ABC,
including the previously missing index() and count() methods).

So tuples have two valid use cases: as read-only arbitrary-length
sequences of homogeneous data and as fixed-length sequences of
heterogeneous data.

These days, the latter use case is often better served by creating a
collections.namedtuple() definition rather than using a bare tuple
directly.

Cheers,
Nick.

--
Nick Coghlan   |   ncog...@gmail.com   |   Brisbane, Australia

Terry Reedy

unread,
Dec 15, 2011, 8:16:40 PM12/15/11
to python...@python.org
On 12/15/2011 3:42 PM, Ned Batchelder wrote:

> This is another place where Python is inconsistent. We're told, "lists
> are for homogenous sequences of varying length, like a C array; tuples
> are for heterogenous aggregations of known length, like a C struct."

I have not been told that for several years, and I am pretty sure you
will not find any such thing in the current docs. I consider it pretty
much obsolete, as the differences that flowed from that idea are gone.
In Python 3, tuples have all the non-mutating sequence methods that list
does. The situation was much different in 1.4.

--
Terry Jan Reedy

Guido van Rossum

unread,
Dec 15, 2011, 8:39:04 PM12/15/11
to Terry Reedy, python...@python.org
On Thu, Dec 15, 2011 at 5:16 PM, Terry Reedy <tjr...@udel.edu> wrote:
On 12/15/2011 3:42 PM, Ned Batchelder wrote:

This is another place where Python is inconsistent. We're told, "lists
are for homogenous sequences of varying length, like a C array; tuples
are for heterogenous aggregations of known length, like a C struct."

I have not been told that for several years, and I am pretty sure you will not find any such thing in the current docs. I consider it pretty much obsolete, as the differences that flowed from that idea are gone. In Python 3, tuples have all the non-mutating sequence methods that list does. The situation was much different in 1.4.

I strongly disagree. Being immutable sequences (i.e. homogeneous) is a minor secondary role for tuples. Their primary role remains to hold a small bunch of heterogeneous values -- like namedtuple, but without needing forethought. A good example are dictionary items -- these are (key, value) pairs where for a given dict, the keys are all of the same type (or of a small set of related types) and ditto for the values, but the key type and the value types are unrelated.

--
--Guido van Rossum (python.org/~guido)

Ben Finney

unread,
Dec 15, 2011, 9:23:17 PM12/15/11
to python...@python.org
Ned Batchelder <n...@nedbatchelder.com>
writes:

> This is another place where Python is inconsistent. We're told, "lists
> are for homogenous sequences of varying length, like a C array; tuples
> are for heterogenous aggregations of known length, like a C struct."

I think that's a poor rendition of the distinction. Rather, what I
advise is: if the *meaning* of an item depends on its position in the
sequence (like with a C struct), use a tuple. If the meaning of an item
is unaffected by its position in the sequence, use a list.

> Then we define a function foo(*args), and Python gives us a tuple! :-(

Yes, exactly: the positional arguments to the function are *not* a
homogeneous sequence, so a list doesn't connote the right thing. The
position is important – we call them “positional arguments” – so a tuple
makes sense.

--
\ “I am the product of millions of generations of individuals who |
`\ each fought against a hostile universe and won, and I aim to |
_o__) maintain the tradition.” —Paul Z. Myers, 2009-09-12 |
Ben Finney

Ned Batchelder

unread,
Dec 15, 2011, 9:55:16 PM12/15/11
to Ben Finney, python...@python.org

On 12/15/2011 9:23 PM, Ben Finney wrote:
> Ned Batchelder<n...@nedbatchelder.com>


> writes:
>
>> Then we define a function foo(*args), and Python gives us a tuple! :-(
> Yes, exactly: the positional arguments to the function are *not* a
> homogeneous sequence, so a list doesn't connote the right thing. The
> position is important – we call them “positional arguments” – so a tuple
> makes sense.

In general the positional arguments to a function are not homogenous,
but the foo(*args) syntax is for precisely when you don't know how many
args you will get, and you will of necessity treat them homogenously,
no? We've been through this in another branch of this thread...

--Ned.

Ned Batchelder

unread,
Dec 15, 2011, 9:56:27 PM12/15/11
to Guido van Rossum, python...@python.org, Terry Reedy
Could you explain why the foo(*args) syntax creates args as a tuple rather than a list?

--Ned.

--
--Guido van Rossum (python.org/~guido)


Stephen J. Turnbull

unread,
Dec 15, 2011, 10:08:55 PM12/15/11
to Ned Batchelder, Antoine Pitrou, python...@python.org
Ned Batchelder writes:
> On 12/15/2011 4:06 PM, Masklinn wrote:
> > On 2011-12-15, at 22:00 , Ned Batchelder wrote:
> >> What? The whole point of the "def foo(*args)" syntax is so a function can take an unknown-length list of arguments, which will be treated uniformly.
> > That's not *entirely* true, it's also used for proxy functions, in order to just pass a bunch of arguments (positional or keywords) along to the next level without having to unpack and repack them one by one.
> We are in agreement: I don't know the length, and I will treat them
> uniformly (pass them all through to the next function).

That's way too high a level of abstraction.

The discussion I found persuasive is the varargs analogy.

/* "Hello Ned" in C */
#include <stdio.h>
char *s = "string";
int i = 1;
double x = 3.1415926;

int main (int argc, char *argv[]) {
printf ("string %s, int %d, double %f\nHello Ned! Are we homogenized yet?");
exit(-1);
}

Of course it still demands "correct perception" on the part of the
user, but I don't see this as "inconsistent".

Guido van Rossum

unread,
Dec 15, 2011, 10:35:21 PM12/15/11
to Ned Batchelder, python...@python.org, Terry Reedy
On Thu, Dec 15, 2011 at 6:56 PM, Ned Batchelder <n...@nedbatchelder.com> wrote:
On 12/15/2011 8:39 PM, Guido van Rossum wrote:
On Thu, Dec 15, 2011 at 5:16 PM, Terry Reedy <tjr...@udel.edu> wrote:
On 12/15/2011 3:42 PM, Ned Batchelder wrote:

This is another place where Python is inconsistent. We're told, "lists
are for homogenous sequences of varying length, like a C array; tuples
are for heterogenous aggregations of known length, like a C struct."

I have not been told that for several years, and I am pretty sure you will not find any such thing in the current docs. I consider it pretty much obsolete, as the differences that flowed from that idea are gone. In Python 3, tuples have all the non-mutating sequence methods that list does. The situation was much different in 1.4.

I strongly disagree. Being immutable sequences (i.e. homogeneous) is a minor secondary role for tuples. Their primary role remains to hold a small bunch of heterogeneous values -- like namedtuple, but without needing forethought. A good example are dictionary items -- these are (key, value) pairs where for a given dict, the keys are all of the same type (or of a small set of related types) and ditto for the values, but the key type and the value types are unrelated.
Could you explain why the foo(*args) syntax creates args as a tuple rather than a list?

It's a historical accident. In ABC, functions didn't have multiple arguments -- instead there was a single argument that was a tuple. If you go back way, way in Python's early history (before 1.0 I think) you'll find that arguments kind of worked the same way. Then an idiom developed to accept a variable number of arguments, in order to support default argument values (because Python's tuples, unlike ABC's, were sequences even then). This turned out to be awkward if you wanted 1 or 2 arguments (the 1-arg case had to be dealt with special because you'd receive a plain value instead of a tuple) and then the *args and arg=value syntax was invented. But because previously varargs had been tuples, we kept them tuples. (I think this was also in the days that you couldn't unpack a list -- but I'm not actually sure of that. I do know that tuple unpacking was always in the language.)

Mike Meyer

unread,
Dec 15, 2011, 11:34:28 PM12/15/11