|
From: Bruce S. <bas...@un...> - 2002-10-04 12:15:11
|
A VPython user sent me a small program that behaved oddly, and I thought I
should share my analysis, since it involves an aspect of Python that is
subtle and may be missed in early study of the language. Fortunately it
rarely bites students writing computational physics programs!
Early in the program the user said "rinitial = ball.pos" which means "assign
an additional name to ball.pos, so that in the future one can refer to the
ball's position either by the label (name) ball.pos or the label (name)
rinitial". You can have lots of names pasted onto the same thing. The puzzle
for the user was that later in the program (after moving the ball around),
printing rinitial showed the new value of ball.pos, not the initial value.
This multiple labeling has consequences only with "mutable" objects such as
lists -- objects whose values can be changed in situ. For example, if you
say "a = 5" and then "b = a", and then say "a = 7", b will still have the
value 5. When you assign 7 to a, you create a new object ("7") and attach
the label "a" to it, so b continues to be a label for the object "5".
But with "rinitial = ball.pos", you can actually change ball.pos without
creating a new object. For example, you might say "ball.pos.y = 7" in which
case the 2nd element in the ball.pos list has changed (without affecting the
other two elements). Since rinitial is a label for ball.pos, printing
rinitial shows you the new value of ball.pos.
A list such as [1,2,3] is mutable. The Visual vectors are mutable. A 'tuple'
such as (1,2,3) is not mutable. Constants such as 3 or pi or a string such
as 'cat' are not mutable.
Needless to say, it took me a while to pay attention to "mutability" as an
important property of Python objects!
Bruce
|
|
From: Bruce S. <bas...@un...> - 2002-10-04 12:15:22
|
A VPython user sent me a small program that behaved oddly, and I thought I
should share my analysis, since it involves an aspect of Python that is
subtle and may be missed in early study of the language. Fortunately it
rarely bites students writing computational physics programs!
Early in the program the user said "rinitial = ball.pos" which means "assign
an additional name to ball.pos, so that in the future one can refer to the
ball's position either by the label (name) ball.pos or the label (name)
rinitial". You can have lots of names pasted onto the same thing. The puzzle
for the user was that later in the program (after moving the ball around),
printing rinitial showed the new value of ball.pos, not the initial value.
This multiple labeling has consequences only with "mutable" objects such as
lists -- objects whose values can be changed in situ. For example, if you
say "a = 5" and then "b = a", and then say "a = 7", b will still have the
value 5. When you assign 7 to a, you create a new object ("7") and attach
the label "a" to it, so b continues to be a label for the object "5".
But with "rinitial = ball.pos", you can actually change ball.pos without
creating a new object. For example, you might say "ball.pos.y = 7" in which
case the 2nd element in the ball.pos list has changed (without affecting the
other two elements). Since rinitial is a label for ball.pos, printing
rinitial shows you the new value of ball.pos.
A list such as [1,2,3] is mutable. The Visual vectors are mutable. A 'tuple'
such as (1,2,3) is not mutable. Constants such as 3 or pi or a string such
as 'cat' are not mutable.
Needless to say, it took me a while to pay attention to "mutability" as an
important property of Python objects!
Bruce
|
|
From: Arthur <aj...@ix...> - 2002-10-04 13:14:57
|
I think it worth supplementing Bruce's analysis with the solution to what
was trying to be accomplished by
rininitial = ball.pos
I believe either:
rinitial = ball.pos[:]
or
rinitial =copy(ball.pos)
would get one to where one is trying to go.
[:] returns a complete "slice" of the list.
copy, of course, a copy of the list.
In either case rinitial is no longer an additional name for ball.pos, but an
object independant of it, which will not be modified upon the modification
of ball.pos.
I think I have this right. Corrections welcome.
Art
----- Original Message -----
From: "Bruce Sherwood" <bas...@un...>
To: "vpusers" <vis...@li...>
Sent: Friday, October 04, 2002 8:16 AM
Subject: [Visualpython-users] Re: strange output
> A VPython user sent me a small program that behaved oddly, and I thought I
> should share my analysis, since it involves an aspect of Python that is
> subtle and may be missed in early study of the language. Fortunately it
> rarely bites students writing computational physics programs!
>
> Early in the program the user said "rinitial = ball.pos" which means
"assign
> an additional name to ball.pos, so that in the future one can refer to the
> ball's position either by the label (name) ball.pos or the label (name)
> rinitial". You can have lots of names pasted onto the same thing. The
puzzle
> for the user was that later in the program (after moving the ball around),
> printing rinitial showed the new value of ball.pos, not the initial value.
>
> This multiple labeling has consequences only with "mutable" objects such
as
> lists -- objects whose values can be changed in situ. For example, if you
> say "a = 5" and then "b = a", and then say "a = 7", b will still have the
> value 5. When you assign 7 to a, you create a new object ("7") and attach
> the label "a" to it, so b continues to be a label for the object "5".
>
> But with "rinitial = ball.pos", you can actually change ball.pos without
> creating a new object. For example, you might say "ball.pos.y = 7" in
which
> case the 2nd element in the ball.pos list has changed (without affecting
the
> other two elements). Since rinitial is a label for ball.pos, printing
> rinitial shows you the new value of ball.pos.
>
> A list such as [1,2,3] is mutable. The Visual vectors are mutable. A
'tuple'
> such as (1,2,3) is not mutable. Constants such as 3 or pi or a string such
> as 'cat' are not mutable.
>
> Needless to say, it took me a while to pay attention to "mutability" as an
> important property of Python objects!
>
> Bruce
>
>
>
> -------------------------------------------------------
> This sf.net email is sponsored by:ThinkGeek
> Welcome to geek heaven.
> http://thinkgeek.com/sf
> _______________________________________________
> Visualpython-users mailing list
> Vis...@li...
> https://lists.sourceforge.net/lists/listinfo/visualpython-users
>
|
|
From: Bruce S. <bas...@un...> - 2002-10-04 14:52:44
|
Many thanks for this important supplement, Arthur. I should have made this comment, but at the moment I was writing I couldn't remember how to do it! Bruce Sherwood ----- Original Message ----- From: "Arthur" <aj...@ix...> To: "Bruce Sherwood" <bas...@un...>; "vpusers" <vis...@li...> Sent: Friday, October 04, 2002 9:13 AM Subject: Re: [Visualpython-users] Re: strange output > I think it worth supplementing Bruce's analysis with the solution to what > was trying to be accomplished by > > rininitial = ball.pos > > I believe either: > > rinitial = ball.pos[:] > > or > > rinitial =copy(ball.pos) > > would get one to where one is trying to go. > > [:] returns a complete "slice" of the list. > copy, of course, a copy of the list. > > In either case rinitial is no longer an additional name for ball.pos, but an > object independant of it, which will not be modified upon the modification > of ball.pos. > > I think I have this right. Corrections welcome. > > Art |
|
From: Arthur <aj...@ix...> - 2002-10-04 22:04:25
|
I feared in the back of my mind, my answer posted this morning is dead wrong. My answer had assumed that ball.pos could be treated as a normal Python list Which is not the case. It is of type "vector", which is not a native Python type, but one coming over from the cvisual code. As such it turns out it is neither sliceable or copyable. The *right* answer here seems to be: rinitial=list(ball.pos) or rinitial=tuple(ball.pos) This stores rinital in a separate object not effected by changes in ball.pos, but which can work for ball.pos=rinital should one want to restore the initial position of ball. I think. Sorry for the misinfo. Art >I think it worth supplementing Bruce's analysis with the solution to what was trying to be accomplished by >rininitial = ball.pos >I believe either: >rinitial = ball.pos[:] >or >rinitial =copy(ball.pos) >would get one to where one is trying to go. >[:] returns a complete "slice" of the list. >copy, of course, a copy of the list. >In either case rinitial is no longer an additional name for ball.pos, but an >object independant of it, which will not be modified upon the modification >of ball.pos. >I think I have this right. Corrections welcome. >Art |