Python is coded mostly in C (for the cpython version), not C++. numpy
also has a lot of underlying C code. But Python programmers usually think in terms of Python objects and refereces ("pointers"), without trying to define the underlying C or machine level equivalents. Everthing is an object, and stored "somewhere" in memory. As long as something has a "reference" to that object if percists. When the reference count drops to 0, it is a candidate for garbage collection. So the key ideas are "what creates an object", and "what contains a reference to it"
It's also important to desinguish between objects that are "mutuable", whose values or properties can change, and "immutable" objects.
Variables just contain references. The identity of a variable is determined by what is references. A variable is created by assignment.
Your code:
list_value = []
f(list_value)
a = list_value[0]
b = list_value[1]
list_value
is a variable that points to a "empty" list. A list is a object class that can "store" references to other objects. That store is probably a C array of pointers. It also has "growth" room so it efficient to "append" objects to the list. But those are implementation details. We talk about a list containing objects, though in detail the list's array just has pointers, with the actual objects store somewhere else in memory (that confuses people who try to get the "memory footprint" of a list, with a naive use of sys.getsizeof
.)
The next line calls your function, passing it a reference to the list that you just created.
def f(list_value: list):
a = numpy.zeros(5)
b = numpy.zeros(4)
list_value.append(a)
list_value.append(b)
The function 'locally' creates 2 numpy arrays (also objects). They are referenced locally by variables 'a' and 'b', but with append, the arrays are "placed" in the list.
Usually a function returns something, such as return list_value
. But here the return is None
, and list_value
remains accessible since it was just passed by reference, and is mutable.
On return, the function local variables disappear, but the arrays still "exist" as elements of the list.
So they can be accessed in various ways.
a = list_value[0]
c, d = list_value
new_list = list_value[:]
back_list = list_value[::-1]
print(list_value)
list_value[1][::2] = [10.0, 20.0]
list_value
has no indication that they were originally assigned to local variables 'a' and 'b'. The arrays in the list are, in that sense, "nameless". But we can do anything with these arrays that is consistent with their shape
and dtype
.