So far we've seen some of the building blocks of data in Python.
Now it's time to take a look at how Python manages objects
and names for those objects within its own system.
For this, I think a useful analogy is to think of a Python object as a suitcase.
This suitcase on the left contains the number 47,320.
The suitcase also has some additional information,
like the type of the object in this case int,
and maybe some extra metadata floating in that bottom right-hand corner.
But suitcases can represent more complex information as well,
not just numbers but also perhaps strings.
In this case the suitcase on the right has the value,
the string "Hello", as well as the type string and maybe some additional metadata.
To get a better understanding of these objects,
let's take a dive into the interactive interpreter.
The key thing to understand here is that pretty much everything in Python is an object.
Understanding objects lets us understand almost everything.
We can ask, is four an object and indeed four is an object.
We can ask, is the string "Hello" an object?
Yes, the string "Hello" is an object.
We can ask, is the value 2.5 an object?
Yes, this float is also an object.
Is the special value None an object?
Yes, the special value None is an object.
Is the value True an object? It is.
Even more abstract things like the type string
itself is an object or the function is instance,
all of these things are objects.
What should we do with objects?
What can we learn about objects?
Well, first every Python object has a type that we can get with the type function.
The type of the value four is the type int.
The type of the value 2.5 is the type float.
The type of the value "Hello" is string,
and the type of the value None is NoneType.
We can even see the type of the value False is a Boolean.
If we keep asking questions,
we'll see something surprising.
The type of the type int is type,
it is a type type.
The type of the type of int is also type.
Something interesting and maybe recursive is happening here at the root.
But for our purposes,
the important thing to understand is that every Python object has some type.
The second important thing to know about Python objects is that they have identity.
For example, the number 41 has some identity that we get with the id value.
The string "Hello" has some identity that we get with the id function here.
If we ever try to compare two values,
like one and 1.0,
it feels like these should be the same,
and indeed they are when we're interpreting with
the double equal sign the value to be the thing that we're comparing.
But Python also gives us an is comparator that checks whether
the two objects on the left and right-hand side are literally the exact same object,
whether they have the same id.
In this case, it's False.
Python even warns us because this is a common mistake.
If we ask for the type of one,
it's an int, but the type of 1.0 is a float.
Really they're fundamentally different objects even if they represent the same value.
This can apply with strings as well.
If we have one big string that says, "Hello world",
and one small string that says "Hello" to which we add some suffix " world",
x and y contain the same values,
so x is equal to y but x is not in fact the exact same object as y.
This is the main difference between equals and is.
Equals is used for comparing values which you do almost always,
is is used when you're comparing identities which is almost never.
You really only use it when you're comparing against the single thing types
that you know that there only exists one copy of.
Interestingly enough, the id here of
a Python object is actually the same as its memory address in C Python,
the reference implementation that I'm using,
the reference implementation of the Python language specification.
But really we're going to spend our time to think about the id
as a unique label that this object has,
so objects have types and identities.