Python in Detail: Everything Is an Object
Welcome to the Everything Is an Object lesson!
This lesson is shown as static text below. However, it's designed to be used interactively. Click the button below to start!
Every value in Python is an object. But what does it mean to "be an object"? It's a subtle question! We'll look at it from two different angles.
One way to think of objects is that they have attributes. And sure enough, every value in Python has attributes. We can see that by calling the built-in
dirfunction, short for "directory". It lists all of the attributes on an object, whether it has a.__dict__or not.>
class Cat:def __init__(self, name):self.name = namekeanu = Cat("Keanu")- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
dir(keanu)Result:
- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
'__doc__' in dir(keanu)Result:
True
That's a long list, but many of these attributes are familiar from past lessons. When we do
keanu == other_cat, Python callskeanu.__eq__(other_cat). When we calllen(keanu), Python callskeanu.__len__(). We didn't define those methods ourselves, so Keanu has the default implementations for them.Integers have even more attributes, including many dunder methods that implement the various mathematical operators and comparison operators.
>
dir(1)Result:
We can access any of these attributes directly. For example, we can make addition more complicated than it needs to be.
>
(1).__add__(2)Result:
3
In Python, even functions are objects!
>
def double(x):return x * 2- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
dir(double)Result:
These are all regular attributes that we can access. For example, we've already seen
.__name__.- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
double.__name__Result:
'double'
The
.__call__method does what it sounds like: it calls the function.- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
double.__call__(3)Result:
6
Most of the function attributes are mundane. But one is very special:
.__code__.- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
double.__code__Result:
It's the function's code, represented as a Python object. But it's not the source code. It's all of the other stuff about the code: the compiled byte code, line numbers, variable names, how many arguments the function takes, etc.
Like everything in Python,
.__code__is an object, so it works withdir.- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
dir(double.__code__)Result:
This is an esoteric part of Python, but it's also a good demonstration of how deep Python goes. For example, the
.co_argcountattribute tells us how many arguments the function takes.- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
double.__code__.co_argcountResult:
1
The
.co_varnamesattribute returns a tuple with the names of locals variables available indouble, including arguments that it takes.>
def double(x):return x * 2double.__code__.co_varnamesResult:
>
def add(a, b):return a + badd.__code__.co_varnamesResult:
('a', 'b')We can even see the function's byte code, which is what the Python virtual machine actually executes when we call the function. Byte code isn't human-readable, but it's still accessible.
>
def double(x):return x * 2double.__code__.co_codeResult:
Python provides the
dis("disassembler") module to help demystify this bytecode. Callingdis.dison a function prints out the bytecode in a more human-readable way.- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
import disprint("code for double")print("===============")dis.dis(double)console output Most code doesn't need to access any of this metadata. But some developer tools do need this data, so it's there. And it shows us that even functions are just another kind of object, with a rich set of their own attributes.
Everything in Python is an object, so every value has attributes. But there's another way to think about what constitutes an object. We'll see it in a future lesson!