Curious case of Lists subset and copy of list subset in Python - & why you should understand this ?
Updated: Sep 2, 2020
Assumption before you start is - that you understand below concepts, if not - its worth a quick detour to below links:
Proceed if you know - what happens as a single variable is assigned references to objects? Else read above three articles real quick and come back.
If you know what happens as a single variable is assigned reference to an object then - let’s introduce another variable into our interaction and watch what happens to its names and objects:
>>> x = 10 >>> y = x
If above two statements are executed in python - something like this happens.
The second command causes Python to create the variable y, the variable x is being used and not assigned here, so it is replaced with the object it references (10), and y is made to reference that object. The net effect is that the variables x and y wind up referencing the same object (that is, pointing to the same chunk of memory).
This scenario in Python—with multiple names referencing the same object—is usually called a shared reference or a shared object. Note that the names x and y are not linked to each other directly when this happens, in fact - there is no way to ever link a variable to another variable in Python! Rather, both variables point to the same object via their references.
Next, suppose we extend the example with one more statement:
>>> x = 10 >>> y = x >>> x = 'bharath'
As with all Python assignments, this statement simply makes a new object to represent the string value 'bharath' and sets a to reference this new object. It does not, however, change the value of y, y still references the original object, the integer 10. The resulting reference structure, looks something like this.
The same sort of thing would happen if we changed b to 'bharath' instead—the assignment would change only y, not x. This behavior also occurs if there are no type differences at all. For example, consider these three statements:
>>> x = 10 >>> y = x >>> x = x + 2
In this sequence, the same events transpire. Python makes the variable x reference the object 10 and makes y reference the same object as x, the last assignment then sets a to a completely different object (in this case, the integer 12, which is the result of the + expression). It does not change y as a side effect. In fact, there is no way to ever overwrite the value of the object 10—as integers are immutable and thus can never be changed in place.
One way to think of this is that, in Python variables are always pointers to objects, not labels of changeable memory areas: setting a variable to a new value does not alter the original object, but rather causes the variable to reference an entirely different object. The net effect is that assignment to a variable itself can impact only the single variable being assigned.
Lets see what happens when mutable objects and in-place changes enter the equation -
there are objects and operations that perform in-place object changes—Python’s mutable types, including lists, dictionaries, and sets. For instance, an assignment to an offset in a list actually changes the list object itself in
place, rather than generating a brand-new list object.
For objects that support such in-place changes, you need to be more aware of shared references, since a change from one name may impact others. Otherwise, your objects may seem to change for no apparent reason. Lets understand it via an example
>>> x = [ 1, 2 , 3 ] # x references an object, [1,2,3] >>> y = x # y references the same object. >>> x [ 1 ] = 24 # the object [1,2,3] is now changed >>> x [ 1 , 24 , 3 ] # x is different >>> y [ 1 , 24 , 3 ] # but so is y
Really, we haven’t changed x itself here; we’ve changed a component of the object that x references. This sort of change overwrites part of the list object’s value in place. Because the list object is shared by (referenced from) other variables, though, an inplace change like this doesn’t affect only x—that is, you must be aware that when you make such changes, they can impact other parts of your program. This behavior only occurs for mutable objects that support in-place changes, and is usually what you want, but you should be aware of how it works, so that it’s expected. It’s also just the default: if you don’t want such behavior, you can request that Python
copy objects instead of making references. There are a variety of ways to copy mutable objects in python - which is a topic of another day.
Of course, you don’t really need to draw diagrams with circles and arrows to use Python. When you’re starting out, though, it sometimes helps you understand unusual cases if you can trace their reference structures as we’ve done here. Because everything seems to work by assignment and references in Python, a basic understanding of this model is useful in many different contexts.
This along with articles I mentioned at the beginning, should give you a good intuitive understanding of what Python is and how it works.
Hope you liked this series - and if it helped you conceptually understand some of things in python which usually are not given due attention in text books - please do share using social icons below.