Home > Blockchain >  What does a variable actually contain?
What does a variable actually contain?

Time:01-13

Would somebody please clear up some technicalities for me.

In my course, it says that a variable doesn't contain a value per se, but a reference in computer memory where the value can be found.

For example:

a = [1, 2, 3]

a contains the reference to the location in computer memory where [1, 2, 3] can be found, sort of like an address.

Does this mean that in my computer, this value of [1, 2, 3] already exists in memory, or am I creating this value [1, 2, 3] on the spot?

CodePudding user response:

a = [1, 2, 3]

causes the following actions by the Python interpreter:

  1. Construct a list containing the elements 1, 2, 3.
  2. Create the variable a
  3. Make the variable from step 2 refer to the list from step 1.

CodePudding user response:

A disassembly of the function might actually be enlightening in this case. Note: this answer is specific to the implementation and version of Python. This was generated with CPython 3.8.9.

Consider the function:

def x():
    a = [1,2,3]

Very simple. Assign the list [1,2,3] to a local variable a.

Now let's look at the byte code that Python generated for this function:

import dis
dis.dis(x)

  2           0 LOAD_CONST               1 (1)
              2 LOAD_CONST               2 (2)
              4 LOAD_CONST               3 (3)
              6 BUILD_LIST               3
              8 STORE_FAST               0 (a)
             10 LOAD_CONST               0 (None)
             12 RETURN_VALUE

I won't get into detail what all these byte codes mean, but you can see the list of instructions the python compiler has turned that simple function into. It loads three constants (0, 1, and 2), onto Python's stack, and uses the BUILD_LIST 3 operation to build a list from three items on the stack, and replaces them with a reference to the new list. This reference is then STOREd in the local variable 0 (which the programmer named a). Further code would use this.

So, the function actually translates your function into, roughly, the commands for "build a new list with contents 0, 1, 2" and "store the reference into a".

So, for a local variable, it is a "slot" (that the programmer has named 'a', and the compiler has named 0) with a reference to a list it just built.

Side note: The constants 0, 1, and 2 that are loaded onto the stack actually exist as references to integer objects in Python, which can have their own functions. For efficiency, CPython keeps a cache of common small numbers so there aren't copies. This is not true of many other programming languages. For example, C and Java can both have variables that contain just an integer without being a reference to an object.

CodePudding user response:

In my course, it says that a variable doesn't contain a value per se, but a reference in computer memory where the value can be found.

That's true, depending on the definition of "memory" and definition of "value".

Memory might refer to virtual memory or RAM (physical memory). You don't have access to physical RAM directly in Python.

The definition of memory might include CPU registers or it might not. Some might argue that a CPU register is not memory. But still, a value may be stored there. Not in Python, though.

"value" may be an "address" again.

sort of like an address.

IMHO, it's good enough to think of it being an address. It doesn't behave like a pointer in C , though. You can't directly write to it and the address may change over time.

this value of [1, 2, 3] already exists in memory

First, it exists in your PY file on disk. The Python interpreter will load that file into memory, so yes, those "values" exist in memory as text characters.

The interpreter may then

  • find that those values already exist in memory and reuse those
  • find a place for these values and store them in a different format (not as text characters but as int objects).

or am I creating this value [1, 2, 3] on the spot?

As mentioned before, it's kinda both. They exist in memory as text before and are then created again as their proper data types or not created because they already exist.

CodePudding user response:

Additionally, to the excellent answers by @Thomas Weller, and @Barmar, you can see how the objects are stored in memory by using id() for each of the objects once they are mapped to a variable.

a = [1,2,3]

hex(id(a))
'0x1778bff00'

Furthermore, as @Max points out in their comment, this list type object is also just storing multiple int objects in this case which have their own memory location. These can be checked by the same logic -

[hex(id(i)) for i in a]
['0x10326e930', '0x10326e950', '0x10326e970']

Now, if you create another list object b which stores the 3 int objects and the previously defined list object a, you can see these refer to the same memory locations -

b = [1,2,3,a]

[hex(id(i)) for i in b]
['0x10326e930', '0x10326e950', '0x10326e970', '0x1778bff00']

And this also shows the behavior of self-referencing objects, such as an object that stores itself. But for this b has to be defined once initially already, since without a memory allocated to b you wont be able to store it into another object (in this case, store it in itself)

b = [1,2,3,b]

hex(id(b)) #'0x1590ad480'

[hex(id(i)) for i in b]
['0x10326e930', '0x10326e950', '0x10326e970', '0x17789f380']

However, if you map the same list of elements of 2 different variables, while the int objects still point to the same memory, these 2 variables have different memory locations, as expected -

d = [1,2,3]
e = [1,2,3]

print('d ->',hex(id(d)))
print('e ->',hex(id(e)))

print('elements of d ->',[hex(id(i)) for i in d])
print('elements of e ->',[hex(id(i)) for i in e])
d -> 0x16a838840
e -> 0x16a37d880
elements of d -> ['0x10326e930', '0x10326e950', '0x10326e970']
elements of e -> ['0x10326e930', '0x10326e950', '0x10326e970']

Redefining a variable with the same elements will keep the same int objects these point to, but the memory location for the variable changes.

d = [1,2,3]
print('old d ->',hex(id(d)))

d = [1,2,3]
print('new d ->',hex(id(d)))
old d -> 0x16a5e7040
new d -> 0x16a839080

CodePudding user response:

What does a variable actually contain?

In short, that's not a question that even makes sense to ask about Python.

In another sense, that depends on the Python implementation. The semantics of variable in Python are simple, but somewhat abstract: a variable associates an object with a name. That's it.

In a = [1,2,3], the name is a and the object is a value of type list. Until the name a goes out of scope, is deleted with del a, or is assigned a new value, a refers to the list [1,2,3].

There is no deeper level, like "a is an address in memory where the list can be found". Python doesn't have a concept of an address space that you can access by location: it just has names for objects that exist... somewhere. Where that somewhere might be isn't important, and Python doesn't provide anyway to find out. The only two things you can do with a name are 1) look up its value and 2) make it refer to something other value.

  • Related