Python language is constructed in a very particular way that makes everything an object. Starting from data types like integers and floats and passing for data structures like list and tuples and even function are Objects. Everything is a Object in python!!! and this makes this programming language work in a particular way that we should be aware to squeeze the maximum out of the language and avoid bugs.
The difference between object and class
As we saw objects are very important in python and can be defined as a piece of memory with values and a set of associated operations. In order to create these objects there should be a class method that allows us to give life to this object because the class contains the variables (values or instances) associated with the object and the methods (associated operations or functions) that the object can perform.
We can see this in the following example. Lest’s create a class for a square:
Now with the class defined, we can create as many square objects as we want,
like the example above, everything in python is created this way. The objects that are the core of the programming language are called built-in objects and are divided into two groups mutable and immutable.
Id and Type
The id() function returns the memory address of an object, this will help us to determine how the address of a object change.
The type() function returns the class type of an object
In python every object has two very important characteristics, It can be mutable or immutable. In other words, objects that are mutable can be overwritten in the same place in memory that was created. The mutable objects are list, dictionaries and sets.
Lets see with an example the behavior of mutable objects:
So now you can see that in mutable objects the address remains the same, this brings new interactions when we are passing this objects to functions so we have to be careful to not modify undesired variables.
The immutable objects can not be modified so they need to be re-assigned in other memory place. The immutable objects are Numbers( int, float, etc), tuples, strings.
Let’s see this more clearly with a little example. In the following code we are going to create a string and try to change one of its values:
This code will result in the following exception:
But this doesn’t mean that we can not assign a immutable type like a integer number, it is just that a new object is created in a different place in memory, lets see the following example:
Why does it matter and how differently does Python treat mutable and immutable objects?
As we saw in the previous paragraphs there are important behaviors that we should take into account when we are working with mutable and immutable objects lets see the origin of this behavior.
First lets see the way the assignments are done in python. first for an assignment we have a target on the left of the equal and the object to be assigned on the right. the target can be a variable or a object and the object can be an arbitrary expression that creates an object. There are a couple of properties we should have in mind
- Assignments creates objects references. Python assignments stores references to objects in names or data structures. They always create references to the objects instead of copying them. This is why sometimes we have to variables pointing to the same object and this particular property affects mutable objects because one change to one will affect the other and this could be and undesired effect that will affect the results of your program. Lets see this example:
this type of behavior is called aliasing or shared reference and represents the phenomena of two different variable names pointing to the same object.
2. Names are created when first assigned. python creates a variable when is assigned the first time in the program so there is no need to previous have a explicit declaration.
3. Names must be assigned before being referenced. This is an important statement to have in mind because this will raise an error and also can return results with ambiguous default values.
4. Some operators perform assignment implicitly. Module imports, functions and class definitions, for loops, and function arguments are all implicit assignments. All this contexts simply bind names to the object references in runtime.
every time we make an assignment to a immutable object a new one is created except in the following cases:
- Some kind of strings
- Integers between -5 and 256 (inclusive)
- Empty immutable containers “tuples”
How arguments are passed to functions and what does that imply for mutable and immutable objects
This part is about the way that objects are sent to functions as objects. As well how names are assigned to names in a function but the have more to do with object references than with variables scopes
How we noted in the early theme arguments to functions are passed by assignment, this means a reference of the object is passed. This phenomena has some special cases that are not so obvious for beginers and are very important when we are dealing with functions. These are the key points that you should be aware of:
- Arguments are passed by automatically assigning objects to local variable names. Function arguments, references to shared objects sent by the caller, are objects too. Because references are implemented as pointers all arguments are passed this way and are never automatically copied.lets see this on an example:
2. Assigning to argument names inside a function does not affect the caller. When we create a new variable inside a function, this variables is created just for the function scope so there is no chance to generate shared references between the function arguments and variables names in the scope of the caller.
3. Changing a mutable object argument in a function may impact the caller. As arguments are assigned to the same id of the caller object and this object is mutable the changes that are done inside the function can be reflected to the caller object. Lets see this behavior with a example:
In fig 1, we can see how the argument x passed to the function is the same object inside the function creating an aliasing behavior
In Fig 2, we make an assignment to the variable b that also points to our caller, an then we make a change on the first element of the list and also in the caller. This can be an undesired behavior that can affect the results of our program. To avoid this we need to copy our argument to an immutable object, copy the object so this way we eliminate the shared reference and the return our desired result
In Fig 3,we can see clearly how the shared reference change our sent object.
4. Immutable arguments are effectively passed by value. These object passed as arguments are passed also as reference but as they are immutable any assignment statement will copy the result in a different space in memory and we can see this as a copy making.