The Story That Explains Python Syntax
Programming is identical. Every language has a syntax — a rigid set of grammar rules the computer enforces. Write the rules correctly and the computer does exactly what you ask. Break one rule — a missing colon, a wrong indent — and the computer refuses to continue. It shows you an error message (like the waiter's blank stare) and waits until you fix it.
The good news? Python's grammar is the simplest of any major language. If English is your first spoken language, Python syntax will feel almost natural.
Syntax is the set of rules that defines how Python code must be written so the interpreter can understand and execute it. It covers everything — how you name things, how you end statements, how you group code into blocks, and how you write expressions. Python was designed to have minimal, clean syntax that reads like pseudocode.
In C++ or Java, you fight the language — semicolons, braces, verbose type declarations. In Python, the syntax gets out of your way so you can focus on solving the problem. This is why beginners learn faster, teams ship faster, and Python dominates in education, data science, and AI.
Python Syntax — The Five Foundational Rules
Master these five rules and you'll understand 90% of all Python code you ever read. Everything else builds on top of these fundamentals.
Indentation — Python's Defining Feature
This is the single most important syntax rule in Python. In every other major language, indentation is cosmetic — it makes code pretty but doesn't affect execution. In Python, indentation defines the structure of your program.
| Line | Code |
|---|---|
| 1 | age = 20 |
| 2 | if age >= 18: |
| 3 | print("Adult") |
| 4 | print("Can vote") |
| 5 | print("Done") |
| Line | Code |
|---|---|
| 1 | age = 20 |
| 2 | if age >= 18: |
| 3 | print("Adult") ← no indent! |
| 4 | print("Can vote") ← 2 spaces! |
| 5 | print("Done") ← 6 spaces! |
# CORRECT — consistent 4-space indentation
if temperature > 30:
print("It's hot outside")
print("Stay hydrated")
else:
print("Weather is fine")
# WRONG — this will crash with IndentationError
if temperature > 30:
print("It's hot outside") # IndentationError: expected an indented block
Always use 4 spaces. Never use tabs. Mixing tabs and spaces causes TabError — one of the most frustrating bugs for beginners because tabs and spaces look identical. Every modern editor (VS Code, PyCharm) converts Tab key presses into 4 spaces automatically. Enable this setting immediately.
Comments and Docstrings
Comments are notes you leave for yourself and other developers. Python completely ignores them during execution. They exist solely for human readers.
# ─── SINGLE-LINE COMMENTS ───────────────────────────────
# This is a comment — Python skips this entire line
x = 42 # Inline comment — after the code on the same line
# ─── MULTI-LINE COMMENTS ────────────────────────────────
# Python has no official multi-line comment syntax.
# Convention: use multiple single-line comments like this.
# Each line starts with #
# ─── DOCSTRINGS (Documentation Strings) ─────────────────
# Triple-quoted strings used as the first line of a
# function, class, or module. These ARE accessible at runtime.
def greet(name):
"""Return a personalised greeting message.
Args:
name (str): The person's name.
Returns:
str: A greeting like 'Hello, Alice!'
"""
return f"Hello, {name}!"
# Access the docstring at runtime
print(greet.__doc__)
Don't write "what" the code does — the code already shows that.
Write "why" the code exists.
Bad: # increment x by 1 → obvious from the code
Good: # compensate for zero-indexed array → explains intent
Variables — Labelled Boxes for Your Data
A variable is a labelled box in your computer's memory. The label is the variable name, and the item inside is the value. You can put anything inside (a number, a word, a list), change the contents at any time, and access it instantly using the label.
The critical difference: in Python, the label is a sticky note attached to the object, not a physical box. Multiple labels (variables) can point to the same object. This is a subtle but powerful concept that matters as you advance.
Creating Variables — No Declaration Needed
In C++ or Java, you must declare a variable with a type before using it: int age = 25;. Python skips all of that. You just assign a value and the variable springs into existence.
# Creating variables — just assign a value
name = "Alice" # str (string)
age = 30 # int (integer)
height = 5.7 # float (decimal number)
is_student = False # bool (boolean)
# Python figures out the type automatically
print(type(name)) # <class 'str'>
print(type(age)) # <class 'int'>
print(type(height)) # <class 'float'>
print(type(is_student)) # <class 'bool'>
# You can change a variable's value AND type anytime
x = 10 # x is an integer
x = "ten" # now x is a string — perfectly legal!
x = [1, 2, 3] # now x is a list
Variable Naming Rules and Conventions
Python has strict rules (break them and the code crashes) and conventions (break them and other developers judge you). Both matter.
| Rule | Valid Examples | Invalid Examples | Why |
|---|---|---|---|
| Must start with a letter or underscore | name, _count, age2 | 2name, @email | Numbers and symbols can't start a name |
| Can contain letters, digits, underscores only | first_name, item3 | first-name, item#3 | Hyphens and special chars are operators |
| Cannot be a keyword | my_class, for_loop | class, for, if | Python reserves 35 keywords |
| Case-sensitive | Name ≠ name ≠ NAME | — | All three are different variables |
| No length limit | total_monthly_revenue | — | Be descriptive, but not absurd |
PEP 8 Naming Conventions
Python has built-in names like list, str, int, type, id, input, print. If you write list = [1, 2, 3], you overwrite the built-in list() function and it stops working for the rest of your program. Use names like my_list or items instead.
Multiple Assignment and Swapping
Python offers elegant shorthand for assigning variables that would take multiple lines in most other languages.
# ─── MULTIPLE ASSIGNMENT (one line) ─────────────────────
x, y, z = 10, 20, 30
print(x, y, z) # 10 20 30
# ─── SAME VALUE TO MULTIPLE VARIABLES ───────────────────
a = b = c = 0
print(a, b, c) # 0 0 0
# ─── VARIABLE SWAPPING (Python magic) ───────────────────
# In other languages: you need a temp variable
# temp = a; a = b; b = temp
# In Python: one beautiful line
a, b = 5, 10
a, b = b, a # swap!
print(a, b) # 10 5
# ─── UNPACKING FROM A LIST ──────────────────────────────
coordinates = [40.7128, -74.0060]
latitude, longitude = coordinates
print(f"Lat: {latitude}, Lon: {longitude}")
Data Types — The Four Fundamental Types
Each container is designed for a specific kind of thing. You can't pour water into a safe, and you can't file a gold bar. Similarly, Python's data types determine what operations are legal — you can multiply two numbers but you can't multiply two sentences (well, not in the mathematical sense).
Python has four primitive (scalar) data types that form the foundation of all other types. Every piece of data in a Python program ultimately reduces to one of these.
int — Integers (Whole Numbers)
Integers are exact, unlimited in size, and the most commonly used numeric type. Unlike C or Java where integers overflow at 231, Python integers can be arbitrarily large — limited only by your computer's memory.
# ─── CREATING INTEGERS ──────────────────────────────────
age = 25
temperature = -7
population = 8_000_000_000 # underscores for readability (Python 3.6+)
big_number = 10 ** 100 # 1 followed by 100 zeros — no problem!
print(type(age)) # <class 'int'>
print(population) # 8000000000
print(len(str(big_number))) # 101 digits — Python handles it easily
# ─── INTEGER OPERATIONS ─────────────────────────────────
a, b = 17, 5
print(a + b) # 22 Addition
print(a - b) # 12 Subtraction
print(a * b) # 85 Multiplication
print(a / b) # 3.4 Division (ALWAYS returns float!)
print(a // b) # 3 Floor division (integer result)
print(a % b) # 2 Modulo (remainder)
print(a ** b) # 1419857 Exponentiation (17^5)
# ─── DIFFERENT NUMBER BASES ──────────────────────────────
binary = 0b1010 # Binary → 10
octal = 0o17 # Octal → 15
hexa = 0xFF # Hex → 255
print(binary, octal, hexa)
In Python 3, the / operator always returns a float, even when dividing two integers that divide evenly: 10 / 2 returns 5.0, not 5. If you need an integer result, use floor division //. This catches many beginners off guard.
float — Floating-Point Numbers (Decimals)
Floats represent real numbers with decimal points. They use 64-bit double-precision internally (same as double in C/Java), giving approximately 15–17 significant digits of precision.
# ─── CREATING FLOATS ────────────────────────────────────
price = 19.99
pi = 3.14159265358979
negative = -0.5
tiny = 1e-8 # Scientific notation → 0.00000001
huge = 6.022e23 # Avogadro's number → 6.022 × 10²³
from_int = float(7) # Convert int to float → 7.0
print(type(price)) # <class 'float'>
print(tiny) # 1e-08
print(from_int) # 7.0
# ─── FLOAT ARITHMETIC ───────────────────────────────────
print(0.1 + 0.2) # 0.30000000000000004 ← NOT 0.3!
print(round(0.1 + 0.2, 1)) # 0.3 ← round() fixes it
# ─── SPECIAL FLOAT VALUES ───────────────────────────────
infinity = float("inf")
neg_infinity = float("-inf")
not_a_number = float("nan")
print(infinity > 999999999) # True
print(not_a_number == not_a_number) # False (NaN ≠ anything, even itself!)
0.1 + 0.2 ≠ 0.3 in virtually every programming language (JavaScript, Java, C, Rust — all of them). This happens because computers store numbers in binary, and 0.1 cannot be represented exactly in binary — just like 1/3 can't be written exactly in decimal (0.333...). For financial calculations, use the decimal module instead: from decimal import Decimal.
int vs float — Quick Comparison
| Property | int | float |
|---|---|---|
| Decimal point | No | Yes, always |
| Precision | Exact (unlimited size) | ~15 digits (can have rounding errors) |
| Memory | Variable (grows with number size) | Fixed 8 bytes (64 bits) |
| Division result | / returns float; // returns int | Both / and // return float |
| Use case | Counting, indexing, IDs, exact values | Measurements, science, percentages |
| Example | 42, -7, 1_000_000 | 3.14, -0.5, 2.5e10 |
str — Strings (Text Data)
Strings are sequences of characters. They are immutable — once created, you cannot change a character inside a string. Any "modification" creates a brand-new string. Strings are the data type you will use most often.
Creating Strings — Four Ways
# ─── SINGLE QUOTES ──────────────────────────────────────
msg1 = 'Hello, World!'
# ─── DOUBLE QUOTES ──────────────────────────────────────
msg2 = "Hello, World!" # identical to single quotes
# ─── TRIPLE QUOTES (multi-line strings) ─────────────────
poem = """Roses are red,
Violets are blue,
Python is awesome,
And so are you."""
# ─── RAW STRINGS (ignore escape characters) ────────────
path = r"C:\Users\new_folder\test" # backslashes treated literally
print(msg1)
print(poem)
print(path)
String Operations — The Essential Toolkit
# ─── CONCATENATION (joining) ────────────────────────────
first = "Hello"
last = "World"
full = first + " " + last # "Hello World"
# ─── REPETITION ─────────────────────────────────────────
line = "─" * 40 # creates a 40-character line
# ─── LENGTH ─────────────────────────────────────────────
print(len("Python")) # 6
# ─── INDEXING (zero-based!) ─────────────────────────────
word = "Python"
print(word[0]) # P (first character)
print(word[-1]) # n (last character)
print(word[2:5]) # tho (characters 2, 3, 4)
# ─── ESSENTIAL METHODS ──────────────────────────────────
text = " Hello, Python World! "
print(text.strip()) # "Hello, Python World!" (remove whitespace)
print(text.lower()) # " hello, python world! "
print(text.upper()) # " HELLO, PYTHON WORLD! "
print(text.replace("Python", "Coding")) # " Hello, Coding World! "
print(text.split(",")) # [' Hello', ' Python World! ']
print("Python" in text) # True (membership check)
print(text.count("o")) # 2
print(text.startswith(" H")) # True
f-Strings — The Modern Way to Format Strings
Introduced in Python 3.6, f-strings are the fastest, cleanest, and most readable way to embed variables and expressions inside strings.
# ─── F-STRINGS (formatted string literals) ──────────────
name = "Alice"
age = 30
salary = 75000.50
# Basic variable insertion
print(f"Name: {name}, Age: {age}")
# Expressions inside f-strings
print(f"In 5 years: {age + 5}")
print(f"Uppercase: {name.upper()}")
# Number formatting
print(f"Salary: ${salary:,.2f}") # $75,000.50
print(f"Percentage: {0.856:.1%}") # 85.6%
print(f"Binary of 10: {10:b}") # 1010
print(f"Padded: {age:05d}") # 00030
print(f"Left align: {'hi':<10}|") # "hi |"
print(f"Right align: {'hi':>10}|") # " hi|"
print(f"Center: {'hi':^10}|") # " hi |"
Python has three string formatting methods: % formatting (old), .format() (Python 2/3), and f-strings (Python 3.6+). Always use f-strings — they're faster, more readable, and more powerful. The older methods still work but are considered legacy.
Escape Characters
| Escape | Meaning | Example | Output |
|---|---|---|---|
| \n | New line | "Line1\nLine2" | Line1 Line2 |
| \t | Tab | "Col1\tCol2" | Col1 Col2 |
| \\ | Backslash | "C:\\Users" | C:\Users |
| \' | Single quote | 'It\'s fine' | It's fine |
| \" | Double quote | "He said \"hi\"" | He said "hi" |
bool — Booleans (True or False)
Booleans are the simplest data type — they have only two possible values: True and False (capitalised — this is mandatory). Every if statement, every while loop, and every comparison in Python ultimately evaluates to a boolean.
# ─── CREATING BOOLEANS ──────────────────────────────────
is_active = True
is_deleted = False
print(type(is_active)) # <class 'bool'>
# ─── BOOLEANS FROM COMPARISONS ──────────────────────────
print(10 > 5) # True
print(10 == 5) # False
print(10 != 5) # True
print(10 >= 10) # True
print("abc" == "ABC") # False (case-sensitive!)
# ─── LOGICAL OPERATORS ──────────────────────────────────
x = 15
print(x > 10 and x < 20) # True (both conditions true)
print(x > 10 or x > 100) # True (at least one true)
print(not (x > 10)) # False (inverts True → False)
# ─── BOOL IS A SUBCLASS OF INT ──────────────────────────
print(True + True) # 2 (True = 1, False = 0)
print(True * 10) # 10
print(False + 7) # 7
# Useful trick: count True values in a list
scores = [85, 42, 91, 58, 73, 95]
passed = sum(s >= 60 for s in scores)
print(f"Students passed: {passed}/{len(scores)}")
Truthy and Falsy Values
Every value in Python can be evaluated as a boolean. Python considers certain values "falsy" (treated as False) and everything else is "truthy" (treated as True).
| Value | Type |
|---|---|
| False | bool |
| None | NoneType |
| 0 | int |
| 0.0 | float |
| "" (empty string) | str |
| [] (empty list) | list |
| {} (empty dict) | dict |
| () (empty tuple) | tuple |
| Value | Why |
|---|---|
| True | The boolean itself |
| 42, -1 | Any non-zero number |
| 3.14 | Any non-zero float |
| "hello" | Any non-empty string |
| [1, 2] | Any non-empty list |
| {"a": 1} | Any non-empty dict |
| Any object | Custom objects default to truthy |
# ─── TRUTHY / FALSY IN ACTION ───────────────────────────
username = ""
if username:
print(f"Welcome, {username}")
else:
print("No username provided") # This runs — empty string is falsy
# Common pattern: default values
name = ""
display_name = name or "Anonymous"
print(display_name) # "Anonymous"
# Check if a list has items
items = []
if not items:
print("Cart is empty") # This runs — empty list is falsy
Type Conversion (Casting)
Python lets you convert between data types using built-in functions. This is called type casting. It's essential when reading user input (which is always a string) or mixing types in calculations.
# ─── PRACTICAL TYPE CONVERSION ──────────────────────────
# User input is ALWAYS a string — you must convert it
age_str = input("Enter your age: ") # Returns "25" (string)
age = int(age_str) # Now it's 25 (integer)
print(f"Next year you'll be {age + 1}")
# Common conversions
print(int("100")) # 100
print(int(9.99)) # 9 (truncates toward zero)
print(float("3.14")) # 3.14
print(str(42) + " cats") # "42 cats"
print(bool(0)) # False
print(bool("hello")) # True
# ─── DANGEROUS CONVERSIONS (these crash!) ───────────────
# int("hello") → ValueError: invalid literal
# int("3.14") → ValueError: can't convert decimal string directly
# int("") → ValueError: empty string
# Safe approach: use int(float("3.14")) for decimal strings
print(int(float("3.14"))) # 3 (works!)
type() and isinstance() — Checking Types
Python provides two ways to inspect data types at runtime. Understanding the difference between them is important for writing robust code.
# ─── type() — returns the exact type ────────────────────
print(type(42)) # <class 'int'>
print(type(3.14)) # <class 'float'>
print(type("hello")) # <class 'str'>
print(type(True)) # <class 'bool'>
# Comparing types
x = 42
print(type(x) == int) # True
print(type(x) == str) # False
# ─── isinstance() — checks type AND inheritance ────────
print(isinstance(42, int)) # True
print(isinstance(True, int)) # True! (bool is subclass of int)
print(isinstance(True, bool)) # True
# Check multiple types at once
print(isinstance(3.14, (int, float))) # True (is it int OR float?)
# ─── PRACTICAL USE ──────────────────────────────────────
def double(value):
"""Double a number, but reject non-numeric input."""
if not isinstance(value, (int, float)):
raise TypeError(f"Expected a number, got {type(value).__name__}")
return value * 2
print(double(21)) # 42
print(double(3.5)) # 7.0
Use isinstance() in production code — it respects inheritance and handles multiple types cleanly. Use type() for debugging and learning, when you need to see the exact type. The reason: type(True) == int returns False, but isinstance(True, int) returns True (because bool inherits from int).
Complete Cheat Sheet — All Four Types at a Glance
| Property | int | float | str | bool |
|---|---|---|---|---|
| Example | 42 | 3.14 | "hello" | True |
| Mutable? | No | No | No | No |
| Size limit | Unlimited | ~15 digits | Unlimited | 1 bit (True/False) |
| Falsy value | 0 | 0.0 | "" | False |
| Convert with | int() | float() | str() | bool() |
| Check with | isinstance(x, int) | isinstance(x, float) | isinstance(x, str) | isinstance(x, bool) |
| Common ops | + - * / // % ** | + - * / round() | + * [] in split() join() | and or not |
| Main use | Counting, indexing | Measurements, science | Text, messages, labels | Conditions, flags |
Complete Practice Program
This program combines every concept from this tutorial — syntax rules, variables, all four data types, f-strings, type conversion, and boolean logic — into a single working script you can run immediately.
# student_report.py — Combines syntax, variables, and all 4 data types
# Run: python3 student_report.py
def get_grade(score):
"""Convert a numeric score to a letter grade."""
if score >= 90:
return "A"
elif score >= 80:
return "B"
elif score >= 70:
return "C"
elif score >= 60:
return "D"
else:
return "F"
def main():
# ─── str: student name ──────────────────────────────
name = "Alice Johnson"
# ─── int: student ID and scores ─────────────────────
student_id = 2024_001
scores = [88, 92, 75, 95, 83]
# ─── float: calculated average ─────────────────────
average = sum(scores) / len(scores)
# ─── bool: pass/fail status ───────────────────────
passed = average >= 60.0
honour_roll = average >= 85.0
# ─── Build report using f-strings ──────────────────
separator = "═" * 40
print(separator)
print(f" STUDENT REPORT CARD")
print(separator)
print(f" Name: {name}") # str
print(f" ID: {student_id}") # int
print(f" Subjects: {len(scores)}") # int from len()
print(separator)
# Display individual scores
subjects = ["Maths", "Science", "English", "History", "Art"]
for subject, score in zip(subjects, scores):
grade = get_grade(score)
status = "✓" if score >= 60 else "✗" # bool → ternary
print(f" {subject:<10} {score:>3} ({grade}) {status}")
print(separator)
print(f" Average: {average:.1f}") # float formatted
print(f" Grade: {get_grade(average)}")
print(f" Passed: {passed}") # bool
print(f" Honour Roll: {honour_roll}") # bool
print(separator)
# Type check summary
print(f"\n Type of name: {type(name).__name__}")
print(f" Type of ID: {type(student_id).__name__}")
print(f" Type of average: {type(average).__name__}")
print(f" Type of passed: {type(passed).__name__}")
if __name__ == "__main__":
main()