Mutable, Immutable types... with Python everything is object!
Introduction
As soon as I started learning Python at Holberton I got immediately hooked, it's simplicity, but at the same time power makes one of the most used dynamic programming languages nowadays (along with Perl, Tcl, PHP, and a new most wanted Ruby). It is used by scientists writing applications for the world's fastest supercomputers and by children first learning to program.
Python is lot similar to C Programming language, but everything simplified, no semicolons, no braces, just type and you most probably get the interpreter to do what you want (but please don't forget to indent!).
In Python, variables are simply names that refer to objects (you will hear that a lot, to Python, EVERYTHING IS AN OBJECT). Variables do not need to be declared before they are assigned (like in C) and they can even change type in the middle of a program.
Like other dynamic languages, all type-checking is performed at run-time by an interpreter instead of during a separate compilation step.
At its creation Guido Van Rossum said 'One of my goals for Python was to make it so that all objects were "first class."'. This means that functions, classes, methods, modules, and all other named objects can be freely passed around, inspected, and placed in various data structures (e.g., lists or dictionaries) at run-time. The internal implementation of Python made this simple to do. All of Python's objects were based on a common C data structure that was used everywhere in the interpreter. Variables, lists, functions, and everything else just used variations of this one data structure.
Object oriented Programming (or OPP)
Object oriented Programming is a programming paradigm based on the concept of "objects", which can contain data and code: data in the form of fields (often known as attributes or properties), and code, in the form of procedures (often known as methods, that are like functions).
A feature of objects is that an object's own procedures can access and often modify the data fields of itself (objects have a notion of this or self). In OOP, computer programs are designed by making them out of objects that interact with one another. Python is class-based, meaning that objects are instances of classes, which also determine their types.
So how can we know what type of data is a variable? There is where the following functions are very useful.
Id() and type()
Every object in Python has an identity, a type and a value. To illustrate this lets create to objects (now we can call them objects), one integer and a string and assign them to a variable.
Every object in Python has a unique identity, it’s own memory allocation. We can access a certain variable’s memory address with a function called id(). Let's check our variables id's:
We can see both variables have unique ids, but what happens when we create a variable "c" with the value 33 and a variable "d" with the value "String":
We can see both c and a share the same id and b and d too! this is because they are both pointing to the same instance, the same place in memory. This doesn't happens with all type of objects, there are some objects that are mutable and there are inmutable objects, we will get to that on the next paragraph.
What happens when we change the value of a to its id?
As now a is pointing to a new place in memory, its id changed.
How can we check if two variables have the same id? we can compare them with the is operator, it is used to compare the identity of two objects.:
>>> print(a is c) >>> True >>> print(a is b) >>> False
The type() function is used to return the type of an object. Let's check it with our variables "a" and "b":
We see that "a" is from class integer and b from class string. Note we get the class instead of type, because Python has predefined classes where every object that belongs to it is an instance of that class, aka, objects!
How can we test the type of an object? We can use the function isinstance() that returns True if an object is of a class or False if it's not. (syntax: isinstance(object, classinfo))
>>> print(isinstance(5, float)) >>> False >>> print(isinstance(5, int)) >>> True >>> print(isinstance([1, 2], list)) >>> True >>> print(isinstance([1, 2], tuple)) >>> False
Mutable and Inmutable objects
As we saw before, when an object is initiated, it is assigned a unique object id. Its type is defined at runtime and once set can never change, however its state can be changed if it is mutable. Simple put, a mutable object can be changed after it is created, and an immutable object can’t.
Objects of built-in types like (int, float, bool, str, tuple, unicode) are immutable. Objects of built-in types like (list, set, dict) are mutable. Custom classes are generally mutable. To simulate immutability in a class, one should override attribute setting and deletion to raise exceptions.
A practical example to find out the mutability of object types. We are creating an object of type int. identifiers "x" and "y" points to the same object. But if we do a simple operation, the object in which "x" was tagged is changed. object 10 was never modified. Immutable objects doesn’t allow modification after creation.
Lets test the case with mutable objects. We are creating an object of type list. identifiers "m" and "n" tagged to the same list object, which is a collection of 3 immutable int objects. Now poping (removing) an item from list object does change the object, object id will not be changed. Both lists would now be [1, 2] in this example.
"m" and "n" will be pointing to the same list object after the modification. This is what we call aliases, m & n are both aliases (see what I did there?--joke). It means changes made with one alias affect the other. Although this behavior can be useful, it is sometimes unexpected or undesirable. In general, it is safer to avoid aliasing when you are working with mutable objects. Of course, for immutable objects, there’s no problem.
What happens in memory when you change an inmutable object?
Lets use the example we saw before with a = 33 and then c = 33, but adding 3 to a changed its id, while c keeps the original.
In Python, a = 33 first creates an object 33 at a certain memory space, and then links the name a to that object location during assignment. a is then bound to that object by pointing to its memory allocated.
CPython already allocates a memory space for integers in range -5 to 256 (integer pre-allocation). If you write now c = 33, c will share the same memory location as c is simply another pointer to the same object 33.
Integers being immutable, if you do a += 3, then a new object 36 is created at a different memory address and then a will points to this new location. c stays bound to the object 33.
Note that if an object is not linked anymore to any names (a, c, etc), then it can be garbage-collected.
The pre-assign values between -5 and 256 are used, because they are most used integers! To better understand how NSMALLPOSINTS and NSMALLNEGINTS macros in Python work:
It is actually an array of 262 integers (most commonly used). And this structure is basically used to access these integers fast. They get allocated right when you initialize your NSMALLPOSINTS and NSMALLNEGINTS.
#define NSMALLPOSINTS 257 #define NSMALLNEGINTS 5
If we create two variables out this range they are equal, but they won't share the same id:
Exceptions to the rule
Every rule has its exception. In inmutable objects there are tuples, which are inmutable objects that can contain mutable objects, so at the end they can be changed. For example you can create a tuple with a list inside:
>>> t = (1,[1, 2, 3])
and change the list, but the tuple id won't change.
As it says on the data model page: "The value of an immutable container object that contains a reference to a mutable object can change when the latter’s value is changed; however the container is still considered immutable, because the collection of objects it contains cannot be changed. So, immutability is not strictly the same as having an unchangeable value, it is more subtle."
Hope you enjoyed this reading and see you on the next article! Thank you for reading!!!