2

I'm learning Python and got confused about memory model of Python

a variable contains the memory address of the object to which it refers

This reads like Python variables are actually pointers, since they only directly contains memory address of the actual object instances.

Then what does Python do when I call a variable name? Does Python always automatically searches the contained memory address and use the object stored there?

For example, see the below code and annotations, do I understand the process correctly?

a=500 # create an int object with value 500, stored this object at a memory address, let's call it id1
b=a #trying to assign a to b, value of a is actually id1, memory address to object int(500), 
# but Python automatically return the object rather than the memory address stored at a. 
# Then refer b to this obejct by storing the same memory address at b 
a=501 # create an  new int object with value 500, stored this object at a new memory address id2, refer a to this new int(500) by storing id2 at a
print(b) # value of b is still id1 and refer to the first int(500) object
Yuhan
  • 39
  • 1
  • 1
    Yes, it seems like you are understanding correctly. – LeopardShark Nov 10 '22 at 09:22
  • Some operations in Python can do a bit more complicated process under the hood (e.g. tuple assignment), but yes, it seems you got the basic idea correct. – matszwecja Nov 10 '22 at 09:40
  • Well, this statement somehow implicates that there is a memory model in **Python**. But Python (the language) does not have any. The language Python intentionally abstracts the memory away from you. This means you can make statements like the one above about a particular Python **interpreter** but not about the language in general. – Klaus D. Nov 10 '22 at 10:41

1 Answers1

0

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=...

chrslg
  • 9,023
  • 5
  • 17
  • 31