Data Types and Variables

Introduction

Every piece of data in a program has a type. Understanding data types is fundamental - they determine what operations are valid, how data is stored in memory, and how much space it requires.

Learning Objectives

By the end of this reading, you will be able to:

  • Identify and use primitive data types
  • Declare and assign variables
  • Understand type systems (static vs dynamic)
  • Perform type conversions
  • Work with strings effectively

1. What are Data Types?

A data type defines:

  • What values a piece of data can hold
  • What operations can be performed on it
  • How it's represented in memory

Why Types Matter

# These look similar but behave differently
a = "5"      # String
b = 5        # Integer

print(a + a)  # "55" (string concatenation)
print(b + b)  # 10 (addition)

2. Primitive Data Types

Primitive types are the basic building blocks provided by a language.

Integers

Whole numbers (positive, negative, or zero).

age = 25
temperature = -10
count = 0

# Python has arbitrary precision integers
big_number = 12345678901234567890
print(big_number * 2)  # Works perfectly!

Common operations:

a = 10
b = 3

print(a + b)   # 13 (addition)
print(a - b)   # 7 (subtraction)
print(a * b)   # 30 (multiplication)
print(a / b)   # 3.333... (true division)
print(a // b)  # 3 (floor division)
print(a % b)   # 1 (modulo - remainder)
print(a ** b)  # 1000 (exponentiation)

Floating-Point Numbers

Numbers with decimal points.

pi = 3.14159
price = 19.99
scientific = 6.022e23  # 6.022 × 10²³

Important: Floating-point has precision limits!

print(0.1 + 0.2)  # 0.30000000000000004 (not exactly 0.3!)

# Why? Binary can't represent 0.1 exactly, just like
# decimal can't represent 1/3 exactly (0.333...)

# For money, use integers (cents) or Decimal
from decimal import Decimal
print(Decimal('0.1') + Decimal('0.2'))  # 0.3 (exact)

Booleans

True or False values.

is_student = True
is_employed = False

# Boolean operations
print(True and False)   # False
print(True or False)    # True
print(not True)         # False

# Comparison operators return booleans
print(5 > 3)    # True
print(5 == 5)   # True
print(5 != 3)   # True

None / Null

Represents the absence of a value.

result = None

if result is None:
    print("No result yet")

3. Strings

Strings are sequences of characters.

name = "Alice"
message = 'Hello, World!'
multiline = """This is a
multi-line string"""

# Empty string
empty = ""

String Operations

first = "Hello"
last = "World"

# Concatenation
full = first + " " + last    # "Hello World"

# Repetition
laugh = "ha" * 3             # "hahaha"

# Length
print(len(first))            # 5

# Indexing (0-based)
print(first[0])              # "H"
print(first[-1])             # "o" (last character)

# Slicing
print(first[1:4])            # "ell"
print(first[:3])             # "Hel" (first 3)
print(first[2:])             # "llo" (from index 2)

String Methods

text = "  Hello, World!  "

print(text.lower())          # "  hello, world!  "
print(text.upper())          # "  HELLO, WORLD!  "
print(text.strip())          # "Hello, World!" (remove whitespace)
print(text.replace("World", "Python"))  # "  Hello, Python!  "
print(text.split(","))       # ["  Hello", " World!  "]

# Checking content
print("Hello" in text)       # True
print(text.startswith("  H"))  # True
print(text.isdigit())        # False

String Formatting

name = "Alice"
age = 25

# f-strings (Python 3.6+, recommended)
message = f"My name is {name} and I am {age} years old"

# format method
message = "My name is {} and I am {} years old".format(name, age)

# % formatting (older style)
message = "My name is %s and I am %d years old" % (name, age)

# Formatting numbers
pi = 3.14159
print(f"Pi is approximately {pi:.2f}")  # "Pi is approximately 3.14"

price = 1234.5
print(f"Price: ${price:,.2f}")  # "Price: $1,234.50"

Strings are Immutable

s = "Hello"
# s[0] = "h"  # Error! Can't modify strings

# Create a new string instead
s = "h" + s[1:]  # "hello"

4. Variables

A variable is a named reference to a value stored in memory.

Declaration and Assignment

# Python infers the type
x = 10          # x is an integer
x = "hello"     # Now x is a string (Python allows this)

# Multiple assignment
a, b, c = 1, 2, 3

# Swap values
a, b = b, a

Naming Rules and Conventions

Rules (must follow):

  • Start with letter or underscore
  • Contain only letters, numbers, underscores
  • Case-sensitive (nameName)
  • Cannot be a reserved keyword

Conventions (should follow):

# Variables: snake_case
user_name = "alice"
total_count = 100

# Constants: UPPER_SNAKE_CASE
MAX_SIZE = 1000
PI = 3.14159

# Private (by convention): leading underscore
_internal_value = 42

# Avoid:
l = 1  # Looks like 1
O = 0  # Looks like 0

Scope

Variables have a scope - where they can be accessed.

global_var = "I'm global"

def my_function():
    local_var = "I'm local"
    print(global_var)   # Can access global
    print(local_var)    # Can access local

my_function()
print(global_var)       # Works
# print(local_var)      # Error! local_var doesn't exist here

5. Type Systems

Static vs Dynamic Typing

Static typing: Types checked at compile time

// Java (static)
int x = 5;
x = "hello";  // Compile error!

Dynamic typing: Types checked at runtime

# Python (dynamic)
x = 5
x = "hello"  # Fine! x is now a string

Strong vs Weak Typing

Strong typing: Limited implicit conversions

# Python is strongly typed
x = "5" + 3  # Error! Can't add string and int

Weak typing: More implicit conversions

// JavaScript is weakly typed
x = "5" + 3  // "53" (3 becomes "3")

Type Hints in Python

Python 3.5+ supports optional type hints:

def greet(name: str) -> str:
    return f"Hello, {name}"

age: int = 25
names: list[str] = ["Alice", "Bob"]

Type hints are not enforced at runtime but help with documentation and can be checked with tools like mypy.


6. Type Conversion

Implicit Conversion

Python automatically converts in some cases:

x = 5       # int
y = 2.0     # float
z = x + y   # 7.0 (int promoted to float)

Explicit Conversion (Casting)

# To integer
int("42")       # 42
int(3.7)        # 3 (truncates, doesn't round)
int("3.7")      # Error! Can't parse directly

# To float
float("3.14")   # 3.14
float(42)       # 42.0

# To string
str(42)         # "42"
str(3.14)       # "3.14"
str(True)       # "True"

# To boolean
bool(0)         # False
bool(42)        # True (any non-zero is True)
bool("")        # False (empty string)
bool("hello")   # True (non-empty string)
bool([])        # False (empty list)
bool([1,2])     # True (non-empty list)

7. Composite Types Preview

Beyond primitives, languages offer ways to group data:

Lists (Arrays)

Ordered, mutable collections:

numbers = [1, 2, 3, 4, 5]
mixed = [1, "hello", 3.14, True]

print(numbers[0])      # 1
numbers.append(6)      # [1, 2, 3, 4, 5, 6]
numbers[0] = 10        # [10, 2, 3, 4, 5, 6]

Tuples

Ordered, immutable collections:

point = (3, 4)
rgb = (255, 128, 0)

x, y = point           # Unpacking
# point[0] = 5         # Error! Tuples are immutable

Dictionaries (Maps)

Key-value pairs:

person = {
    "name": "Alice",
    "age": 25,
    "city": "Boston"
}

print(person["name"])  # "Alice"
person["age"] = 26     # Update value
person["job"] = "Engineer"  # Add new key

Sets

Unordered collections of unique elements:

numbers = {1, 2, 3, 2, 1}  # {1, 2, 3}
print(2 in numbers)        # True

a = {1, 2, 3}
b = {2, 3, 4}
print(a | b)  # Union: {1, 2, 3, 4}
print(a & b)  # Intersection: {2, 3}

8. Memory and References

How Variables Work

Variables in Python are references to objects in memory:

a = [1, 2, 3]
b = a          # b refers to the SAME list

b.append(4)
print(a)       # [1, 2, 3, 4] - a is affected!

# To make a copy:
c = a.copy()   # or list(a) or a[:]
c.append(5)
print(a)       # [1, 2, 3, 4] - a is NOT affected

Identity vs Equality

a = [1, 2, 3]
b = [1, 2, 3]
c = a

print(a == b)  # True (same value)
print(a is b)  # False (different objects)
print(a is c)  # True (same object)

# id() shows memory address
print(id(a))   # e.g., 140234567890
print(id(c))   # Same as above
print(id(b))   # Different

Small Integer Caching

Python caches small integers (-5 to 256):

a = 100
b = 100
print(a is b)  # True (same cached object)

a = 1000
b = 1000
print(a is b)  # False (different objects)

Exercises

Basic

  1. What is the type of each variable?
a = 42
b = 3.14
c = "hello"
d = True
e = None
f = [1, 2, 3]
  1. What does each expression evaluate to?
10 + 3
10 - 3
10 * 3
10 / 3
10 // 3
10 % 3
10 ** 3
  1. Fix the errors:
print("The answer is " + 42)
name = "Alice
age = twenty-five

Intermediate

  1. Write code that:

    • Takes a temperature in Celsius
    • Converts it to Fahrenheit: F = C × 9/5 + 32
    • Prints the result formatted to 1 decimal place
  2. What happens with each conversion? Predict, then test:

int(3.9)
int("3.9")
float("hello")
bool([])
bool([0])
str([1, 2, 3])
  1. Explain why this happens:
a = [1, 2, 3]
b = a
b.append(4)
print(a)  # What prints?

Advanced

  1. Research: What is the largest integer Python can handle? What about floats?

  2. Investigate floating-point issues:

# Why do these give different results?
sum([0.1] * 10)
0.1 * 10
  1. Create a simple program that:
    • Stores person data in a dictionary
    • Has at least 4 fields (name, age, height, is_student)
    • Prints a formatted summary

Summary

  • Data types determine what values and operations are valid
  • Primitive types: integers, floats, booleans, None
  • Strings are immutable sequences of characters
  • Variables are references to values in memory
  • Python is dynamically typed (types checked at runtime)
  • Python is strongly typed (limited implicit conversions)
  • Use explicit conversion (casting) when needed
  • Collections (lists, tuples, dicts, sets) group data together

Next Reading

Control Structures →