34 votes

Understanding the absence of pointers in Python

In some simple applications that I have had to write in C/C++ I've seen the ease with which to solve certain tasks using pointers. Now, more interested in another language: Python, I've noticed the absence of this concept. Why this absence? Being Python a very powerful language and is used, then, what concept replaces him?, what is implicit in the data types, the mappings in the instantiation of a class?

An example extremely simple 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 achanges in a may be observed by dereferencing b. Any allocation for indirection *b = <valor>; modified 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 is modified a new object is created; then, both make reference to different objects and different values.

There is a way to do that in C in Python, with this kind of data, but it is possible to do something similar with types of mutable data; however, it can only be when we make internal modifications to the data mutable, for example: change the value of an element in 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

38voto

Guillermo Ruiz Points 734

His absence is due to the explicit use of pointers is a feature of languages of more low level, like C. high-level Languages such as Python tends to avoid with the purpose of making more easy and agile utilization, as well as not having to know the details of the data model.

The programmer of Python does not have to deal with pointers is not to say that the interpreter does not make use of them. In fact the used profusely implicitly.

In Python everything is an object created in dynamic memory (maintained automatically). When you call a function the arguments are passed by their pointers. This is what is known as the convention of call-by-object. In the same way if you a = b, a what saves is the object pointer b. So all variables are pointers to objects, which are handled implicitly.

So yes there is a difference is between immutable objects and mutable.

  • Immutable numbers, strings or tuples. The assign x = 2015 create an integer object and x will point to him, but the contents of that object may not be modified. If then you x = 2016 which will make it internally will be to create a new object with the new content.
  • Mutable are other objects as dictionaries or lists. In this case, those objects can be modified. If you have v = [1] and then call v.append(2), v will continue pointing to the same object, but its content will have changed.

In summary, when you run this code:

x = 2015
y = x
x = 2016

print x
print y

v = [1]
w = v
v.append(2)

print v
print w

The result will be:

2016
2015
[1, 2]
[1, 2]

7voto

mgarciaisaia Points 503

In C, pointers tend to satisfy three needs: to cross-reference structures reserved dynamically pass parameters to a function by reference, or iterate through a collection.

In the case of Python, and the language of objects with automatic memory in general, the variables that meet the role of reference structures created dynamically: you can create instances of the objects at any time.

In general, the objects reserved in the memory dynamics of the processes, and the variables are references to them: almost, almost that the references are abstractions of pointers, with some properties more.

For this reason, the passage of parameters is always done by reference, so that you don't need pointers for this.

Finally, in the languages of objects there are objects iterators, which expose an interface of the highest level to iterate through collections of data.

Abstract from the details of the memory of the process is something sought after in languages, and for all this is that there are necessary pointers: by design.

4voto

abulafia Points 18959

The answer of @GuillermoRuiz I think it's great, but I would like to delve into some details about the mutability and immutability, which are often confusing at first, but that is very clear if we keep in mind that all are pointers.

Change elements of a list

The fact that a list is "mutable" implies not only that we can add items to it, but that we can change the stored values.

In reality, being purists, the list only contains are "pointers" to the data in question. That is to say, a list like this:

a = [1, 2, 3]

Actually contains three pointers, each one pointing to an integer, of the respective values 1, 2 and 3. If now we change the first element:

a[0] = 100

When you print the list, see:

>>> a
[100, 2, 3]

This does not mean that the first element of the list has been replaced by a 100 (that would be true in an array (C), but it has created a new object of type integer and the pointer that was on the first element of the list that pointed to a 1, is now pointing at 100. The 1 prior is "without references" and be removed from memory by the garbage collector.

Copies of lists

On the other hand, the fact that the variables are really pointers (or if you prefer, references) implies that the following assignment:

b = a

does not copy the elements of a, but that simply assigns to b a copy of the pointer. a. That is to say, a and b point in reality to the same list. So if we do:

b[0] = 50

it is the same if we had done a[0] = 50.

To check if two variables "point" to the same data, Python provides the comparator is:

>>> a is b
True

If we don't want that point to the same, but they are a copy (in different locations of the memory), we can achieve it as well:

b = list(a)

or like this:

b = a[:]

In either of these two cases:

>>> a is b
False
>>> a == b
True

The operator == compares the elements of a with b, while is compares the identity of a with b, which in practice consists in compare to what 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:

def pon_cero(lista):
   lista[0] = 0

a = [1,2,3]
pon_cero(a)
print(a)
# [0, 2, 3]

In a tuple, to be immutable, it can't be done.

Immutability, but not both

But care, that a tuple is immutable just means that you can not change the value of tupla[i] for another value, but if tupla[i] to be a list, the values of that list itself could be changed:

tupla = ( [0,0], [1,1] )
# tupla[0] = [2,2] # No está permitido. Error
tupla[0][0] = 2
tupla[0][1] = 2    # No hay problema aqui en cambio
print(tupla)
([2,2], [1,1])

0voto

Pablo Points 28

It's a bit of a fudge, but if you really need 1 variable and a "pointer" you can do:

 class mutable_obj:
    def __init__(self, x):
        self.x = x

a = mutable_obj(10)
b = a
a.x == b.x # True
a.x = 30
a.x == b.x # True
b.x = 86
a.x == b.x # True
 

I think it's unnecessary, even if someone knows a better way to say it! : D

HolaDevs.com

HolaDevs is an online community of programmers and software lovers.
You can check other people responses or create a new question if you don't find a solution

Powered by:

X