Home > front end >  How do python's "in memory" variables work
How do python's "in memory" variables work

Time:04-19

I'm trying to understand how "in memory" works within python. From my understanding it's a variable that is not stored anywhere but just kind of floats in the memory. I'm not exactly sure how to word this correctly.

To clarify I'm using PyKEP module and I'm loading in a SPICE kernel pykep.util.load_spice_kernel('kernel_name.bsp'). Link to the documentation

When I do this I have no new variable in the the global scope. However, it allows me to then access more data (velocity, position, ect) of the asteroid that I would call after as such.

asteroid = pk.planet.spice(spiceID, 'SUN', 'ECLIPJ2000', 'NONE', pk.MU_SUN, mu_self, self_radius, self_radius * 1.05)

I can now use asteroid.eph(epoch) without any errors in the global scope. However, this is not the case if I define it in other places or try to move it.

For example:

example 1: functions

Note pk is the PyKEP module below.

def loadKernel(name = 'de440s_Ryugu.bsp', spiceID = '162173', mu_self = 30.03336, self_radius = 432.5):
    pk.util.load_spice_kernel(name)
    asteroid = pk.planet.spice(spiceID, 'SUN', 'ECLIPJ2000', 'NONE', pk.MU_SUN, mu_self, self_radius, self_radius * 1.05)
    return asteroid

Inside the function's local scope I could use asteroid.eph(epoch) but outside I need to re-execute that first line. Which makes sense. But, why can't I return it to the global scope.

example 2: inside objects/classes

class Trajectory:
    def __init__(
            self,
            seq=[pk.planet.gtoc7(3413), pk.planet.gtoc7(
                234), pk.planet.gtoc7(11432)])
        # We define data members:
        self.__seq = seq

    def velAndPos(self):
        r, v = self.__seq[i   1].eph(end)
        return r, v

Here I would encounter an error saying that the kernel file is not loaded even if I add pykep.util.load_spice_kernel('kernel_name.bsp') as the first line in the velAndPos method. Why would this be the case? Is it because the __seq is privet?

Further, what is the advantage of using "in memory" variables?

Thank you in advance.

CodePudding user response:

You can create a variable as a "global variable" in the global scope, prior to utilizing it inside of a function definition, and then declare it as "global" inside of the function. Here is an example that may help you:

globvar = 0

def set_globvar_to_one():
    global globvar    # Needed to modify global copy of globvar
    globvar = 1

def print_globvar():
    print(globvar)     # No need for global declaration to read value of globvar

set_globvar_to_one()
print_globvar()       # Prints 1

And here is a link to a thread that covers this topic: Using global variables in a function

CodePudding user response:

Doing my best to answer your question, but if someone else knows better please correct me in the comments.

How do in memory variable's work? Linked here you'll see that python and other high-level languages use a symbol table to map a variable name to the address it represents. And from the PyKep docs you'll find that your call to that utility loads the kernel into memory. At this point, the page table of the process that is executing your python process is aware of where the kernel has been loaded.

How it applies to your code (best guess) It's hard to say exactly without seeing your project structure, but I'll give it a shot. My guess is that you are not properly sequencing your calls to methods/attributes requiring a loaded kernel. For example, if you load the kernel only at the time of a function call, that kernel won't exist in the process until that function is called.

CodePudding user response:

I had a quick look at pykep and I suspect some of the confusion is because it's implemented in C and bound to Python.

The kernels, it seems, are binary data files that the load function brings into memory, and then the other pykep functions can access them (again, under the hood it's all C ).

So it's not such a surprise that you aren't seeing the data appear as Python variables.

Now, as for your code - managing data with classes is a good practice. You can actually run arbitrary code in the class definition scope, so I think the following has a decent chance of working:

class Trajectory:

    pk.util.load_spice_kernel(name)

    def __init__(self, seq=None, name=None):

        if seq is None:
            # don't use something mutable as your default value,
            # else modifying it also modify the default behaviour
            seq = [
                pk.planet.gtoc7(3413),
                pk.planet.gtoc7(234),
                pk.planet.gtoc7(11432)
            ]
        # We define data members:
        self.__seq = seq

    def velAndPos(self):
        r, v = self.__seq[i   1].eph(end)
        return r, v

If that doesn't work, you might try having the load call in both methods, but that seems inefficient.

  • Related