Python Basics: Variables, Data Types, and Operators
Summary
Covers Python's core building blocks: variables and assignment, all fundamental data types (integers, floats, strings, booleans, lists, tuples), mathematical and comparison operators, string operations, imports, and code indentation.
Concepts Covered
This chapter covers the following 23 concepts from the learning graph:
- Python Programming Language
- Variable
- Variable Assignment
- Integer Data Type
- Float Data Type
- String Data Type
- Boolean Data Type
- List Data Type
- Tuple Data Type
- None Value
- Type Conversion
- Mathematical Operators
- Comparison Operators
- Logical Operators
- Import Statement
- Module System
- Code Indentation Rules
- Python Comments
- String Concatenation
- List Indexing
- Tuple Immutability
- Modulo Operator
- Integer Division
Prerequisites
This chapter builds on concepts from:
Pixel says...
Welcome to Chapter 2! We're about to learn the building blocks of every Python program. Variables, data types, and operators are the tools you'll use in every single LED project. Let's light this up!
What You'll Learn
By the end of this chapter, you'll be able to:
- Create variables and store different kinds of data in them
- Recognize and use Python's six main data types
- Write math expressions and comparisons using operators
- Import modules to add extra power to your programs
- Write clean, correctly indented Python code with helpful comments
What You'll Need
For this chapter you don't need any hardware — just Thonny and your Raspberry Pi Pico. All the short examples run in Thonny's Shell panel (the REPL window at the bottom).
Python: The Language of This Course
Python is a programming language — a set of words and rules that computers understand. Think of it like a recipe language. You write the steps, and the Pico follows them exactly.
Python was created in 1991 by Guido van Rossum. It's now one of the most popular languages in the world. Scientists, game developers, and makers all use it.
We use a special version called MicroPython. MicroPython is Python that runs on tiny computers like the Raspberry Pi Pico. It packs almost all of Python's features into a very small space.
Here's the simplest Python program you can write. This single line prints a greeting to the screen:
print("Hello, world!") # This line shows text in the Shell panel
Run it in Thonny's Shell. You should see Hello, world! appear immediately.
Variables: Named Storage
A variable is a named storage spot for a piece of information. Think of it like a labeled box. You put something inside, give the box a name, and use that name whenever you need what's inside.
Variable assignment means placing a value into a variable. In Python, you use the equals sign (=) to assign a value. The variable name goes on the left, and the value goes on the right:
color_name = "red" # Store the text "red" in color_name
led_brightness = 200 # Store the number 200 in led_brightness
is_on = True # Store True in is_on
After assignment, you can read the value back by using the variable's name:
color_name = "red"
print(color_name) # Prints: red
Pixel thinks...
Variable names can use letters, numbers, and underscores. Always start with a letter — not a number. So led_1 is fine, but 1_led won't work. Python is also case-sensitive: Color and color are two different variables. Use lowercase_with_underscores for all your variable names.
Here are the naming rules to remember:
- No spaces in names — use underscores:
strip_length, notstrip length - Python keywords (
for,if,while) can't be used as variable names - Choose names that describe what's stored:
red_brightnessis great,xis not
Data Types: What Kind of Thing Is It?
Every value in Python has a data type — a category that describes what kind of information it is. Python has six types you'll use in this course.
Before we look at each type in detail, here's a quick overview:
| Data Type | Example | What It Stores |
|---|---|---|
| Integer | 255 |
Whole numbers (no decimal) |
| Float | 2.5 |
Numbers with a decimal point |
| String | "red" |
Text characters |
| Boolean | True |
True or False only |
| List | [255, 0, 0] |
Ordered, changeable collection |
| Tuple | (255, 0, 0) |
Ordered, unchangeable collection |
Let's explore each one.
Integers: Whole Numbers
An integer (often shortened to int) is a whole number with no decimal point. Integers can be positive, negative, or zero.
num_pixels = 30 # How many LEDs on the strip
red_channel = 255 # Maximum brightness for red
blue_channel = 0 # Blue is completely off
You'll use integers constantly in NeoPixel programming. Color values always range from 0 to 255 — all integers.
Floats: Decimal Numbers
A float (short for "floating-point number") is a number that includes a decimal point.
brightness_scale = 0.75 # 75% brightness
speed = 1.5 # 1.5 seconds per animation frame
Use floats when whole numbers aren't precise enough — like setting brightness to 37.5%.
Strings: Text
A string is a piece of text. You create a string by wrapping characters in quotation marks — either single quotes (') or double quotes (").
color_name = "rainbow"
message = 'Hello, coder!'
empty = "" # An empty string — still a valid string
String concatenation means joining two strings together using the + operator. The following code joins two strings and prints the combined result:
first = "Moving"
second = " Rainbow"
full = first + second # full is now "Moving Rainbow"
print(full) # Prints: Moving Rainbow
Booleans: True or False
A boolean (or bool) can only hold one of two values: True or False. Always capitalize both words exactly that way.
strip_is_on = True
animation_running = False
Booleans are the building blocks of decisions. When you ask "is the button pressed?" the answer is always a boolean.
Lists: Ordered and Changeable
A list is a collection of values stored in order. You create a list with square brackets [ ], separating items with commas.
rgb_color = [255, 100, 0] # Orange: red=255, green=100, blue=0
steps = [0, 7, 14, 21, 28] # Five pixel positions
Lists are changeable — you can add, remove, or update items after you create them.
List indexing means accessing one item from a list by its position number. Python counts from 0, not 1. So the first item sits at index 0, the second at index 1, and so on:
rgb_color = [255, 100, 0]
red = rgb_color[0] # Gets 255 — the first item
green = rgb_color[1] # Gets 100 — the second item
blue = rgb_color[2] # Gets 0 — the third item
Watch out!
Python counts from 0, not 1. The first item is at index [0], not [1]. If your list has 3 items, the valid indexes are 0, 1, and 2. Trying to access index 3 on a 3-item list will cause an error — and it surprises a lot of beginners!
Tuples: Ordered and Unchangeable
A tuple is like a list — but once you create it, you can't change it. You create a tuple with parentheses ( ).
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
WHITE = (255, 255, 255)
Tuple immutability means tuples are "locked." You can read items from a tuple, but you can't add, remove, or change them after creation. This is exactly why color constants in NeoPixel code use tuples — you don't want to accidentally overwrite RED.
RED = (255, 0, 0)
print(RED[0]) # 255 — reading is fine
# RED[0] = 128 # This would raise a TypeError — tuples can't be changed
You index a tuple the same way you index a list — using [position].
None: No Value Yet
None is a special value that means "nothing" or "no value yet." It's used when a variable needs to exist but doesn't have a meaningful value at the moment.
last_button_press = None # No button pressed yet
You'll see None used as a placeholder before a variable gets its real value.
Now let's practice identifying all six types interactively:
Diagram: Python Data Type Explorer
Python Data Type Explorer
Type: microsim
sim-id: python-data-type-explorer
Library: p5.js
Status: Specified
Bloom Level: Understand (L2) Bloom Verb: classify, identify Learning Objective: Students classify Python values by data type — given a displayed value, they select its type from six options and receive feedback that connects the type to an LED programming context.
Instructional Rationale: The classify objective (L2 Understand) calls for a prediction-then-reveal pattern, not animation. Students see a value, commit to a type selection, then receive confirmation with an explanation. Prediction before reveal is the key retrieval-practice mechanism for retention at this level.
Canvas layout:
- Top area: A large "value card" showing a Python value in monospace font on a dark background (e.g., 42, "hello", True, 3.14, [1,2,3], (255,0,0), None)
- Center area: Seven labeled type buttons — Integer, Float, String, Boolean, List, Tuple, None — arranged in a row or two rows on narrow screens
- Bottom area: Feedback panel showing correct/incorrect result with an explanation and an LED code example
- Progress bar: "Question X of 15" shown below the value card
Visual elements: - Value card: Large rounded rectangle, dark background, white monospace text, border color matches type (blue=int, cyan=float, green=string, yellow=bool, orange=list, purple=tuple, gray=none) — border only shown AFTER student answers - Type buttons: Pill-shaped, highlight on hover, turn green (correct) or amber (incorrect) after selection - Feedback panel: Warm green background (correct) or amber (not quite) with two lines of text: (1) why this value is that type, (2) an LED example using this value
Data Visibility Requirements:
Stage 1: Show value card with value visible, border color hidden
Stage 2: Student clicks a type button
Stage 3: Reveal correct type, color the border, show feedback:
- Why: e.g., "255 is an integer — it's a whole number with no decimal point"
- LED example: e.g., "In NeoPixel code: strip[0] = (255, 0, 0) — 255 is the red channel value"
Stage 4: "Next" button advances to a new value
Values to cycle through (15 total):
- 42 → Integer
- 3.14 → Float
- "hello" → String
- True → Boolean
- [255, 0, 0] → List
- (128, 0, 200) → Tuple
- None → None
- 0 → Integer
- 0.5 → Float
- "Moving Rainbow" → String
- False → Boolean
- [1, 2, 3, 4, 5] → List
- (255, 255, 255) → Tuple
- 255 → Integer
- "" → String (empty string)
Controls: - Seven type buttons (one per type) - "Next Value" button — shown after student answers, advances to next card - "Shuffle" button — randomizes card order for replay
Responsive design: Canvas width fills container; font sizes and button layout scale with canvas width; buttons reflow to two rows on narrow screens.
Type Conversion: Changing From One Type to Another
Sometimes you need to convert a value from one type to another. This is called type conversion.
Python has three built-in functions for the most common conversions. Before seeing examples, here's what each one does:
int()— converts to an integer, cutting off any decimalfloat()— converts to a float, adding a decimal pointstr()— converts to a string of text
Now let's see each one in action:
# String to integer
brightness_text = "200" # This is a string — you can't do math with it yet
brightness_number = int(brightness_text) # Now it's the integer 200
# Integer to float
speed = 3
speed_float = float(speed) # Now it's 3.0
# Integer to string
channel_value = 255
channel_text = str(channel_value) # Now it's the string "255"
Type conversion matters in NeoPixel code. If a sensor returns a reading as a string, you must convert it to an integer before using it as a color value.
Pixel's tip
You can check a variable's type with type(). In the REPL, try print(type(255)) — you'll see <class 'int'>. And print(type(3.14)) shows <class 'float'>. This is great for debugging when a value isn't behaving the way you expect!
Operators: Making Things Happen
Operators are symbols that perform actions on values. Python has three groups you'll use constantly.
Mathematical Operators
Mathematical operators do arithmetic. You already know most from math class. Let's look at each one before summarizing them in a table:
red = 100 + 55 # 155 — addition
steps = 30 - 5 # 25 — subtraction
double = 128 * 2 # 256 — multiplication
half = 100 / 2 # 50.0 — division (result is always a float)
quotient = 100 // 3 # 33 — integer division (drops any remainder)
remainder = 100 % 3 # 1 — modulo (just the leftover)
squared = 4 ** 2 # 16 — exponentiation
Two operators deserve extra attention: integer division (//) and the modulo operator (%). They always work as a pair. When you divide 100 by 3:
100 // 3gives33— how many full groups of 3 fit into 100100 % 3gives1— what's left over after those 33 full groups
The modulo operator shows up constantly in LED animation. It lets a pixel position wrap around the strip instead of falling off the end:
import config
position = 47
strip_length = config.NUMBER_PIXELS # e.g., 30
wrapped = position % strip_length # 47 % 30 = 17
If your strip has 30 LEDs and position reaches 47, then 47 % 30 = 17 — the pixel appears at position 17 instead of past the end of the strip.
Now that you've seen every operator in action, here's a complete reference:
| Operator | Symbol | Example | Result | LED Use |
|---|---|---|---|---|
| Addition | + |
100 + 55 |
155 |
Increase a color channel |
| Subtraction | - |
255 - 50 |
205 |
Decrease brightness |
| Multiplication | * |
128 * 2 |
256 |
Scale a color value |
| Division | / |
255 / 2 |
127.5 |
Split brightness (float result) |
| Integer Division | // |
255 // 2 |
127 |
Split brightness (whole number) |
| Modulo | % |
47 % 30 |
17 |
Wrap pixel position around strip |
| Exponent | ** |
2 ** 8 |
256 |
Calculate bit-range sizes |
Comparison Operators
Comparison operators compare two values and always return a boolean — either True or False. Before looking at the table, note that the result is never a number: it's always one of those two words.
| Operator | Meaning | Example | Result |
|---|---|---|---|
== |
Equal to | 255 == 255 |
True |
!= |
Not equal to | 100 != 200 |
True |
< |
Less than | 50 < 100 |
True |
> |
Greater than | 200 > 255 |
False |
<= |
Less than or equal | 100 <= 100 |
True |
>= |
Greater than or equal | 200 >= 255 |
False |
Notice that == (two equals signs) tests whether two values are the same, while = (one equals sign) assigns a value. Mixing these up is one of the most common Python mistakes!
brightness = 200
print(brightness == 255) # False — not at maximum
print(brightness < 255) # True — below maximum brightness
Logical Operators
Logical operators combine booleans. You use them to check multiple conditions at the same time. There are three logical operators: and, or, and not.
Before seeing code, here's what each one means in plain English:
and— True only if both sides are Trueor— True if at least one side is Truenot— flips True to False, and False to True
button_pressed = True
strip_on = False
print(button_pressed and strip_on) # False — both must be True
print(button_pressed or strip_on) # True — at least one is True
print(not button_pressed) # False — flips True to False
Now let's try all three operator groups in a hands-on simulation:
Diagram: Python Operator Playground
Python Operator Playground
Type: microsim
sim-id: python-operator-playground
Library: p5.js
Status: Specified
Bloom Level: Apply (L3) Bloom Verb: calculate, use, demonstrate Learning Objective: Students apply Python's mathematical, comparison, and logical operators to LED-themed problems and observe the result of each expression.
Instructional Rationale: Apply (L3) calls for a parameter-exploration or interactive calculator pattern. Students select an operator, enter operands, and see the Python result alongside a plain-English LED interpretation. Prediction challenges are included so students commit to an answer before seeing the result — strengthening Apply-level encoding over purely passive observation.
Canvas layout:
- Top row: Three category tabs — Math | Comparison | Logic — active tab highlighted in blue
- Center panel: Left operand input, operator display (large, centered), right operand input
- Result panel: Shows the Python expression and its result (e.g., 47 % 30 = 17)
- LED Interpretation panel: Explains what this result means in an LED context
- Challenge panel: A pre-loaded challenge problem for the student to solve before revealing the answer
Visual elements: - Three tabs: styled as segmented control at top; active tab has solid blue background - Operand inputs: Large text fields (100px wide), border highlights on focus - Operator display: Large centered symbol (font-size 36px) in a rounded box between the operands - Result value: Large (font-size 48px), color-coded: blue for numbers, green for True, red for False - LED interpretation: Small text panel below result — e.g., "If your strip has 30 LEDs and a pixel is at position 47, it wraps to position 17"
Available operators: - Math tab (dropdown): +, -, *, /, //, %, ** - Comparison tab (dropdown): ==, !=, <, >, <=, >= - Logic tab: operands become True/False dropdowns; operator dropdown has: and, or, not (not uses only left operand)
Data Visibility Requirements:
Stage 1: Student selects a tab and operator
Stage 2: Student enters operand values (or selects True/False for Logic)
Stage 3: Result updates live as student types: show full expression 100 % 30 = 10
Stage 4: LED interpretation panel updates with a real NeoPixel context for this exact calculation
Challenge problems (pre-loaded, student must enter answer before "Reveal" button): - Math: "A strip has 30 LEDs. A pixel is at position 47. Where does it appear? Enter: 47 % 30" - Comparison: "Red channel = 128, Blue channel = 255. Is red brighter? Enter: 128 > 255" - Logic: "Button A is pressed (True). Button B is not pressed (False). Are BOTH pressed? Select: True and False"
Responsive design: Canvas fills container width; operator display and inputs scale with canvas width; tabs reflow to vertical on very narrow screens.
Import Statements and Modules
Python's built-in features are powerful, but sometimes you need extra tools. That's where modules come in.
A module is a collection of ready-made code that someone else wrote and packaged for you to use. Python's module system lets you load these tools into your program with a single line.
An import statement loads a module. The syntax is simple: import module_name. After importing, you access the module's functions and values using a dot (.):
import utime
utime.sleep(1) # Pause for 1 second — the utime module provides this
The four modules you'll use most in this course are:
import utime # Time tools: sleep(), ticks_ms()
import urandom # Random numbers: randint()
import neopixel # NeoPixel LED control: NeoPixel class
import machine # Hardware control: Pin, PWM, ADC
We also import a config module that stores your hardware settings — things like how many LEDs are on your strip:
import config
print(config.NUMBER_PIXELS) # e.g., 30 — how many LEDs
print(config.NEOPIXEL_PIN) # The GPIO pin the strip connects to
Here's a complete short program that uses imports to blink all LEDs red for one second:
import config
import neopixel
import utime
# Create the strip object
strip = neopixel.NeoPixel(config.NEOPIXEL_PIN, config.NUMBER_PIXELS)
# Turn all pixels red
for i in range(config.NUMBER_PIXELS):
strip[i] = (255, 0, 0)
strip.write() # Send color data to the LEDs
utime.sleep(1) # Wait 1 second
# Turn all pixels off
for i in range(config.NUMBER_PIXELS):
strip[i] = (0, 0, 0)
strip.write()
Every LED on your strip should flash red for one second, then turn off.
You've got this!
Imports might feel like magic at first — they're not. They're shortcuts! Instead of writing hundreds of lines of NeoPixel control code yourself, import neopixel gives you all of that for free. Programming is full of tools like this. Using them is smart, not lazy.
Code Indentation Rules
Python uses indentation — the spaces at the start of a line — to understand how code is organized. This is different from most other languages, which use curly braces { } for grouping.
A block is a group of lines that belong together. All lines in the same block must have the same amount of indentation. Lines outside the block return to a smaller indentation level.
Before seeing a code example, here are the two things Python checks:
- Every block must be indented the same amount as its peers
- Lines inside a block must be indented more than the line that opened the block
# CORRECT — lines inside the if block are indented 4 spaces
is_on = True
if is_on:
print("LED is on!") # 4 spaces — inside the if block
print("Glowing bright") # 4 spaces — still inside the block
print("Always runs") # 0 spaces — outside the if block
The standard is 4 spaces per indentation level. Thonny adds them automatically when you press Enter after if, for, while, or def. Do not mix tabs and spaces — Python treats them as different sizes and raises an error.
Here's what a wrong indentation looks like:
# WRONG — IndentationError!
is_on = True
if is_on:
print("LED is on!") # Missing indentation — Python won't run this
Try this in Thonny and you'll see IndentationError: expected an indented block. That error is Python's way of saying "I expected indented lines here."
Let's explore correct and incorrect indentation visually:
Diagram: Code Indentation Explorer
Code Indentation Explorer
Type: microsim
sim-id: code-indentation-explorer
Library: p5.js
Status: Specified
Bloom Level: Understand (L2) Bloom Verb: identify, interpret Learning Objective: Students identify which lines of a Python snippet are correctly indented, which have errors, and explain what block each line belongs to.
Instructional Rationale: Identify/interpret (L2 Understand) calls for a classify-and-explain pattern. The student clicks a line to see its block membership highlighted, then clicks "Check Indentation" to receive color-coded feedback on all lines simultaneously. Immediate feedback on individual lines before the whole-snippet check builds understanding step by step.
Canvas layout:
- Left panel (60%): A Python code snippet displayed in monospace font on a dark background (Thonny-like). Each line is a clickable row. Line numbers shown on the left margin.
- Right panel (40%): Feedback area showing:
- Block membership for the last clicked line: "This line is at indentation level 1 — inside the if block"
- After "Check Indentation": color-coded verdict for every line
Visual elements: - Code font: monospace, 14px, white on dark gray background - Block-level bracket overlays on left: vertical colored lines connecting lines that belong to the same block (level 0 = white, level 1 = blue, level 2 = orange) - Line highlights: green border = correct indentation, red border = error - Feedback panel: white background, plain text, 13px
Code examples (cycle with "Next Example" button, 4 examples total):
Example 1 (correct — single if block):
is_on = True
if is_on:
print("LED is on")
print("Glowing!")
print("Outside the if block")
Example 2 (error — missing indentation):
brightness = 100
if brightness > 50:
print("Bright!")
Example 3 (correct — nested blocks):
for i in range(30):
if i % 2 == 0:
print("Even pixel:", i)
print("Pixel:", i)
Example 4 (error — inconsistent indentation):
for i in range(5):
print(i)
print("extra spaces")
Interactive features: - Click any line → highlight that line, show block membership in right panel - "Check Indentation" button → color all lines green/red and show error explanations for bad lines - "Show Fix" button → reveal the corrected version side by side with the original - "Next Example" button → advance to the next code snippet
Responsive design: Panel layout is side-by-side on wide screens, stacks vertically on narrow screens. Font size scales down on narrow screens to keep line content visible.
Python Comments
A comment is a note inside your code that Python completely ignores. Comments are for humans — they help you (and your teammates) understand what code does and why.
You create a comment with the hash symbol #. Everything to the right of # on that line is ignored by Python:
# Set up the LED strip — this runs once when the program starts
import config
import neopixel
strip = neopixel.NeoPixel(config.NEOPIXEL_PIN, config.NUMBER_PIXELS)
strip[0] = (255, 0, 0) # Red: full red, no green or blue
strip.write() # Send the colors to the physical LEDs
The best comments explain why you made a choice — not what the code does (the code already shows that). Here's the difference:
# Not very helpful — just restates the code
red = 255 # Set red to 255
# More helpful — explains the reason
red = 255 # WS2812B max channel value; values above 255 are ignored
While you're learning, it's great to add "what" comments too. They help you trace your own thinking as you read back through your code.
Try It Yourself
Challenge 1 — Four Types: Create four variables, one of each type: an integer, a float, a string, and a boolean. Name each variable to describe an LED project property. Add a comment on each line. Then print all four variables.
Challenge 2 — Wrap the Pixel: A moving pixel starts at position 0 and jumps by 7 steps at a time. Your strip has 30 LEDs. Write a program that prints the pixel's position after each of 6 jumps — and wraps it around the strip using the modulo operator so it never goes past position 29.
# Starter code for Challenge 2
import config
strip_length = config.NUMBER_PIXELS # 30 LEDs
step_size = 7
position = 0
for step in range(6):
position = (position + step_size) % strip_length
print("Jump", step + 1, "→ position", position)
Run this and you should see six position values, all between 0 and 29.
Check Your Understanding
Answer these questions in your head first. Then check your answers below.
-
What is the difference between a list and a tuple? Why would you use a tuple for a color constant like
RED? -
A variable holds
speed = "2.5"as a string. You need it as a float for a calculation. What single function call converts it? -
Your strip has 25 LEDs. A position variable reaches
62. What does62 % 25equal? What does that tell you about where the pixel appears? -
What does
color == "red"do? What doescolor = "red"do? Why do these behave completely differently? -
Python finds an error in this code. What is the problem?
brightness = 100
if brightness > 50:
print("Bright!")
Show answers
-
A list uses
[ ]and can be changed after creation. A tuple uses( )and is unchangeable (immutable). Use a tuple for color constants likeRED = (255, 0, 0)because you don't want any part of your code accidentally changing the value ofRED. -
speed = float("2.5")— thefloat()function converts the string to the number2.5. -
62 % 25 = 12. The pixel appears at position 12. After dividing 62 by 25, you get 2 remainder 12 — so the pixel wraps to position 12 on the strip. -
color == "red"is a comparison — it checks ifcolorholds"red"and returnsTrueorFalse.color = "red"is an assignment — it stores the string"red"intocolor. Using=when you mean==(or vice versa) is one of the most common Python bugs! -
The
printline is missing indentation. It should be indented 4 spaces because it belongs inside theifblock. Python raises anIndentationErrorwhen a block opener likeifisn't followed by indented lines.
Chapter complete!
You did it! You now know the building blocks of every Python program — variables, six data types, operators, imports, indentation, and comments. Every LED animation you'll ever write uses exactly these tools. You're already glowing, coder. Now let's go make the LEDs glow too!
What's Next
In Chapter 3, you'll learn how to wrap code into reusable functions and discover the programming principles — like DRY ("Don't Repeat Yourself") — that make your programs cleaner and easier to build on.