passing objects to functions

Bengt Richter bokr at oz.net
Sun Nov 24 17:06:08 EST 2002


On Sun, 24 Nov 2002 14:15:25 -0600, Joe Heafner <heafnerj at spam.vnet.net> wrote:

>
>I have the following Python code written using VPython:
>
>from visual import *
>
>def derivative(t,x,xp,xpp):
>  xmu = 1.407645794e16
>  r = mag(x)
>  r3 = r**3
>  xpp[0] = -xmu*x[0]/r3
>  xpp[1] = -xmu*x[1]/r3
>  xpp[2] = -xmu*x[2]/r3
>
>t = 2451545.0
>x=vector(1.,1.,1.)
>xdot=vector(1.,1.,1.)
>xmu = 1.407645794e16
>#xddot = -xmu*x/(mag(x)**3)
>#print xddot
>xddot=vector(0,0,0)
 ^^^^^^ Here you bind the name xddot to whatever object vector(0,0,0) creates

>
>x=vector(2.,2.,2.)
 ^^ Similarly you bind the name x

>derivative(t,x,xdot,xddot)
>
>print xddot
>
>When executed, I get the expected result for xddot. When I modify the code 
>to read:
>
>from visual import *
BTW, using a wholesale * import is not a good habit, because all the importable names
in the module come in and will replace anything you already had by a matching name.
There are cases where it's ok, but beware. If you just import visual, you get the
one name "visual" and then you can get to anything else via visual.whatever,
and for convenience and speed you can bind selected names like foo = visual.foo
(you don't have to give them the same name BTW. import math; pie = math.pi will work,
however inadvisable that one might be).

>
>def derivative(t,x,xp,xpp):
>  xmu = 1.407645794e16
>  r = mag(x)
>  r3 = r**3
>  #xpp[0] = -xmu*x[0]/r3
>  #xpp[1] = -xmu*x[1]/r3
>  #xpp[2] = -xmu*x[2]/r3
>  xpp = -xmu*x/r3
   ^^^^^ Here you are rebinding a function-local name xpp to an object with the value -xmu*x/r3
         xpp was previously bound to the fourth argument's value, which is not affected.
         xpp[index] does not rebind the xpp name. Instead it uses xpp to find the object
         (a reference to which was passed in the function/procedure call) and asks that
         object to modify itself according to its definition of indexed assignment (i.e.,
         via the __setitem__ method in a custom object). Thus the external object associated
         temporarily with xpp inside the function can get modified. But associating a new
         value with the temporary local xpp name will have no effect on the outside.
         I.e., assignment to xpp does not act like a C++ reference parameter. It does not
         write through and modify some memory location. In Python there aren't any
         memory locations in that sense. You have names, but they don't designate places
         in memory. Names exist in various name spaces where they can be looked up to see
         what they are bound to. Assignment to a bare name is giving the name a new binding.
         The object it was previously bound to is unaffected, except that if no other binding
         existed it may be garbage collected.
>
>t = 2451545.0
>x=vector(1.,1.,1.)
>xdot=vector(1.,1.,1.)
>xmu = 1.407645794e16
>#xddot = -xmu*x/(mag(x)**3)
>#print xddot
>#xddot=vector(0,0,0)
 ^-Here you comment out the xddot binding
>
>x=vector(2.,2.,2.)
>derivative(t,x,xdot,xddot)
                     ^^^^^- and here it doesn't exist when you try to pass it
>
>print xddot
>
>I get the error message:
>
>[localhost:~] joe% python testrk4.py
>Visual-2002-07-22
>Traceback (most recent call last):
>File "testrk4.py", line 22, in ?
>derivative(t,x,xdot,xddot)
>NameError: name 'xddot' is not defined
because you commented it out ;-)
Specifying a name in a call does not create a binding for the name, so that's
why you got the message. (That doesn't work in C either BTW. Names used in
calling parameter expressions have to *exist*, barring something perverse
that I can't think of now).

>[localhost:~] joe%
>
>Why does this not work when simply writing
>
>xddot = -xmu*x/(mag(x)**3)
>
>outside my function works perfectly? I'm lost here, and Lutz and Ascher's 
because an assignment inside a function does not write the name on the same
blackboard as a name used outside, unless you tell Python that it should.

Also, the assignment on the inside used xpp, not xddot.
You could declare xddot global inside the function and then assign to xddot,
but that is an ugly way to return values from a function. The best way is
to pass the function a reference to a mutable object and talk to that via
its methods to change its state and store values, or to return values
with a return statement in the function. Note that you can return a (reference to a)
composite object like a tuple or a list, or a custom object.

>book has not helped me, most probably because I don't know where to look 
>for the problem I'm having. I'm trying to port some QuickBASIC numerical 
>analysis code and I need  the capability to pass a vector (a VPython 
>vector, not an ordinary array) into a function, potentially modify that
>vector's components, and then have the same vector accessible outside the 
>function. I can make it work with arrays but not with vectors. I'd 
>appreciate any help.
>
Multiple values separated by commas in a return statement get returned in a tuple, and
assigning the returned value to a sequence of names separated by commas
unpacks the tuple and binds corresponding names and tuple values, e.g.,

def derivative(whatever, blah, blah2):
  # whatever
  ...
  return "some value you've computed", "a second value"

xddot, the_second_value = derivative(actual, parameter, references_and_expressions)

I highly recommend spending some time  with the tutorial and other newbie stuff you'll
find links to at www.python.org

Regards,
Bengt Richter



More information about the Python-list mailing list