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 |