Re: [Python-ideas] Python Isn't Perfect: adding a 'gotchas' section to the tutorial
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,
Message: 2 Date: Sat, 10 Dec 2011 13:34:15 -0500 From: Ned Batchelder
To: Richard Prosser Cc: python-ideas@python.org Subject: Re: [Python-ideas] Python Isn't Perfect: adding a 'gotchas' section to the tutorial Message-ID: <4EE3A627.8010002@nedbatchelder.com> Content-Type: text/plain; charset=ISO-8859-1; format=flowed 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.
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.
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
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:
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,
mailto:python-ideas-request@python.org> wrote: Message: 2 Date: Sat, 10 Dec 2011 13:34:15 -0500 From: Ned Batchelder
mailto:ned@nedbatchelder.com> To: Richard Prosser mailto:richard.prosser@mail.com> Cc: python-ideas@python.org mailto:python-ideas@python.org Subject: Re: [Python-ideas] Python Isn't Perfect: adding a 'gotchas' section to the tutorial Message-ID: <4EE3A627.8010002@nedbatchelder.com mailto:4EE3A627.8010002@nedbatchelder.com> Content-Type: text/plain; charset=ISO-8859-1; format=flowed 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.
_______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
On Sun, 11 Dec 2011 19:34:07 -0500
Ned Batchelder
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.
On 12/12/2011 12:59 AM, Mike Meyer wrote:
On Sun, 11 Dec 2011 19:34:07 -0500 Ned Batchelder
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
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
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.
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
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
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.
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
On Mon, 12 Dec 2011 11:40:03 -0500
Terry Reedy
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.
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
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
On 2011-12-12, at 06:11 , Greg Ewing wrote: 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.
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.
ಠ_ಠ
On Mon, Dec 12, 2011 at 7:59 PM, Masklinn
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
On 2011-12-12, at 06:11 , Greg Ewing wrote: 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.
_______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
-- ಠ_ಠ
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
participants (7)
-
Greg Ewing
-
Masklinn
-
Matt Joiner
-
Mike Meyer
-
Ned Batchelder
-
Richard Prosser
-
Terry Reedy