Everything is object! — A pythonic way to blow your mind…
Prepare to get your mind blown… because after this story, your perception of how objects work in Python will change drastically, it’ll get wider and richer. So, stay with me while we venture through the pythons core.
Eveything in Python is an object, and you might ask yourself what is an object? according to tutorialspoint an object is “A unique instance of a class. An object comprises both data members (class variables and instance variables) and methods.” Because O.O.P (Object Oriented Programming) enables programmers to think like they are working with objects, the best way to explain this is by using an example.
Let’s say we have an object in real life, like a cat
Cat has attributes that represent the data: Claws, Eyes
and cat has actions that manipulate that data: Scratch, follow red dot
And what if I tell you, that not only cat but even Claws, Eyes, Scratch, Follow red dot are treated as objects…? Cool huh? We’re just warming up.
All objects in Python can be either mutable or immutable.
Inmutable — Objects like: int, float, bool, str, tuple, bytes
Mutable — Objects like: list, set, dict, array
So, when an object is created, it has an unique ID and a type (assigned at runtime), their value can change only it the object is mutable, if immutable the value can’t change. Further explanation ahead.
Meanwhile, take a breath, because we’re going deep.
ID and Type of an object
Every object in Python has an ID and a type.
ID — Identity of an object, address memory id(<obj>)
>>> name = "Camilo" >>> id(name) 40178544
Those weird looking numbers are an address of memory, in a computer, everything is stored somewhere in the memory.
Type— Classification of the object type(<obj>)
>>> type(name) <class 'str'>
In Python, there are no built in data types. The types are actually classes and each variable is an instance of the corresponding class. So name is an object instantiated from the class str.
So long, so good. Now we know that python has mutable and immutable objects, and that every object is not an actual built-in like in C, but an instance of a class… Vamos! there’s more.
Mutable objects
As discussed later, mutable objects can be modified. Let’s take a look with our trusty lists.
list1 = [1, 2, 3] list2 = list list1.append(4) print(list2) [1, 2, 3, 4]
> list1 is a list of ints
> list1 is assigned to list2
> 4 is appended to list1
> list2 is printed with the appendend 4 in list1, but why?
It’s called aliasing, it happens whenever one variable’s value is assigned to another variable, since we created an alias list1 called list2, those names point to the same object. By using function id() we can have more insights.
id(list1) 456717722471761 id(list2) 456717722356711 list1 is list2 True
> id of list1
> prints list1’s id
> id of list2
> prints list2’s id
> Asks if list is list2
True, but why?
Both list1 and list2 point to the same object, they have the same identity.
is operator is different from ==, whilst one evaluates if it’s the same object, the other evaluates if they’ve the same value.
is — Same object
== — Same value
Things get even more interesting when trying to modify an object and have a different id, for this purpose, we shall make a copy of the assigned list and then modify it, just like this.
list1 = [1, 2, 3] list2 = list[:] list1.append(4) print(list2) [1, 2, 3] id(list1) 428073317276041 id(list2) 428071677225641 list1 is list2 False
Here, id of list1 is different from id of list2, they no longer point to the same object.
Immutable objects
As discussed later, immutable objects can be modified. Let’s take a look with our trusty tuples.
tuple1 = (1, 2, 3) tuple1[0] = 4 print(tuple1) Error : Traceback (most recent call last): ... TypeError: 'tuple' object does not support item assignment
> tuple1 has (1, 2, 3) value
> Modifying 0 position of tuple1 to 4
> prints tuple1 content
> Error, no item assignment support
Because tuple is an immutable object, then tuple1’s value can’t be modified after creation. Amazed? just read this…
Not all of the immutable objects are actually immutable.
The value of a tuple can be of different data types, mutable data types…
tuple1 = (“Camilo”, [1, 2, 3])
tuple1 contains an immutable string and a mutable list. This migth be confusing, but nonetheless important, the value of an immutable object can’t change, but it’s content objects can.
Why does it matter and how differently does Python treat mutable and immutable objects
We already know what a mutable and immutable object is, but, why does it matter, is it worth another mind-blown? Yes it’s worth it.
As a programmer, your mission is to make the computer do your biding, not knowing and even worst, not understanding how things work under the hood can mess your workflow, example.
Remember list1 and list2?, Python has to make a copy of list1 and then, reassign all the elements of the list to add a new element to it. This is not as efficient in terms of memory and time.
Immutable objects, on the other hand, are quicker because the whole object is not reassigned every time we try to modify it — Python will just create a new object with the updated value.
By understanding how mutable and immutable objects work and behave, will not only save time, but headaches and “unexpected” behaviors on the program.
How arguments are passed to functions and what that implies for mutable and immutable objects
Python stores variables in memory like pointers in C, variables store the address (the ID) of the object.
When a function asks for arguments and we pass them an object, we’re not passing the actual object, we are passing the reference of the object to the function, the address, so any change done by the function will be done in that address.
If we pass a mutable object to a function and modify its value, the new value of that object is accessible from outside the function. Like this:
def func(val): val += [3, 2, 1] x = [1, 2, 3] print x [1, 2, 3] func(x) print x [1, 2, 3, 3, 2, 1]
As shown on the example, x’s reference is passed to the func, now the func knows where the change must be done (address), because is not modifying the actual object, but a reference to it. After func, we see the updater list.
Now, if we try it with an immutable object, the modification inside the function will not be accessible from outside its scope. Like this:
def func(val): val += "bar" x = "foo" print x foo func(x) print x foo
x hasn’t been modified inside the function, still, it holds it’s original creation value outside the scope of func.
OOP is natural, versatile and powerful, knowing how everything works, from mutable to immutable objects, everything just starts to take shape. After this story I hope you consider your mind = blown.
Happy coding ;)!