What does Python treat as reference types?
Asked Answered
N

3

31

I assumed sequence types in Python were value types. It turns out they're reference types (Meaning that the value of a variable won't be copied when assigned to a new variable, but referenced). So now I'm wondering, what are the value types in Python? That is, what types in Python can I assign to new variables without worrying that the variable was referenced?

Nivernais answered 28/5, 2011 at 0:36 Comment(0)
B
48

All values in Python are references. What you need to worry about is if a type is mutable. The basic numeric and string types, as well as tuple and frozenset are immutable; names that are bound to an object of one of those types can only be rebound, not mutated.

>>> t = 1, 2, 3
>>> t[1] = 42
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
Berkow answered 28/5, 2011 at 0:39 Comment(4)
For completeness it should be noted that, while a tuple is immutable, any mutable objects contained in it may be mutated: t = 1, [2], 3 ; t[1].append(42)Radiomicrometer
For completeness, could you add how I would go about duplicating/cloning a value?Nivernais
That depends on the type. For lists, you can either pass it to list() or slice the whole thing (L[:]). For sets, pass it to set(). For other types, see the relevant documentation. Note that there are types that effectively cannot be cloned at all, simply because they represent an external resource (e.g. socket).Berkow
I feel this is good and concise. Thank you for your answer.Acropolis
G
22

Coming from iOS development using strongly typed Swift language, Python reference was a bit confusing so I decided to do a little comparison. Here is the summary: -

  • When assigning a variable to python say a = 10 you are simply pointing/referencing the the object in this case 10 which is stored in a memory. So if that object changes then the value of a variable a also changes but changing a does not change the object 10, This behave similar to Swift Primitive value types such as Int.

To make this clear here is an example: -


 # "a" points to an object in this case 10
a = 10

# "b" points to the same object which a points but does not point to a variable a.
b = a 

# Now if we change "a" to point to another object in memory say 20. 
a = 20

# "b" still points to the old object 10 in other words
# "b == 10" but "a == 20", This is because "b" was never pointing to the variable "a" 
# even though we assigned it as "b = a" instead it was pointing to the object 10
#  which is # the same as writing b = 10. 

Let's check with a more complex data structure List

list1 = [10,20,30,40]
list2 = list1 #[10,20,30,40]

list1 = [3,4] 

# list1 ==> [3,4]
# list2 ==> [10,20,30,40]


Again that behave the same to Swift and other similar languages. Here comes the huge difference Let's try changing value at a certain index ( This gets more tricky)

list1 = [10,20,30,40]
list2 = list1 #[10,20,30,40]

# change value of list 1 at a certain index say index 0
list1[0] = 500

# If you check again the values of list1 and list2 you will be surprised. 
#list1 ==> [500,20,30,40]
#list2 ==> [500,20,30,40]

They both change because they were all pointing to the same object so changing the object changes all list1 and list2. This is very confusing from other Languages such as Swift. In Swift List/Array are value types meaning they are not referenced instead they are copied around, However in python it is another story, changing a value at a certain index results in changing that value for all properties which references that object just like in the example above. This is very important to keep in mind for folks coming from Swift or other similar languages.

So how do we copy in python?

  • If you want to copy the list in python then you have to explicitly do so as shown on the example below: -
list1 = [10,20,30,40]
list2 = list(list1)

# list1 ==> [10,20,30,40]
# list2 ==> [10,20,30,40]

Doing so will avoid undesired effects when list1 changes list2 will remain the same.

As an example

list1[0] = 500
#list1 ==> [500,20,30,40] # Changed
#list2 ==> [10,20,30,40] # Unchanged
Glyceryl answered 10/8, 2020 at 3:29 Comment(2)
Glad that I could help :)Glyceryl
This was so helpful. I'm coming from Swift & was surprised when Python's assignment operator wasn't behaving as expected with lists. FWIW - and I'm sure you know this - it seems lists have a .copy() method which will also produce a copy of the list that isn't attached to the original.Termless
H
8

The answer above is correct, but I object to the semantics of "reference".

C-like languages treat variables as fixed buckets, in which values are placed. When you call a function, a new set of buckets are created, and the values are copied into them. Sometimes, a bucket is pass-by-reference, and actually becomes an alias for the caller's bucket.

Python, on the other hand, treats variables as mere labels (names) for values (objects). When you call a function, a new set of labels are created and slapped onto those same objects.

It doesn't make sense to mention "references" in the context of Python, because in every other language, "reference" implies an alternative to "value". Python has no such duality; it just passes around and assigns objects. Nothing is referred to.

Nitpicky, perhaps, but the terminology causes no end of confusion for C++ programmers, who e.g. hear Python passes by references and don't understand how to reassign the caller's names.

Hofstetter answered 28/5, 2011 at 4:46 Comment(5)
Python passes by value, but the values are references.Berkow
That's silly. The passed values aren't references to objects; they ARE objects.Hofstetter
Perhaps this article (bit.ly/4Cjmn0) and the SO question that linked to it (bit.ly/3fRXW) can shed some light on this. I find the terminology used in the article helps makes things a bit less confusing. Also, while I see your point about references, I disagree with it. A label or name is a reference, in the general sense of the word. When I use your name, I am referring to you.Manvel
I totally agree with you and I get into fights about this on SO sometimes ;-) If you know what a C-reference is then you know that Python cannot pass these, since that would make all objects mutable. I call Python's modus "call by aliasing", just to avoid questions like this one. On the other hand thinking that Python passes objects by reference works too: That reference is given by a string (the name of a object on the virtual machine) not by a number (a memory address on real hardware). Both views make sense and knowing them both helps more than either alone :-)Unfrequented
I disagree in that you guys are thinking of Python variables like they are directly referenced by their names. I am not sure whether my idea is acutely accurate or not, but my understanding is that in Python, variable names hold the reference to the reference to the target value, and then the referenced reference value references the target value, which is the object. That's why Python is so slow and energy-consuming. This idea comes from the fact that Python is a script language,a combination of a compiler + a compiled language. So one more referencing is added in the way.Acropolis

© 2022 - 2024 — McMap. All rights reserved.