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, <python-ideas-request@python.org> wrote:

On 2011-12-11, at 22:30 , Richard Prosser wrote:
Although that way may not be obvious at first unless you're Dutch.
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).

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

On Sun, 11 Dec 2011 19:34:07 -0500 Ned Batchelder <ned@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 <mwm@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

On 12/12/2011 12:59 AM, Mike Meyer wrote:
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 12/12/2011 4:00 AM, Masklinn wrote:
Definitely.
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:
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:
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 <tjreedy@udel.edu> wrote:
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

Richard Prosser wrote:
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

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.

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 <masklinn@masklinn.net> wrote:
-- ಠ_ಠ

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

On 2011-12-11, at 22:30 , Richard Prosser wrote:
Although that way may not be obvious at first unless you're Dutch.
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).

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

On Sun, 11 Dec 2011 19:34:07 -0500 Ned Batchelder <ned@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 <mwm@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

On 12/12/2011 12:59 AM, Mike Meyer wrote:
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 12/12/2011 4:00 AM, Masklinn wrote:
Definitely.
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:
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:
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 <tjreedy@udel.edu> wrote:
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

Richard Prosser wrote:
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

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.

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 <masklinn@masklinn.net> wrote:
-- ಠ_ಠ

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