To answer to your interrogation: "why then a=100;b=a;a=101
doesn't change values of b", I remind you that even in C, it would not be the case. The fact that a
and b
are pointers, and made equal, doesn't mean that changes to a
impacts b
. They are not alias. *a
and *b
may be, but not a
and b
.
In C, something quite similar would be with constant strings.
char *a="hello";
char *b=a;
a="foo";
printf("%s\n", b);
// prints hello
Yes, a and b are pointers. But yet it is a
you change when you type a="foo";
, not its content. So, yes, a
and b
were equals... until, you said a="foo";
when they stopped being equal, since you changed a. They are just pointers. Which is a value like another after all. It is not stranger to see that a
and b
are no longer equal in this code that it would be in
int a=12;
int b=a;
a=15;
They were equals, and then they are not. Pointers are just values. Addresses.
It is what is at this address that may be shared. And not strangely so.
int T[10]={1,2,3,4,5,6,7,8,9,10};
int *a=&(T[2]);
int *b=a;
printf("%d %d\n", *a, *b);
// prints 3 3
*a=5;
printf("%d %d\n", *a, *b);
// prints 5 5
You may wonder why I needed a whole array. Well, it is just to show you that this "alias" behavior of pointer is nothing more that this seemingly less magic example
int T[10]={1,2,3,4,5,6,7,8,9,10};
int ia=2;
int ib=a;
printf("%d %d\n", T[ia], T[ia]);
// prints 3 3
T[ia]=5;
printf("%d %d\n", T[ia], T[ib]);
// prints 5 5
Pointers are just that. Indices. Except that they are a form of indices in a global huge array of all memory. But nothing magic in the "alias" of *a
and *b
, and in the fact that this "alias" behavior impact *a
and *b
, but not a
and b
(changing a doesn't change b). It should not be more surprising than the fact that, as long as ia
and ib
doesn't change in my last example and remains equals, there is an aliasing between T[ia]
and T[ib]
(obviously, you would say, they are both T[2]
. Well, yes, "obviously", but no more than with pointers), and that there is no "aliasing" between ia
and ib
; ia=5
, wouldn't impact value of T[ib]
. Again, yes, "obviously", but no more obviously than changing a
doesn't change value of *b
.
Now, back in python: yes, variables contain pointers to object, not object themselves. But still, if you change a, you change the pointer.
a=[1,2,3,4]
b=a
print(a[1],b[1]) # prints 2 2
a[1]=5
print(a[1],b[1]) # prints 5 5
There is an "aliasing" between a[?]
and b[?]
because we said b=a
. But
a=[1,2,3,4]
b=a
a=[0,2,3,4]
print(a[0], b[0]) # prints 0 1
There is no "aliasing" between a and b
But, you may ask, then, how can I change the content of a, without changing a
itself (the pointer).
Well, we just did. There is no *
operator in python (well, there is one, that is literally named *
, but that has really nothing to do with this matter). So, if a
and b
are an object whose content can be modified (like lists, as we just did. Or dictionaries. Or instances of classes. Or some specific objects provided by libraries, such as ndarray or pandas dataframes), as long as a=b
, and you don't change value of a
and b
, when you change the content of one (a[1]=12
or a['bla']='foo'
or a.foo=15
, or...) it impacts the content of the other (obviously: they are the same object)
But not all objects are modifiable.
a=12
b=a
# The is no `a.value=15` that would change a values, without changing the object
Those are immutable objects. Reason why I used the analogy of constant strings in C
char *a="hello";
char *b=a;
a="foo"; // Doesn't change b
Because, similarly, they may be objects. But you can't change their content. You can't strcpy(a,"bar")
, because they are constant strings. So, if you want to change a
you have to change the pointer, not the content.
It is the same for immutable objects
a=12
b=a
# Only way to change a value is to change a
a=13
So, think of literal 12
as not a value, but a pointer to an instance of int
(it is a thought model, not reality). Sure a
is a pointer, somehow. But the only way to say that a
no longer "points" to an int whose value is 12
, but now points to an int whose value is 13
, is not to change what is pointed by a
, because it is immutable, but to change a
, and makes it "point" to another object, whose value is 13
Likewise (and more surprisingly for someone used to almost any other languages)
a="hello"
b=a
a[0]='H' # wouldn't work
Wouldn't work. Strings are immutable. The only way to have that capital H is
a="hello"
b=a
a="Hello"
But then, of course, it doesn't impact b
.
Same goes for tuples: a=(1,2); b=a
you can't a[0]=3
, you have to a=(3,2)
which doesn't impact b
So, you may consider all variables to be pointers. But there is no &
and *
operator. No explicit referencing, dereferencing operators. Just, if a=b
, and are mutable, then content of a is the same as content of b, even when you change a
's content (by saying a[...]=...
for example). And if a=b
but are immutable, then, content of a
is the same as content of b
, but that doesn't matter, since you can't change the content of a
, only a
itself, by saying a=...