Values, types and names · about 30 min

Everything is an object: values and types

Why this matters

A program spends its life creating data, inspecting it and combining it. In Python every piece of data, from the number 3 to a function to a module, is an object, and every object has a type that decides what you can do with it. Once you see values as objects with a type, error messages like TypeError: unsupported operand type(s) for +: 'int' and 'str' stop being mysterious: Python is telling you that these two objects' types do not know how to combine. This mental model is the foundation for the whole track.

What an object is

When CPython runs x = 42, it needs the number 42 to exist somewhere in memory. It is stored as an object: a block of memory (a C structure inside the interpreter) holding

From the Python side you see three properties:

PropertyQuestion it answersHow to see itCan it change?
identitywhich object is this?id(obj)never, for the object's lifetime
typewhat kind of object?type(obj)no
valuewhat data does it hold?printing it, using itonly for mutable types
>>> x = 42
>>> type(x)
<class 'int'>
>>> id(x)
140245839127632

The id is a number unique among objects alive at the same time. In CPython it happens to be the memory address of the object. The exact number differs every run, so never rely on it in output; you will use it in the next lesson to tell objects apart.

Literals: how values get into a program

A literal is a value written directly in the source code. The way you write it decides its type:

42          # int: a whole number
-7          # an int too (the minus is an operator applied to 7)
3.14        # float: a number with a fractional part
1e6         # float: 1 times 10 to the 6th, i.e. 1000000.0
"hello"     # str: text
'hello'     # the same str; quote style does not matter
True        # bool: one of the two truth values
None        # NoneType: "no value"
[1, 2, 3]   # list (module 7)

When the compiler meets a literal, it creates the object and stores it as a constant in the bytecode. Remember LOAD_CONST from the bytecode lesson: that instruction pushes one of these pre-built constant objects.

type() and the built-in types

type(obj) returns the object's type. The core built-in types you will use constantly:

print(type(42))
print(type(3.0))
print(type("3"))
print(type(True))
print(type(None))
<class 'int'>
<class 'float'>
<class 'str'>
<class 'bool'>
<class 'NoneType'>

<class 'int'> is the repr of the type object. If you want just the name, every class has a __name__ attribute:

print(type(42).__name__)
int

The dot in type(42).__name__ is attribute access: "get the attribute called __name__ from this object". Names surrounded by double underscores ("dunder" names) are special names that Python itself defines and uses.

Types decide behavior

The same operator means different things for different types, because each type defines what its operations do:

print(3 + 4)          # int + int: addition
print("3" + "4")      # str + str: concatenation
print("ab" * 3)       # str * int: repetition
print(3 * 4)          # int * int: multiplication
7
34
ababab
12

When you write a + b, the VM looks at the type of a and asks it how to add b (concretely, it calls the type's __add__ method; you will write such methods yourself in the object-oriented module). If neither type knows how, you get a TypeError:

print(3 + "4")
TypeError: unsupported operand type(s) for +: 'int' and 'str'

Python is strongly typed: it does not quietly convert "4" into 4 or 3 into "3" for you. It is also dynamically typed: names do not have types, objects do. The same name can refer to an int now and a string later. Both ideas come up again and again.

Asking "is this a kind of X?": isinstance

type(x) == int checks for exactly int. Usually what you want is "is x an int or something that behaves as one", which is isinstance:

print(isinstance(42, int))
print(isinstance("42", int))
print(isinstance(3.0, (int, float)))   # any of several types
True
False
True

The difference matters with subtypes. You will see in lesson 4 that bool is a subtype of int, so isinstance(True, int) is True while type(True) == int is False.

Even types and functions are objects

"Everything is an object" is literal. Functions are objects; types are objects; modules are objects:

print(type(print))
print(type(int))
print(type(type))
<class 'builtin_function_or_method'>
<class 'type'>
<class 'type'>

Because int is an object, you can store it in a variable and call it later: convert = int then convert("5") gives 5. This uniformity is one of Python's great strengths, and later modules (functions as values, decorators, classes) are built on it.

Common mistakes

Recap

Going further: in the REPL, try dir(42) to list the attributes of an int object, and help(int) to read about them. Many have dunder names: that is how operators are implemented.

Exercises

Exercise 1 · quiz

The three properties of an object

Every Python object has three properties. Which list names them?

Answer
  • identity, type, value

Identity (which object it is, fixed for its lifetime, shown by id()), type (what kind of object, fixed, shown by type()), and value (the data it holds). Names are not a property of an object: an object can have zero, one or many names bound to it, as the next lesson shows.

Exercise 2 · quiz

Read the literal

Select all of the literals below whose type is str.

Answer
  • '42'

  • "3.5"

  • '''True'''

Quotes make a string, whatever the characters inside look like. '42', "3.5" and '''True''' are all str; 42 is an int, 3.5 a float and True a bool. The type of a literal is decided by the compiler from how it is written, before the program runs.

Exercise 3 · write code

Show the types

Read one line of input (a string), then print, on four lines, the type names of:

  1. the input line itself,
  2. the input converted with int(),
  3. the input converted with float(),
  4. the result of the comparison len(line) > 1 (where line is the input; len(line) is the number of characters in it).

Print just the type's name using type(x).__name__. For input 7 the output must be exactly:

str
int
float
bool

The input will always be a whole number.

File: main.py

Starting point

line = input()
print(type(line))

Example

input

7

expected output

str
int
float
bool

Example

input

-120

expected output

str
int
float
bool
Hint 1

print(type(line)) shows <class 'str'>; type(line).__name__ is just str.

Hint 2

Convert first, then ask for the type: type(int(line)).__name__.

Reference solution
line = input()
print(type(line).__name__)
print(type(int(line)).__name__)
print(type(float(line)).__name__)
print(type(len(line) > 1).__name__)

Exercise 4 · quiz

Types are objects too

What does this print?

print(type(type(3)))

Type the exact output.

Answer

type(3) is the class int, and int is itself an object whose type is type. In Python, classes are objects like any other: you can store them in variables, pass them to functions and ask for their type. type is the type of all classes (it is even its own type).