Variables and Data Types
Beginner⏱50 minutes📖14 min readLesson 3 of 10

Variables and Data Types

Learn how Python variables are names bound to objects, how int, float, str, bool and None literals differ, and when exact arithmetic demands Decimal and f-strings

A coffee stand program prints its receipt, and the cashier stops laughing:

python
>>> tea_price = 0.10 >>> croissant_price = 0.20 >>> print("Total:", tea_price + croissant_price) Total: 0.30000000000000004

Tea and a croissant, and the register announces a total with fourteen extra digits. The customer sees a screen that cannot add two numbers written as 0.10 and 0.20. Nothing in the program is broken. Python did exactly what its design says to do, and every digit of that long number is there for a reason that you will be able to explain by the end of this lesson.

The receipt sits at the crossing point of three ideas that this lesson builds from the ground up. First, names such as tea_price point at values; they are not boxes that hold the values. Second, values arrive in kinds, such as whole numbers, numbers with a dot, text, answers and an explicit empty slot. Third, each kind has rules, so money, measurements, counts and text each need the right tool.

This lesson is the third stop of the course. By the end you will bind names, read any written value and name its kind, convert between kinds safely, dodge the classic floating point trap, and write strings that interpolate values on the fly. Every claim here is checkable in a Python 3.15 REPL, and there are interactive checks along the way.

Key terms

Object
A single piece of data living in memory, such as the number 3 or the text hello, that a name can point at.
Variable
A name that your program uses to refer to an object. The name is a sticky note, not a box that stores the value itself.
Literal
A value written directly into source code, such as 42, 3.14, text in quotes, True or None.
Data type
The kind of value an object carries, such as int for whole numbers or str for text.
Type annotation
A note next to a name or a function that documents the expected kind of value for readers and checker tools.
f-string
A string prefixed with the letter f that inserts values into text, such as f"total: {total}".
Immutable
Unchangeable after creation. Python strings are immutable, so text operations hand back a new string instead of editing one in place.
Type conversion
Building a value of one kind from another with built-in functions such as int, float and str.

1. Names and Objects: the Sticky Note Model

Start with the example from the receipt. The line tea_price = 0.10 does two things. Python first builds one object holding the value 0.1, and then binds the name tea_price to that object. The name is a label you can use to find the object again, and the type belongs to the object, not to the name.

python
tea_price = 0.10 # one float object, one name pointing at it quantity = 3 # a second object, a second name quantity = 4 # the same name, now bound to a different object

Two properties of the model explain almost everything that confuses beginners about assignment:

  • Rebinding is normal. Assigning to a name again does not edit the old object; it turns the sticky note toward a new one.
  • The type lives on the object. The name quantity never had a type of its own. It pointed at an int object, and later a name like quantity could point at text instead.

Python permits a name to hold an int now and a str later. The diagram below follows one name, count, as a program rebinds it from one kind of object to another. Every arrow is an ordinary assignment, and every new state is a different object existing in memory.

100%
Description

A state diagram for the section 1. Names and Objects: the Sticky Note Model, showing the states and transitions described in the surrounding text.

Legal Python is generous, but readers and tools pay a tax for wild rebinding. A teammate who sees count holding text will assume the same everywhere else. Checker tools such as mypy can only help if names keep a stable type, and the community guidance in PEP 8 asks exactly for that stability. Keep each name described by one word.

📌Important

Python lets a name switch types freely, and beginners should not copy that habit from the language. Pick a name whose wording describes one kind of value, and keep it on that kind for the whole program. Future you will read it, and checkers will thank current you.

Python enforces a small set of hard rules for names, and the community adds a second layer of taste on top.

  • A name may contain letters, digits and underscores.
  • A name must not start with a digit.
  • Names are case-sensitive, so Tea and tea are different names.
  • Reserved keywords such as class, if, for, while and lambda must not be used as names.
python
# legal and readable tea_price = 0.10 MAX_TABLES = 12 # legal, but foreign to Python eyes teaPrice = 0.10 # syntax errors 2nd_price = 9.99 # cannot start with a digit my-price = 9.99 # a hyphen is read as subtraction, so this is not a name class = "cs101" # class is a reserved keyword

PEP 8, the community style guide, then converts taste into convention:

  • snake_case for ordinary names: tea_price, order_total.
  • UPPER_SNAKE_CASE for values treated as constants: MAX_TABLES.
  • No single letters l, O or I, which read as digit shapes on screens.
  • Descriptive over clever: croissant_price beats cp.
Practice Question
How to answer

Multiple-choice question with 4 options. Select one option, then choose Check Answer.

A script runs `x = 5` on one line and later runs `x = "five"` on another line. Which statement is accurate about what Python does and what good practice suggests?

Practice Question
How to answer

Multiple-choice question with 4 options. Select one option, then choose Check Answer.

Which of these names is both legal in Python and in the shape that PEP 8 recommends for a customer postcode value?

What a rebinding looks like inside memory

One more view of the sticky note model, this time for three famous lines. The snippet below is worth stepping through slowly, because it separates names from objects more sharply than any definition could.

python
x = 3 # one int object is built, x is bound to it y = x + 1 # x is read, 4 is computed, a NEW int object is built, y binds to it x = "three" # a str object is built, and x is rebound away from the int

The sequence diagram shows the same three lines as a conversation between the source code and the object store. Watch that every assignment rebinds one name, while the objects themselves keep existing.

100%
Description

A sequence diagram for the section What a rebinding looks like inside memory, showing the order of messages and replies described in the surrounding text.

After the third line, x holds text and y still holds 4. The int object 3 loses its last public name, and Python cleans it up in the background without any help from you. Assignment is a fire-and-forget note change, never a deletion of data.

2. The Value Quiver: Literals You Will Meet First

A literal is a value spelled directly into source code. The five beginners below cover the overwhelming majority of programs you will read this year.

Literal
Type
Everyday meaning
42
int
a count, a quantity, an index
3.14
float
a measurement with a fractional part
"hello"
str
text, also called a string
True
bool
a yes or no answer
None
NoneType
an explicit empty slot
python
count = 42 # int ratio = 3.14 # float greeting = "hello" # str flag = True # bool empty = None # NoneType, the deliberate nothing

The mindmap gathers the full quiver in one picture, including the two corners that matter later: exact money arithmetic with decimal.Decimal, and the frozendict built-in that Python 3.15 added for fixed, immutable mappings.

100%
Description

A mind map for the section 2. The Value Quiver: Literals You Will Meet First, grouping the ideas described in the surrounding text.

Use the bucket exercise to lock the classification in. One item is a trap that catches almost every beginner the first time, so read before you drag.

Sort into Buckets
How to answer

Sorting exercise. Place each item into the correct bucket, then check your answer.

Sort each literal into its type bucket

Drag every card into the bucket that describes the object it creates in Python.

Items, click an item, then click a bucket to place it:

int

Empty, click to place the selected item

float

Empty, click to place the selected item

text

Empty, click to place the selected item

boolean

Empty, click to place the selected item

absence

Empty, click to place the selected item

3. Whole Numbers, Real Numbers and Booleans

int: digits without a ceiling

Python ints grow until memory says stop. There is no value at which + 1 suddenly wraps around or errors out, which removes a whole mistake category you would otherwise inherit from languages with fixed-width integers.

python
>>> digits = len(str(2 ** 1000)) # how wide is 2 to the power of 1000 >>> digits 302
ℹ️Note

📚 Did you know? The official library documentation states that Python int values are limited only by memory. A beginner laptop computes 2 ** 1000, all 302 decimal digits, instantly, while a fixed 64-bit integer overflows just past 9223372036854775807.

float: fast, approximate, 64 bits

Floats cover measurements and anything with a decimal point. CPython stores each one as an IEEE 754 binary64 double: a 53 bit mantissa plus an exponent, all in base 2. Numbers that need no binary tail, such as 0.5, 3 and 271.75, sit exactly in a float. Numbers such as 0.1 do not, and the tail is the seed of the receipt joke.

0.1≈7205759403792794256≈0.10000000000000000560.1 \approx \frac{7205759403792794}{2^{56}} \approx 0.1000000000000000056

The float closest to 0.1 is slightly bigger than one tenth, and that tiny excess survives every calculation. The float limits themselves are visible constants:

python
>>> import sys >>> sys.float_info.max 1.7976931348623157e+308 >>> sys.float_info.max * 2 inf >>> sys.float_info.min 2.2250738585072014e-308

bool: two values that are secretly numbers

True and False are the only bool literals, and comparisons produce them. A detail surprises everyone eventually: bool is a subclass of int, so True works as 1 and False works as 0.

python
>>> 5 > 3 True >>> 3 == 4 False >>> True == 1 True >>> type(True) <class 'bool'>
ℹ️Note

📚 Did you know? bool is a subclass of int, and True == 1 evaluates to True. Language history explains it: the bool type was added to Python 2.3 on top of the existing integer world, and the arithmetic compatibility was kept deliberately.

A conversion walkthrough you can type as you read

The built-in functions type(), int(), float() and str() do the day to day work of checking and moving between kinds. Each line below is real, so type them into a REPL and confirm them.

python
>>> type(42) # the int family classifier <class 'int'> >>> type(3.14) <class 'float'> >>> type("42") # quotes change everything <class 'str'> >>> int("42") # text to a whole number 42 >>> float("3.14") # text to a floating point number 3.14 >>> str(3.14) # a number to its text form '3.14' >>> int(3.99) # a float to an int TRUNCATES 3 >>> int("hello") Traceback (most recent call last): ... ValueError: invalid literal for int() with base 10: 'hello'

Three behaviors matter most in daily work:

  • int() applied to a float truncates toward zero, and never rounds.
  • int() applied to text that is not a number raises ValueError instead of guessing.
  • Converting user input matters constantly, because input() hands you a str and arithmetic needs an int or float.
💡Tip

int(7.9) is 7, not 8, by design. When you want school rounding, call round(7.9), which returns 8. When you want a safe money conversion, reach for round on purpose and say so in a comment.

Practice Question
How to answer

Multiple-choice question with 4 options. Select one option, then choose Check Answer.

You type `type(True)` in a Python REPL. Which output is printed?

Practice Question
How to answer

Multiple-choice question with 4 options. Select one option, then choose Check Answer.

A script contains the line `discount = int(7.9)`. Which value is stored by that conversion, and why?

4. The 0.1 plus 0.2 Problem, and the Two Honest Cures

Return to the receipt. The float nearest 0.1 carries a small positive excess, and the float nearest 0.2 carries another. The sum of the float excesses represents the value that Python is honest about:

python
>>> 0.1 + 0.2 0.30000000000000004 >>> 0.1 + 0.2 == 0.3 False

Nothing rounded wrong. Binary floating point has no exact code for one tenth, so the answer is naturally the nearest representable value. Two cures cover everyday needs, and choosing between them is a real engineering decision.

100%
Description

A flowchart for the section 4. The 0.1 plus 0.2 Problem, and the Two Honest Cures, showing the path and decision points described in the surrounding text.

Cure one: decimal.Decimal for money. The Decimal type works in base ten, so one tenth, two tenths and their sum behave exactly as the decimal payroll in your head expects it. Two details matter: build Decimal values from quoted text, never from a float, and keep floats completely out of the arithmetic.

python
>>> from decimal import Decimal >>> Decimal("0.1") + Decimal("0.2") Decimal('0.3') >>> Decimal("0.1") + Decimal("0.2") == Decimal("0.3") True >>> Decimal(0.1) + Decimal(0.2) # the wrong construction, from floats Decimal('0.3000000000000000166533453693773481063544750213623046875')

Cure two: math.isclose for comparisons. When floats are the right tool but you must compare, compare with a tolerance instead of ==.

python
>>> import math >>> math.isclose(0.1 + 0.2, 0.3) True
⚠️Warning

Float arithmetic is approximate by design and money deserves exactness. Cent counters stored as int, or decimal.Decimal built from quoted text, are the two robust choices. A float total can disagree with the ledger by a fraction of a cent, repeated across a million orders, which is a genuine business problem rather than a printing quirk.

Practice Question
How to answer

Multiple-choice question with 2 options. Select one option, then choose Check Answer.

You claim in a code review that `0.1 + 0.2 == 0.3` evaluates to `True` in Python. Is the claim true or false?

Practice Question
How to answer

Multiple-choice question with 4 options. Select one option, then choose Check Answer.

A payroll script must store wage and salary values and produce totals that match decimal arithmetic exactly. Which value kind should the script use for the money math, once the values are in?

Matching Question
How to answer

Matching exercise with 5 pairs. Match each item on the left with its answer on the right.

Match each type to the literal that represents it.

int
Drop here
float
Drop here
str
Drop here
bool
Drop here
NoneType
Drop here

Drag answers from here:

42
3.14
"42"
True
None

5. Text: the Immutable String

Strings hold text. Single and double quotes are equal, so 'hi' and "hi" build the same object. The backslash starts escape sequences for characters that are inconvenient to type directly, which gives you newlines, quotes and raw text modes.

python
>>> sentence = "she said \"hi\"\nthen left" >>> print(sentence) she said "hi" then left >>> pattern = r"\d+" # a raw string keeps backslashes literal >>> pattern '\\d+' >>> poem = """Roses tint red, ... violets stay blue, ... Python keeps the quotes ... open for you.""" # triple quotes span real lines

Strings are immutable. No method edits a string in place; each one builds and returns a fresh string. This single fact explains every surprising result a beginner meets when calling string methods.

python
>>> name = "anna" >>> name.upper() 'ANNA' >>> name 'anna' >>> shout = name.upper() # shout binds to the new string
ℹ️Note

📚 Did you know? word.upper() does not change word even when you call it twice. Because str is immutable, the only way to keep the shout is to bind it, as in shout = name.upper(). Dictionaries, not strings, are where in-place edits happen, and that lesson arrives later in the course.

The everyday toolkit covers most text chores:

python
>>> " iced tea ".strip() 'iced tea' >>> "iced tea".split() ['iced', 'tea'] >>> "iced tea".replace("tea", "coffee") 'iced coffee' >>> len("iced tea") 8

Slicing, and the end index is exclusive

Text is ordered, indexes count from zero, and slices take a start and an end. Keep one rule in memory and slicing stops being scary: the end index is always excluded. Slicing [0:4] therefore yields the first four characters, at positions 0, 1, 2 and 3.

python
>>> word = "checkout" # c h e c k o u t, indexes 0 to 7 >>> word[0] 'c' >>> word[0:4] 'chec' >>> word[4:8] 'out' >>> word[0:4] + word[4:8] 'checkout'

Positions 0 through 3 produce chec, then positions 4 through 7 produce out. The halves join back into the full word, which is a quick self-check that your end indexes are right.

6. f-strings: Text That Interpolates

An f-string is a string prefixed with an f that lets braces interpolate values straight into text. It is the standard tool for readable output, and format specs after the colon, such as :.2f, control the rendering.

python
>>> total = 0.1 + 0.2 >>> print(f"Total: {total:.2f}") Total: 0.30

The :.2f spec rounds the display to two decimal places, while the stored float itself stays as float as ever. Text interpolation without formatting works everywhere you would otherwise join strings:

python
>>> item = "tea" >>> price = 1.25 >>> line = f"{item}: {price}" >>> line 'tea: 1.25'

Fill the blanks below to rebuild the total line and the coins counter, then check yourself. The first blank makes the braces interpolate.

Fill in the Blanks
How to answer

Fill-in-the-blank exercise with 2 blanks. Type the missing words, then check your answer.

Complete the summary line and the conversion. The first blank turns the text into an f-string and the second fills the coins conversion.

blank"Total: {total}" coins = blank(cash_text)

Word Bank, drag words into the blanks above:

f
int
str
float
is
#
💡Tip

Older tutorials show two older styles, .format() and the % operator. Read them when you inherit code, but write f-strings for new work; the official tutorial recommends them for interpolation, and 3.14 even adds a companion syntax called a t-string for safe templates, covered in the updates box below.

7. None and Reading an Absence

None is the type NoneType and stands for an explicit empty slot. It says the value is deliberately missing, rather than zero, empty text or a blank.

python
>>> found = None >>> type(found) <class 'NoneType'> >>> found is None True

Functions that reach their end without a return statement hand back None, so a variable holding the result of such a function looks empty for a reason:

python
>>> result = None >>> result is None True >>> result == None True

Both comparisons above produce True, but only one is considered good style. PEP 8 and the official documentation recommend the identity form for None, because identity is exactly the question you mean: is this the one None object, or any other value?

💡Tip

Write result is None, not result == None, when checking for absence. Some objects override equals comparison in ways that turn == None into the wrong answer, while identity comparison cannot be fooled.

8. Annotations: Documentation for Readers and Checkers

Comments explain the why; annotations describe the what. A type annotation next to a parameter or a function result records what kind of value is meant, and tools such as mypy and the editors use them to check your work.

python
def total(price: float, quantity: int) -> float: """Return the price times the quantity.""" return price * quantity

The annotations above are documentation. Python records them, prints them when asked, and lets checker tools read them, yet the function itself still accepts whatever a caller passes. This is what the official tutorial calls optional static checking: enforcement comes from the tools, not from the runtime.

⚠️Warning

Annotations do not enforce anything at run time by themselves. A function annotated as returning float still runs and returns text if its body says so, until a checker like mypy or a teacher's test suite says otherwise. Treat annotations as promises that tools verify, not as a fence.

9. The Type World as of November 2026

2026 Updates (as of November 2026)

ℹ️Note

What changed recently, and why older tutorials look different. Every line below was checked against a primary source in November 2026:

  • Python 3.15.2 is the current stable release (3.15.0 shipped on 2026-10-09, and 3.15.2 followed on 2026-10-25). Tutorials that still call earlier series the latest are drifting behind.
  • frozendict is a new built-in in 3.15 (PEP 814, shipped 2026-10-09). It holds an immutable, hashable mapping, which suits fixed configuration data; a plain dict stays the everyday choice.
  • UTF-8 became the default text encoding in 3.15 (PEP 686). Opening a text file without naming an encoding now reads and writes UTF-8 across platforms, which removes a classic source of mojibake.
  • Template strings t"..." arrived in 3.14 (PEP 750, released 2025-10-07). A t-string behaves like an f-string and records template parts instead of only producing text, so frameworks can render values safely.
  • Python 3.10 reached end of life on 2026-10-01. Machines still on 3.10 receive no fixes, so a beginner starting a project should use a supported series such as 3.15.
ℹ️Note

📚 Did you know? frozendict in Python 3.15 is a built-in type, which is unusual company: int, str and dict took more than thirty years to get a sibling. PEP 814 describes it as an immutable, hashable mapping, so it can even serve as a dictionary key where a regular dict cannot.

Practice Questions

Answer these before the next lesson. Each stem stands on its own, so review sessions can show them without any surrounding page. Inline questions earlier in the sections count too, and ids stay stable for review scheduling.

Practice Question
How to answer

Multiple-choice question with 4 options. Select one option, then choose Check Answer.

In a REPL, `word = "checkout"` is set and then `print(word[0:4])` runs. What is printed?

Practice Question
How to answer

Multiple-choice question with 4 options. Select one option, then choose Check Answer.

A program sets `name = "leaf"` and runs `name.upper()`. What does `name` contain after that line, and what does the call itself produce?

Practice Question
How to answer

Multiple-choice question with 4 options. Select one option, then choose Check Answer.

A reviewer sees `if result == None:` inside a pull request and prefers another form. Which check matches PEP 8 guidance for testing against None?

Practice Question
How to answer

Multiple-choice question with 2 options. Select one option, then choose Check Answer.

A function is declared `def total(price: float) -> float:` and its body runs `return "3"`. Does the annotation stop that wrong return at run time in plain Python?

Practice Question
How to answer

Multiple-choice question with 4 options. Select one option, then choose Check Answer.

Which listing shows only legal Python variable names?

What Comes Next

You can now read the receipt joke in full: tea_price and croissant_price are names bound to float objects, and float objects speak binary. The next lessons turn these single values into structures, ordering them into lists and tuples, and then into mappings. Before moving on, the video below works as a parallel full-course reference, and its data types chapters restate this lesson's material from a second voice.

A friendly parallel full-course reference for data types: watch its data type chapters when you want this lesson replayed by a second teacherWatch on YouTube
Description

A video walkthrough that supports the section What Comes Next and repeats its main ideas in a second voice.

✅Success

Key Takeaways:

  1. A Python variable is a name bound to an object. Assignment rebinds a name, rebinding is legal across kinds, and the type belongs to the object rather than the name.
  2. The five first literals are 42 as int, 3.14 as float, "hello" as str, True as bool and None as the deliberate empty slot, each with a type you can confirm with type().
  3. int grows without a fixed ceiling, while float is an IEEE 754 binary64 double that cannot hold 0.1 exactly, which is why 0.1 + 0.2 prints 0.30000000000000004.
  4. Money math should use decimal.Decimal built from quoted text, and float comparisons should use math.isclose rather than ==.
  5. int(3.99) truncates toward zero and never rounds; use round() when school rounding is the actual requirement.
  6. Strings are immutable, so methods such as .upper() return new strings, and slices treat the end index as exclusive, so "checkout"[0:4] is chec.
  7. f-strings interpolate values with braces, and format specs such as :.2f change only the display, never the stored float.
  8. Compare against None with is None, the identity form that PEP 8 asks for.
  9. Annotations such as price: float document and feed checker tools; the runtime itself does not enforce them.
  10. As of November 2026, Python 3.15.2 is current, frozendict is a new built-in, UTF-8 is the default encoding, and Python 3.10 is end of life, so a fresh project starts on a supported series.

References

Every factual claim links to its source, with the access date printed so the source can be rechecked.

  1. Python Software Foundation · Accessed 2026-11-06

  2. Python Software Foundation · Accessed 2026-11-06

  3. Python Software Foundation · Accessed 2026-11-06

  4. [4]Built-in typesDocumentation

    Python Software Foundation · Accessed 2026-11-06

Progress30%