Python: Mutable, Immutable... everything is an object!
The Object-Oriented Programming (OOP) is a fairly extensive paradigm but from which we will take a small definition as the combination of data and functionality wrapped inside something called an object. Everything in Python is considered an object. An object is something a variable (or name) can refer to. As you might find "Objects combine data values with behavior. Objects represent information, but also behave like the things that they represent. The logic of how an object interacts with other objects is bundled along with the information that encodes the object's value."
In Python, Objects have attributes named values and also have methods, which are function-valued attributes; and as we mentioned before, everything in here is an object, that is why no matter the data type of the values all are considered as objects behaving in a manner that befits the values they represent, and containing for themselves their own methods and attributes that facilitate their text execution. For example, strings type have an array of methods that allows it to perform its executability, as 'upper', 'swapcase', or 'endswith'.
Likewise, Python also has what in C we could call a memory address, in this case, for each unique created object.
Identity: id() function
id() is a built-in function that accepts a single parameter and is used to return the identity of an object, this identity (like a location in the memory) has to be unique and constant for this object during the lifetime. Two objects with non-overlapping lifetimes may have the same id() value.
It's syntax is:
id(object)
and an example could be:
a = "Hello" b = [1, 2, 3] print("a name as: {}".format(a)) print("id a: {}".format(id(a))) print("b name as: {}".format(b))
print("id b: {}".format(id(b)))
with the respective output:
a name as: Hello id a: 140330098528584 b name as: [1, 2, 3]
id b: 140330097739784
As we can see, id() allows us to check the respective address of the created objects, 'a' as a string and 'b' as a list, each one with a different identity.
type() function
type() method returns the class type of the argument(object) passed as parameter. type() function is mostly used for debugging purposes. Its syntax: type(object).
a = "Hello" b = [1, 2, 3] print(type(a))
print(type(b))
output (respectively):
<class 'str'>
<class 'list'>
But how does this come to the subject? and, why does it matter, and how differently does Python treat mutable and immutable objects? Well, a method like type () works for us to the extent that we need to know the type of object that we are creating and manipulating because depending on this we will have to consider its mutability or immutability. That is why also the mentioned built-in id(), to know that, while we manipulate different types of objects (for example, if we want to add something to a list or modify a string) depending on what we want to do, this will affect the created objects, their location in memory, and the expected result either on the same object or on a new parallel object; in any way, at some point, it will be accurate to know the location of the determinate object, if it keeps being the same one , if we got a new one during the process, or an error message warning us of the improper use of an object type.
Mutable and Immutable objects
In Python, the value of some objects can change. Objects whose value can change are said to be mutable; objects whose value is unchangeable once they are created are called immutable. Numeric objects are immutable; once created their value never changes and these are distinguished by integers, floating-point numbers, and complex numbers. There are also sequences that vary between immutable and mutable as you can see in the image.
how arguments are passed to functions and what does that imply for mutable and immutable objects?
In Python, arguments are passed to function by reference. It means if you change what a parameter refers to within a function, the change also reflects back in the calling function. The advantage of call-by-reference consists of greater time- and space-efficiency because arguments do not need to be copied. On the other hand, this harbors the disadvantage that variables can be "accidentally" changed in a function call. This call by reference can change between immutable and mutable objects implying the following:
Passing immutable arguments to a function would be passed by value, the object reference is passed to the function parameters and they can't be changed within the function, because they can't change at all.
Passing mutable arguments to a function is the same as passed as reference, but they can be changed in place in the function. For example, if we have a list with which can be changed in place (in the function) because is a mutable object so it will change even in the caller's scope.