Skip to content
  • Home
  • How To
  • M0
  • Module 1 - Python
  • Agents
  • M2
  • M3
  • M4
  • M5
  • M6
  • Progress
  • Contact
  • Pricing
  • Sign in
  • Future
  1. Module 1M1
  2. ›
    S1Python Foundations
  3. ›
    Lesson 2 of 4The Core Data Types - Numbers, Text, Booleans, and Nothing
  4. ›
    S1›Lesson 2 of 4
  1. Module 1
  2. ›
  3. Section 1
  4. ›
  5. Lesson 2

The Core Data Types - Numbers, Text, Booleans, and Nothing

FREE·~1.5 h·2 labs·4 questions·1 assignment


Context

Every value Python holds has a type, and the type decides what the value can do. A whole number, a decimal number, a piece of text, a true-or-false answer, and a deliberate marker for absence each behave differently even when they look similar on screen.

Type is the first thing that matters when data arrives from outside your program. A row read from a file line by line is text, all of it, including the digits, and text will not add up. A count of samples is a whole number, an accuracy is a decimal, a flag saying whether a row passed validation is true or false, and a missing measurement is not a zero, it is an absence that has to stay distinguishable from a real zero.

Get the type wrong and the failure is silent rather than loud. Adding two pieces of text that hold digits joins them end to end instead of summing, so a total of 1000 samples quietly becomes the text "500500", and the line that did it raises no error. The previous lesson got code running and printing, this lesson establishes what is actually being printed.


Goal

  • Identify the type of any literal on sight, integer, float, string, boolean, or None.
  • Predict exactly what type() returns for a given value before you run it.
  • Distinguish an integer (a whole-number count) from a float (a decimal measurement) and explain why the two behave differently.
  • Demonstrate the float rounding surprise and explain where it comes from.
  • Explain why None is a real value with its own type, not "nothing" and not zero.

Prerequisites

Neither of these is required, and the lesson teaches every category from scratch whether or not you open them. They are here only if you would rather have the shape in mind before the detail arrives.

  • YouTube - "Python Tutorial for Beginners 3: Integers and Floats - Working with Numeric Data" by Corey Schafer. Twelve minutes on the two numeric types and how they differ. Watch for the single idea that every value has a category, nothing more.
  • Official docs - The Python Tutorial, "Numbers" and "Text". Two short subsections introducing integers, floats and strings with live examples.

Table of Contents

  • Data Type and type()
  • Integer
  • Float
  • String
  • Boolean
  • None

Theory

Data Type and type()

What. A data type is the category a value belongs to, int for whole numbers, float for decimals, str for text, bool for truth-values, and so on. type() is the built-in tool that reports which category any value belongs to. Why. Every value in Python carries a type, and that type silently decides what the value can and cannot do, whether you can divide it, join it to other text, or compare it. You cannot reason about a program without knowing the types flowing through it. When. Reach for type() the moment you are unsure what a value actually is, especially after reading data from a file or a user, where a number you expected may secretly be text.

Nothing new needs to be installed for this lesson. type() is a built-in, it is always available the instant the interpreter starts, exactly like print from the last lesson. You met built-ins in Lesson 1.1.1, those are functions baked into the language with no import required.

# 'type(...)' takes one value and returns the class (the category) that value belongs to.
type(64)
# 'type' on a decimal number reports a different category than on a whole number.
type(0.01)
# 'type' on quoted text reports the string category.
type("accuracy")

Those three lines echo <class 'int'>, <class 'float'> and <class 'str'>. The <class '...'> wrapping is Python naming the kind of thing the value is, so read <class 'int'> simply as "this is an integer". Every value you will ever handle answers type() with exactly one such category.

The reason this matters is that the type is the value's rulebook. 64 + 64 gives 128 because adding two integers is defined. "acc" + "uracy" gives "accuracy" because adding two strings is defined as joining them. But mixing categories carelessly, adding a number to text, is undefined, so Python raises an error instead of guessing, and Lesson 1.1.4 covers the conversion that avoids it. The type is what Python checks to decide which behavior applies.

DON'T:

  • DON'T confuse the value with its type, 64 is the value, <class 'int'> is the category type() reports for it.
  • DON'T assume a value's type from how it looks on screen, "64" looks like a number but type("64") reports <class 'str'>, it is text.

Integer

What. An integer (int) is a whole number with no fractional part, positive, negative, or zero, written with no decimal point. Why. Integers are the natural type for anything you count: rows in a dataset, epochs of training, the number of features. A count is never 3.5, so it lives as an integer. When. Use an integer whenever the quantity is discrete and countable, and whenever you need exact arithmetic with no rounding risk.

An integer literal is written with digits, and a minus sign written in front makes the number negative. There is no upper limit you will hit in practice, Python integers grow as large as your memory allows, so factorials and huge counts stay exact.

# An integer literal: a whole-number count, here the number of training epochs.
epochs = 50
# Integers can be negative, here a (silly) offset, still a whole number.
offset = -3
# 'type' confirms the category is 'int'.
type(epochs)

Notice there is no decimal point anywhere. The moment you write 50.0 you have a different type, even though the mathematical value looks equal.

Adding, subtracting and multiplying two integers keeps an integer, while true division gives a float, as Lesson 1.1.4 shows. 64 * 2 is 128 (an int), 100 - 1 is 99 (an int). This exactness is the integer's great virtue: counting 1, 2, 3 a billion times accumulates no error, because no rounding ever happens.

# Integer plus integer is an integer, counting up batches stays exact.
batch_count = 250 + 250
# 'type' on the result confirms it stayed an 'int'.
type(batch_count)

DON'T:

  • DON'T write a leading zero on a plain integer like 007, Python rejects it, write 7.
  • DON'T reach for an integer to hold a measured quantity like a learning rate, a rate of 0.01 is not a whole number and belongs in a float.

Float

What. A float (float, short for "floating-point number") is a number written with a decimal point or in e notation, used for measured or fractional quantities. Why. Most real-world measurements, a learning rate of 0.01, an accuracy of 0.97, a temperature of 36.6, are not whole numbers, and floats are how Python represents them. They are also the source of the rounding surprises that bite beginners. When. Use a float whenever the quantity can be fractional, the result of a division, or a measurement. Any number written with a decimal point is automatically a float.

A float literal written in decimal form carries a decimal point, even if the fractional part is zero. 5.0 is a float, 5 is an integer, same mathematical value, different type and different behavior. Floats also accept scientific notation for very small or very large numbers, and a literal like 1e-3 is a float with no decimal point at all.

# A float literal: a measured rate with a decimal point.
learning_rate = 0.01
# A float written in scientific notation: 1e-3 means 1 times 10 to the power -3 = 0.001.
small_rate = 1e-3
# '5.0' is a FLOAT even though it equals the integer 5, the decimal point decides.
five = 5.0
# 'type' confirms the float category.
type(learning_rate)

The decimal point, or the e notation, is the sole signal that turns a number into a float. Write 5 and you get an int, write 5.0 and you get a float, and 1e-3 prints back as the plain decimal 0.001 while staying a float throughout.

Now the surprise that every programmer meets once and never forgets. Floats are stored in a binary format that cannot represent every decimal fraction exactly, the same way 1/3 cannot be written exactly in decimal digits. So tiny errors creep in.

# Adding two simple-looking decimals does NOT give the clean answer you expect.
0.1 + 0.2

The REPL echoes 0.30000000000000004, not 0.3. This is not a bug in Python, it is a fundamental limit of how decimal fractions are squeezed into binary floating-point. The lesson is permanent: never assume two floats are exactly equal, and expect a faint trail of error after arithmetic. (Python's standard library has a decimal module, a tool for exact decimal arithmetic, for the rare cases where this error is unacceptable, but for ML work the tiny imprecision is harmless and normal.)

DON'T:

  • DON'T test floats for exact equality like 0.1 + 0.2 == 0.3 (== asks whether two values are equal and answers True or False), it is False because of the rounding shown above.
  • DON'T store a count as a float, epochs = 50.0 invites both the rounding risk and confusion about whether half an epoch is meaningful.

String

What. A string (str) is an ordered sequence of characters wrapped in quotes, single '...' or double "...", your choice, as long as they match. Why. All text is a string: a dataset's column names, a model's label, a file path, a message to the user. A string is text held in memory, ready to use. When. Use a string for anything that is text rather than a quantity, names, labels, categories, messages, even when the text happens to contain digits, like a ZIP code.

The quotes are Python syntax marking where the text starts and ends, they are not part of the value itself. 'accuracy' and "accuracy" are the exact same string. Being an ordered sequence means the characters have positions, a first, a second and so on, and len() counts them.

# A string literal in double quotes: the name of a metric we are tracking.
metric = "accuracy"
# Single quotes make an identical string, the quote style is your choice.
dataset = 'mnist'
# 'len(...)' is a built-in that returns how many characters the string holds.
len(metric)
# 'type' confirms the string category.
type(metric)

len(metric) echoes 8, one for each character in "accuracy".

A string can hold any character, letters, digits, spaces, punctuation, even emoji. Crucially, digits inside quotes are text, not a number you can do math with.

# This looks like a number but the quotes make it a STRING, i.e. text.
year = "2024"
# Joining two strings with '+' concatenates them, it does NOT add numbers.
prefix = "model_" + "v1"

year holds the text "2024" and not the number 2024, so you could not subtract from it without converting it first, which is a later lesson. And the + joining "model_v1" is the same symbol you use to add numbers, doing something completely different because the values on either side of it are strings. The type decides what the operator means.

DON'T:

  • DON'T mix quote styles on one string, "accuracy' is a syntax error, open and close with the same kind.
  • DON'T treat a digit-string like a number, "2024" + "1" gives the text "20241", not 2025.

Boolean

What. A boolean (bool) is a truth-value: exactly one of two values, True or False, written with a capital first letter. Why. Every decision a program makes, keep training or stop, accept this row or drop it, comes down to a boolean. They are the answers to yes/no questions and the fuel for the if statements you meet soon. When. Use a boolean to record a yes/no fact (is_trained), and expect one whenever you ask a comparison question (which the next lessons cover in depth).

There are only two boolean literals, and the capitalization is mandatory: True and False. Lowercase true is just an undefined name and will error. A boolean records exactly one yes-or-no fact.

# A boolean literal: a yes/no fact about our model's state.
is_trained = True
# The other boolean literal, note the capital 'F'.
has_gpu = False
# 'type' confirms the boolean category.
type(is_trained)

Booleans become far more useful in Lesson 1.1.4, where comparison operators like > and == produce them, so a comparison such as "is accuracy above 0.9?" evaluates to exactly one of these two values.

A quiet but useful detail: in Python a boolean is a special kind of integer under the hood, where True acts like 1 and False acts like 0. You rarely rely on this directly, but it explains why True + True evaluates to 2. For now, treat booleans as their own clear category of truth-values.

DON'T:

  • DON'T write booleans in lowercase, true and false are not Python, only True and False work.
  • DON'T quote them, "True" is a string (text), not the boolean True, and the two behave differently.

None

What. None is a single special value meaning "no value here yet", the explicit, deliberate absence of data. Its type is NoneType, and there is only ever one None in a running program. Why. Programs constantly need a placeholder for "nothing assigned so far": the best model before training has run, a result not yet computed, a setting left blank. None is that honest placeholder, distinct from a real 0 or empty text. When. Use None as a starting placeholder for something that will get a real value later, and as the meaningful answer "there is nothing here."

None is written with a capital N and no quotes. It is not zero, not an empty string, not False, it is its own value with its own type, standing for genuine absence.

# 'None' marks "no model yet", we will replace it after training runs.
best_model = None
# 'type' reports the special NoneType category.
type(best_model)

The name best_model exists and is perfectly usable, it just deliberately points at "nothing meaningful yet". Later in the course you will rebind it to a trained model, and that transition from None to a real value is a common, readable pattern. Typed alone at the >>> prompt, best_model shows nothing at all, because None is the one value the REPL never echoes.

The distinction from zero and empty text is the whole point. 0 is a real count, zero correct predictions is still an answer. "" is a real string, an empty label is still a label. None says something stronger: there is no value at all. Mixing these up leads to bugs where "not computed yet" is mistaken for "computed and the answer was zero."

DON'T:

  • DON'T quote it, "None" is the four-character string "None", not the absence value None.
  • DON'T treat None as interchangeable with 0 or "", None means "no value," while 0 and "" are real values that happen to be empty or zero.

Lab Exercises

Both problems first, then both solutions. Do not peek.

Lab Exercise 1: Name That Number

Covers the first half (Data Type and type(), Integer, Float).

Start the Python REPL. For each of these literals, first write down what you think type() will report, then confirm it by calling type() on the literal: 64, 0.01, -7, 2.0, 1e-2. State for each whether it is an integer or a float, and explain in one line why 2.0 and 2 differ in type even though they are mathematically equal.

Then, still in the REPL, evaluate 0.1 + 0.2 and write down exactly what came back. Explain in one line why that is the answer, and say what it implies about ever comparing two floats with ==.

Lab Exercise 2: Text, Truth, and the Four Kinds of Empty

Covers the second half (String, Boolean, None).

Create a script values.py. In it, bind and then print each of these next to its type(), one per line: the string "loss", the string '0.5', the boolean True, the boolean False, and None. Also print len("loss") and explain the number in a comment.

Then add the part that matters. Print the results of comparing 0, 0.0, False and None against each other with ==, and print the type of each of those four. In a final comment, answer two things: why '0.5' is not a float, and which of those four values means "there is no value here" as opposed to "here is a value, and it is empty or zero".


Solution 1: Name That Number
# A whole number with no decimal point -> integer.
type(64)    # <class 'int'>
# A number with a decimal point -> float.
type(0.01)  # <class 'float'>
# Negative whole number, still no decimal point -> integer.
type(-7)    # <class 'int'>
# Has a decimal point ('.0'), so it is a FLOAT even though it equals 2.
type(2.0)   # <class 'float'>
# Scientific notation always produces a float, 1e-2 means 0.01.
type(1e-2)  # <class 'float'>
# The rounding surprise: binary floats cannot hold 0.1 or 0.2 exactly.
0.1 + 0.2   # 0.30000000000000004

64 and -7 are integers, 0.01, 2.0 and 1e-2 are floats. 2.0 and 2 are mathematically equal yet differ in type purely because of the .0, since the decimal point is what turns the whole-looking 2 into a float.

0.1 + 0.2 echoes 0.30000000000000004 rather than 0.3 because neither operand can be stored exactly in binary floating-point, so each carries a tiny error into the sum. The implication is permanent and it is the reason the surprise is worth meeting this early: never write some_float == another_float and expect it to hold, because two floats that should be equal frequently are not.

DON'T:

  • DON'T assume 2.0 is an int because it "looks whole", the decimal point makes it a float, full stop.
  • DON'T read 1e-2 as an integer, the e notation is float-only.
  • DON'T treat the trailing ...04 as a defect you can fix, it is inherent to floating-point and every language that uses binary floating point has it.
Solution 2: Text, Truth, and the Four Kinds of Empty
# Quoted text -> string.
loss_label = "loss"
# Digits inside quotes are still TEXT, the quotes decide, not the contents.
half_text = '0.5'
# Capitalized truth-values -> boolean, the capital letter is mandatory.
converged = True
has_gpu = False
# The explicit absence value -> NoneType.
checkpoint = None

# Print each value beside the category 'type()' reports for it.
print(loss_label, type(loss_label))        # loss <class 'str'>
print(half_text, type(half_text))          # 0.5 <class 'str'>
print(converged, type(converged))          # True <class 'bool'>
print(has_gpu, type(has_gpu))              # False <class 'bool'>
print(checkpoint, type(checkpoint))        # None <class 'NoneType'>
# 'len' counts the four ordered characters l, o, s, s.
print(len("loss"))                         # 4

# Compare the four values that all look like "empty" against each other.
print(0 == 0.0, 0 == False, 0.0 == False)  # True True True
# False False False
print(None == 0, None == 0.0, None == False)
# And the types of those same four values.
print(type(0), type(0.0))                  # <class 'int'> <class 'float'>
print(type(False), type(None))             # <class 'bool'> <class 'NoneType'>

# '0.5' is not a float because the quotes make it text, and text is a category,
# not a number, so it would have to be converted before any arithmetic.
# Of the four, only None means "there is no value here". 0, 0.0 and False are
# real values that happen to be zero, zero-point-zero, and no.

Run it:

# Hand the file to the interpreter, every 'print' above writes one line.
python3 values.py

The two comparison lines are the ones to sit with. 0, 0.0 and False all compare equal to one another, because == asks about value and all three carry the same numeric value of zero, False included, since a boolean is a special kind of integer underneath. None compares equal to none of them, because it is not a quantity at all. Yet all four report a different type(), so equality and category are two different questions, and neither answer can stand in for the other.

DON'T:

  • DON'T call len() on a number, len(64) errors, because a number has no characters to count.
  • DON'T assume '0.5' behaves like 0.5, one is text and one is a number.
  • DON'T read 0 == False being True as proof they are the same thing, their types differ and only one of them is a truth-value.

Theory Assessment

Conceptual reinforcement, not a coding section. All four questions with their hints first, then all four answers.

Q1: What type() Reports, and the Missing Decimal Point

Two parts. First, in one sentence, say what type() does and what the <class 'int'> it echoes actually tells you about a value. Second, explain why type(5) and type(5.0) report different categories even though 5 and 5.0 are mathematically equal, and name both types.

Hint: type() does not change the value, it reports which group the value belongs to. For the second part, one tiny piece of syntax is the entire difference between the two.

Q2: Two Values That Are Not What They Look Like

Both parts are cases where the screen misleads you. First, you write zip_code = "90210", is zip_code an integer or a string, and what is one operation that behaves differently because of that? Second, explain in two or three sentences why 0.1 + 0.2 does not equal 0.3, and what that means for comparing floats.

Hint: For the first, the quotes decide the category no matter what sits between them, and + is the operation worth testing. For the second, the cause is how decimal fractions are stored, not a mistake in your arithmetic.

Q3: Truth Values and Genuine Absence

Two parts on the last two categories. First, explain why True + True evaluates to 2 and why type(True + True) reports <class 'int'>. Second, a teammate says "None, 0, and "" are all just empty, so they are the same", correct them precisely, saying what each one actually represents.

Hint: For the first, a boolean is not really separate from integers underneath, so consider what number each truth-value stands in for. For the second, two of the three are real values that happen to be empty or zero, and one of them means there is no value at all.

Q4: Five Values That All Look Like Nothing

Here are five values: "0", 0, 0.0, False, None.

Answer three things about them, and be exact. First, how many distinct types are present, and name the type of each value. Second, which pairs compare equal under ==, and which values are equal to nothing but themselves. Third, a student concludes from your second answer that "if two values are ==, they are the same kind of thing, and if they are not ==, they are different kinds of thing." Show that both halves of that conclusion are wrong. One half falls to a pair from this list, and for the other you will have to reach outside it, which is itself worth explaining.

Hint: Work out the equality answer by running it before you reason about it, because at least one result surprises nearly everyone. Then notice that the equality groups and the type groups do not have the same shape, and that mismatch is the whole question.


Answer 1:

type() takes a value and returns the category, the class, that the value belongs to, without altering the value at all. The echoed <class 'int'> tells you the value is an integer, meaning a whole number, and therefore that it follows the integer rulebook for which operations are valid on it.

type(5) reports <class 'int'> and type(5.0) reports <class 'float'>. The entire difference is the decimal point: 5 has none, so it is a whole-number integer, while 5.0 carries a .0, which makes it a floating-point number. They are equal in mathematical value but belong to different categories with different behavior.

DON'T say type() "converts" the value, it only reports the category and changes nothing. And DON'T assume equal value means equal type, 5 == 5.0 is True yet their types differ.

Answer 2:

zip_code is a string, because the value is wrapped in quotes, and quotes mark text regardless of whether the characters between them are digits. The operation that gives it away is +: zip_code + "1" joins text into "902101", whereas if it were the integer 90210, then + 1 would add to make 90211. The type decides whether + means "join text" or "add numbers".

0.1 and 0.2 cannot be stored exactly in the binary floating-point format Python uses, the same way 1/3 cannot be written exactly in decimal digits. Each is therefore stored with a tiny error, and adding them yields 0.30000000000000004 instead of 0.3. The practical consequence is that you must never test floats for exact equality, and should compare with a small tolerance instead of expecting == to hold.

DON'T treat a quoted ZIP code, phone number or ID as a number, they are labels, and leading zeros and + behavior both matter. And DON'T blame Python for the float result, the imprecision is inherent to floating-point and affects every language that uses binary floating point.

Answer 3:

In Python a boolean is internally a special kind of integer, where True stands in for 1 and False stands in for 0. So True + True is really 1 + 1, which is 2, and because adding two integers gives an integer, type(True + True) reports <class 'int'> rather than bool.

The teammate is wrong on all three counts, because the three mean different things. 0 is a real integer value, a genuine count that happens to be zero. "" is a real string value, a genuine piece of text that happens to be empty. None is the special NoneType value meaning there is no value at all, neither zero nor empty text, but the deliberate absence of any value. Confusing "not computed yet" with "computed and got zero" is a real and common source of bugs.

DON'T lean on boolean arithmetic for clarity in real code, adding Trues to count them works but reads poorly. And DON'T lump the three empties together, code often has to tell "absent" apart from "empty".

Answer 4:

All five types are distinct, so there are five: "0" is str, 0 is int, 0.0 is float, False is bool, and None is NoneType.

Three of the five compare equal to one another. 0 == 0.0 is True, 0 == False is True, and 0.0 == False is True, because == asks about numeric value, all three carry the value zero, and a boolean is a special kind of integer where False stands in for 0. "0" is equal to none of the others, because a string is never numerically equal to a number, and None is equal to none of them either, because it is not a quantity at all. So "0" and None are each equal to nothing but themselves, for two completely different reasons.

Both halves of the student's conclusion fail. The first half dies inside this list: 0 and False are == while being an int and a bool, so equal never implied same kind.

The second half cannot be broken by anything in this list, and noticing why is the point. All five values here have distinct types, so no two of them are the same kind of thing to begin with, and a counterexample needs a pair that is the same kind and still not equal. Step outside the list and it is immediate: 0 and 1 are both int and are not ==, and "0" and "" are both str and are not ==. Equality asks about value and type() asks about category, they are two different questions, and neither answer can stand in for the other.

DON'T use == as a type check in either direction. Value and category are separate axes here, which is exactly why type() exists as its own tool rather than something you could infer from a comparison.


Assignment

One assignment. The problem and its hints first, then the solution.

Assignment: The Placeholder Lifecycle

Model how a value starts absent and later becomes real. Create lifecycle.py and walk it through four stages, printing at each one.

(1) Bind best_accuracy = None and print it with its type. (2) Print whether it currently is None, using the is operator rather than ==. (3) "Train" by rebinding best_accuracy = 0.0, then print it with its type and print the is None test again. (4) Rebind once more to best_accuracy = 0.97 and print the final value and type.

Then, in comments, settle three things. Explain why stage (1) and stage (3) mean opposite things even though 0.0 looks "empty". Explain why is None is the correct test for absence where == 0 is not, and demonstrate the failure rather than asserting it, by printing best_accuracy == 0 at stage (3) alongside the is None result. Finally, state what == 0 would have reported back at stage (1), and whether that answer would have been safe to rely on.

Hints:

  • None means "no value yet", while 0.0 is a real measured value of zero, so a test that cannot tell those apart will silently misread a genuine result as a missing one.
  • The is operator tests whether a name points at the exact None object rather than at something merely equal to it, which is why it is the recommended way to check for None.

Solution:
# (1) Start absent: no accuracy has been measured yet.
best_accuracy = None
print(best_accuracy, type(best_accuracy))  # None <class 'NoneType'>

# (2) 'is None' tests whether the name points at the exact None object.
print(best_accuracy is None)               # True

# (3) "Train" once: rebind to a REAL measured value that happens to be 0.0.
best_accuracy = 0.0
print(best_accuracy, type(best_accuracy))  # 0.0 <class 'float'>
print(best_accuracy is None)               # False
# The demonstration: as a test for absence, '== 0' calls this real 0.0 missing.
print(best_accuracy == 0)                  # True

# (4) Improve: rebind to the final measured accuracy.
best_accuracy = 0.97
print(best_accuracy, type(best_accuracy))  # 0.97 <class 'float'>

# Stage (1) means "no accuracy measured yet", stage (3) means "measured, and the
# answer was 0.0". They both look empty and mean opposite things.
# At stage (3) 'is None' is False while '== 0' is True, so '== 0' reports the
# real measurement as if it were the missing one.
# Back at stage (1), 'None == 0' would have been False, which as a test for
# absence calls the missing value present. So '== 0' is wrong at both stages,
# in opposite directions, and neither mistake raises an error.

Run it:

# Walk the placeholder from absent to measured to final.
python3 lifecycle.py

The output traces the lifecycle: None <class 'NoneType'> with is None reporting True, then after the first rebind 0.0 <class 'float'> with is None reporting False and == 0 reporting True, and finally 0.97 <class 'float'>.

The last comment carries the part worth keeping. == 0 asks about value, so as a test for absence it is wrong at both stages and in opposite directions: at stage (1) it calls the missing None present, and at stage (3) it reports a genuine measured 0.0 as though nothing had been measured. Neither mistake raises an error, so both pass silently, while is None gives the right answer at every stage.

DON'T use == 0 to detect a missing value, is None asks about identity and == 0 asks about value, and only one of those two questions is the one you actually meant.


Additional Resources

Optional, and nothing later in the bootcamp leans on either one. Open them only if this lesson left a question behind.

  • YouTube - "Learn Python - Full Course for Beginners [Tutorial]" by freeCodeCamp.org. The early section on numbers, strings and booleans, for a second visual pass over the core categories.
  • Official docs - The Python Tutorial, "Floating-Point Arithmetic: Issues and Limitations". The careful, full explanation of why 0.1 + 0.2 is not exactly 0.3, which the page works through on 0.1 + 0.1 + 0.1, well past the single example this lesson needed.

Summary

This lesson took the single idea you already had, that a program is full of values, and revealed that each of those values quietly carries a label that decides what it can do. A whole number and a decimal number look like cousins, yet Python treats them as separate species: one exact and countable, the other measured and faintly imprecise. Text wears quotes and obeys entirely different rules, where a plus sign joins instead of adds. A truth-value collapses the whole world into yes or no. And None stands honestly for the times when there is simply nothing to report yet.

The tool that ties it together is small but it will follow you everywhere: type() is the question you ask whenever a value surprises you. Most of the confusing bugs in a beginner's first month are type bugs in disguise, a number that was secretly text, a missing value mistaken for zero, two floats that refused to be equal. Knowing the five core categories on sight, and knowing how to interrogate any value you are unsure about, is what turns those mysteries into quick, obvious diagnoses.

None of this is machine learning yet, but the seam is already visible. The line between text and a number is the first line that later decides whether a column is grouped as a category or measured as a quantity. The datasets ahead are enormous collections of values, most of them these same five kinds, and every transformation you will ever apply to them begins with the question this lesson taught you to ask: what type is this, really?


Cheat Sheet

Part A - Reference Table

Type Example literal type() reports When to use When to avoid
int 64, -7, 0 <class 'int'> Counting whole things exactly Measured/fractional quantities
float 0.01, 2.0, 1e-3 <class 'float'> Measurements, division results Exact counts (rounding risk)
str "loss", 'mnist' <class 'str'> Any text, labels, names Math (digits in quotes are text)
bool True, False <class 'bool'> Yes/no facts, decisions Storing more than two states
None None <class 'NoneType'> "No value yet" placeholder When you mean a real 0 or ""

Part B - Compact Code Block

n = 64           # int: whole-number count
rate = 0.01      # float: decimal, slightly imprecise
name = "adam"    # str: text in quotes (single or double)
ok = True        # bool: True / False, capital first letter
weights = None   # NoneType: explicit "no value yet"

type(rate)       # -> <class 'float'> (ask any value its category)
0.1 + 0.2        # -> 0.30000000000000004 (float rounding surprise)
len("adam")      # -> 4 (one per character)
weights is None  # -> True (test for absence, not '== 0')
←Previous: Lesson 1
Next: Lesson 3→

Questions about this lesson: #module-1 on Discord

Found an error in this lesson? Report it

Your progress
Current streak
🔥 0
Lessons marked today
0 / 3
Longest streak
0

Sign in

The bootcamp

  • Curriculum
  • How To
  • Pricing
  • Changelog
  • Future

The community

  • Discord
  • Reviews
  • Contact

Follow

  • Instagram
  • X
  • TikTok
  • Reddit

Legal

  • Terms
  • Privacy
  • Refunds

Coming soon on November 16, 2026

Theme