In some simple applications that I have had to write in C/C++ I have seen the ease with which certain tasks are solved using pointers . Now, more interested in another language: Python, I have noticed the absence of this concept. What is this absence due to? Being Python a very powerful and used language, then, what concept replaces it? Is it implicit in the data types, in the assignments, in the instantiation of a class?
An extremely simple example would be that in C we can code things like this:
#include <stdio.h>
int main(void) {
// your code goes here
int a = 5;
int *b = &a;
printf("a = %d; b = %d\n", a, *b); // (1)
a = 6;
printf("a = %d; b = %d\n", a, *b); // (2)
return 0;
}
(1): a = 5; b = 5
(2): a = 6; b = 6
b
points to the memory address of a
, any modifications to a
can be observed by dereference b
. Any assignment by indirection will *b = <valor>;
modify a
.
But, in Python:
a = 5
b = a
print "a = {0:d}; b = {1:d}".format(a,b) # (1)
b is a # resultado: True
a = 6
print "a = {0:d}; b = {1:d}".format(a,b) # (2)
b is a # resultado: False
(1): a = 5; b = 5
(2): a = 6; b = 5
At the beginning a
and b
refer to the same object. Then when a
it is modified a new object is created; so, both refer to different objects and of different values.
There isn't a way to do what C does in Python with this data type, but it is possible to do something similar with mutable data types; however, it is only possible when we make internal modifications of the mutable data, for example: changing the value of an element of a list.
a = [1, 2]
b = a
print b is a # resultado: True
b.append(3)
print b is a # resultado: True
a = [4, 5]
print b is a # resultado: False
Its absence is due to the fact that the explicit use of pointers is a characteristic of lower-level languages such as C. High-level languages such as Python avoid it in order to make its use easier and more agile, as well as not having to know details of the data model.
Just because the Python programmer doesn't have to deal with pointers doesn't mean that the interpreter doesn't make use of them. In fact he uses them profusely implicitly.
In Python everything is an object created in dynamic (automatically maintained) memory. When you call a function, the arguments are passed through their pointers. This is what is known as the object calling convention. Similarly, if you assign
a = b
,a
what it saves is the pointer of theb
. So all variables are pointers to objects, which are handled implicitly.What we do have to differentiate is between immutable and mutable objects.
x = 2015
will create an entire object andx
point to it but the content of that object cannot be modified. If you then assignx = 2016
, what it will do internally is create a new object with the new content.v = [1]
and then callv.append(2)
,v
it will still point to the same object, but its content will have changed.In short, when running this code:
The result will be:
In C, pointers typically satisfy three needs: refer to dynamically reserved structures, pass parameters to a function by reference , or iterate through a collection.
In the case of Python, and self-memory object languages in general, variables serve the function of referencing dynamically created structures: one can create instances of the objects at any time.
In general, objects are stored in the dynamic memory of processes, and variables are references to them: almost almost references are abstractions of pointers, with some more properties.
For this reason, parameter passing is always done by reference, so no pointers are needed for this.
Finally, in object languages there are iterator objects, which expose a higher-level interface for traversing collections of data.
Abstracting from the details of the memory of the process is something sought after in languages, and for all this it is that pointers are not necessary: by design .
@GuillermoRuiz's answer seems excellent to me, but I would like to delve into some details about mutability and immutability, which are often confusing at first, but which are very clear if you keep in mind that they are all pointers .
Change items in a list
The fact that a list is " mutable " implies not only that we can add elements to it, but also that we can change the stored values.
Actually, being purists, the list only contains "pointers" to the data in question. That is, a list like this:
It actually contains three pointers, each pointing to an integer, of respective values
1
,2
and3
. If we now change the first element:When printing the list we will see:
This does not mean that the first element of the list has been replaced by a 100 (that would be true in a C array), but that a new object of type integer has been created and that the pointer that was in the first element of the list list that pointed to a
1
, now points to100
. The1
previous one becomes "dereferenced" and will be removed from memory later by the garbage collector.Copies of lists
On the other hand, the fact that the variables are actually pointers (or if you prefer, references) implies that the following assignment:
does not copy the elements of
a
, but simply assigns tob
a copy of the pointer.a
. That is,a
andb
actually point to the same list. So if we do:it is the same as if we had done
a[0] = 50
.To check if two variables "point" to the same data, Python offers the comparator
is
:If we don't want them to point to the same one, but to be a copy (in different places in memory), we can achieve it like this:
or this way:
In either of these two cases:
The operator
==
compares the elements ofa
with those ofb
, whileis
comparing the identity ofa
with that ofb
, which in practice consists of comparing which memory address each refers to.Lists as parameters
The above also explains why a function can modify elements of a list that it receives as a parameter:
In a tuple, being immutable, this cannot be done.
Immutability, but not so much
But be careful , the fact that a tuple is immutable only means that the value of cannot be changed
tupla[i]
for another value, but if ittupla[i]
were a list, the values of that list could be changed:It's a bit of a hack, but if you really need 1 variable and a "pointer" you can do:
I think it's unnecessary, anyway if someone knows a better way let me know! :D