Python Basics — Syntax and Fundamentals
Below is a thorough, professional, and practical explanation of each topic you listed. Each section includes definitions, rules, examples, common pitfalls, and short best-practice notes. At the end you’ll find a set of basic coding exercises with hints and example solutions.
1. Understanding indentation and code blocks
What it is
Indentation is the whitespace (spaces or tabs) at the start of a line. In Python, indentation defines code blocks — the grouping of statements that belong together (for example, the body of a function, loop, conditional branch, etc.). Unlike many other languages that use braces {} to delimit blocks, Python relies on consistent indentation.
Rules
- Indentation must be consistent within the same block.
 - The standard convention is 4 spaces per indentation level (PEP 8).
 - Never mix tabs and spaces in the same project (can lead to TabError).
 - A new block is started after a colon : (e.g., if, for, def, class, while, try, with).
 
Example
if x > 0:
    print("positive")
    y = x * 2
else:
    print("non-positive")
    y = 0
Pitfalls
- Inconsistent indentation raises IndentationError or TabError.
 - Relying on visual alignment (with tabs/spaces mixed) can break code in other editors.
 
Best practice
- Configure your editor to insert 4 spaces on Tab.
 - Use a linter or formatter (e.g., flake8, black) to enforce consistency.
 
2. Comments (single-line and multi-line)
Purpose
Comments are for explaining code to human readers — they are ignored by the interpreter.
Single-line comments
- Start with #. Use them for short notes or to temporarily disable a line.
 
# This is a single-line comment
x = 5  # Inline comment: value of x
Multi-line comments / Block comments
- Python has no dedicated multi-line comment token, but multi-line strings (triple quotes) are often used as block comments. Note: if a triple-quoted string is not assigned to a variable or used as a docstring, it becomes a no-op expression but still parsed.
 
"""
This is a string literal that can be used like a
multi-line comment, though it's actually a string.
"""
- For module, class, and function documentation, use docstrings (triple-quoted strings placed immediately after the definition). Tools like help() and documentation generators read docstrings.
 
def add(a, b):
    """Return the sum of a and b."""
    return a + b
Best practice
- Use # for short comments and docstrings for API documentation.
 - Keep comments concise and meaningful; avoid stating the obvious.
 
3. Variables and identifiers
Variables
- Containers that hold references to objects. Python variables are dynamically typed: a variable can hold values of any type at different times.
 
x = 10
x = "hello"  # now x refers to a string
Identifiers
- Names used for variables, functions, classes, modules, etc.
 - Rules for valid identifiers:
- Can contain letters (A–Z, a–z), digits (0–9), and underscores _.
 - Must not start with a digit.
 - Case-sensitive (Value ≠ value).
 - Cannot be a reserved keyword (e.g., for, if).
 
 
Naming conventions (PEP 8)
- snake_case for variables and functions: user_name.
 - PascalCase (CapWords) for classes: CustomerAccount.
 - Constants (module-level) in UPPER_SNAKE_CASE: MAX_RETRIES.
 
Example
user_age = 30
_user_count = 5    # allowed, starts with underscore
Best practice
- Choose clear, descriptive names.
 - Avoid single-letter names except in small scopes (e.g., i in loops).
 
4. Keywords in Python
What they are
Keywords are reserved words that have a special meaning in the language syntax. They cannot be used as identifiers.
Common keywords (not exhaustive)
False, None, True, and, as, assert, break, class, continue, def, del, elif, else, except, finally, for, from, global, if, import, in, is, lambda, nonlocal, not, or, pass, raise, return, try, while, with, yield
How to see the full list
import keyword
print(keyword.kwlist)
Best practice
- Learn the most-used keywords (def, class, if, for, while, try/except, with, lambda, return).
 
5. Data types overview
Python's type system
Python has built-in (primitive and composite) types and allows creation of user-defined types (classes). Types are objects; every value has a type.
Core built-in types
Numbers
int — arbitrary-precision integers.
a = 42float — double-precision floating point.
b = 3.14complex — complex numbers with a + bj.
c = 1 + 2j
Boolean
bool — True or False. Subclass of int.
is_valid = True
Strings
str — immutable sequence of Unicode characters.
s = "Hello, world"- Single, double, or triple quotes allowed. Triple-quoted strings support multi-line text.
 
Bytes and bytearray
- bytes — immutable sequence of bytes.
 - bytearray — mutable sequence of bytes.
 
b = b'hello'
ba = bytearray(b'hello')
Sequence types
- list — ordered, mutable collection: [].
 - tuple — ordered, immutable collection: ().
 - range — represents a sequence of numbers, typically used in loops.
 
Mapping
- dict — key-value store (hash map). Keys must be hashable.
 
Set types
- set — unordered collection of unique elements (mutable).
 - frozenset — immutable version.
 
NoneType
- None is a singleton used to denote “no value” or “missing”.
 
Example
numbers = [1, 2, 3]      # list
pair = (1, 'a')          # tuple
config = {'host': 'x'}   # dict
Type inspection
- type(obj) returns the type.
 - isinstance(obj, Type) is preferred for type checks.
 
Best practice
- Prefer isinstance() over type() checks when checking for inheritance.
 - Use immutable types for keys in dicts (str, int, tuple of immutables).
 
6. Type casting and conversion
What it is
Type casting converts a value from one type to another. Python provides built-in conversion functions.
Common conversions
- int(x) — to integer (may raise ValueError).
 - float(x) — to float.
 - str(x) — to string.
 - bool(x) — to boolean (empty containers → False, non-zero numbers → True).
 - list(iterable), tuple(iterable), set(iterable), dict(mapping_or_iterable).
 
Examples
int("42")    # 42
float("3.14")  # 3.14
str(100)     # "100"
bool(0)      # False
bool([1,2])  # True
Notes and pitfalls
- int("3.14") raises a ValueError. Convert via float first: int(float("3.14")).
 - Converting floats to ints truncates toward zero (not rounding): int(3.9) == 3.
 - bool("False") is True because non-empty strings are truthy.
 
Best practice
- Validate or catch exceptions when converting user input.
 - Be explicit and document conversions to avoid subtle bugs.
 
7. Taking user input
Built-in function
- input(prompt) reads a line from standard input as a string. It returns str.
 
Example
name = input("Enter your name: ")
age_str = input("Enter your age: ")
age = int(age_str)  # convert input to integer (handle errors)
Important points
- input() always returns a string; cast as needed.
 - Use try/except to handle invalid conversions.
 
Example with validation
while True:
    age_str = input("Enter age: ")
    try:
        age = int(age_str)
        break
    except ValueError:
        print("Please enter a valid integer.")
Note for non-interactive contexts
- For scripts meant to run unattended, prefer command-line arguments (via argparse) instead of input().
 
8. Output formatting using print() and f-strings
print() basics
- print() writes to standard output and adds a newline by default.
 - Parameters: print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
 
Examples
print("Hello", "World")           # "Hello World"
print("No newline", end='')       # no trailing newline
print("A", "B", sep='-')          # "A-B"
Old-style formatting (%)
name = "Alice"
print("Hello, %s. You are %d." % (name, 30))
The str.format() Method
The str.format() method is a built-in Python feature that allows you to insert values into strings using placeholders ({}) inside the string.
It was introduced in Python 2.6 and 3.0 as a more powerful and flexible alternative to the older % string formatting style.
It works by calling the .format() method on a string, where each {} placeholder is replaced by the corresponding value passed into the method.
Basic Syntax
"{}".format(value)
or for multiple values:
"{} {}".format(value1, value2)
Example:
name = "Alice"
age = 25
print("My name is {} and I am {} years old.".format(name, age))
Output:
My name is Alice and I am 25 years old.
Here, each {} acts as a placeholder that gets replaced with the arguments provided to .format().
Positional and Keyword Arguments
You can use both positional and keyword arguments inside the placeholders for more control.
Positional Example:
print("Hello {0}, you are {1} years old.".format("Alice", 25))
Keyword Example:
print("Hello {name}, you are {age} years old.".format(name="Alice", age=25))
Output (both):
Hello Alice, you are 25 years old.
This flexibility makes it easy to reuse or rearrange values without repeating them in the argument list.
Referencing Variables or Attributes
You can also reference elements of lists, dictionaries, or object attributes directly in placeholders.
Dictionary Example:
person = {"name": "Alice", "age": 25}
print("Name: {0[name]}, Age: {0[age]}".format(person))
Object Example:
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
p = Person("Bob", 30)
print("Name: {0.name}, Age: {0.age}".format(p))
Output:
Name: Alice, Age: 25
Name: Bob, Age: 30
Formatting Numbers and Alignment
The .format() method also supports powerful format specifiers to control number formatting, alignment, padding, precision, and more — using a colon : after the placeholder.
Examples:
# Floating-point precision
print("Pi is approximately {:.2f}".format(3.14159))   # 2 decimal places
# Padding and alignment
print("Left aligned: {:<10}".format("Hi"))
print("Right aligned: {:>10}".format("Hi"))
print("Centered: {:^10}".format("Hi"))
Output:
Pi is approximately 3.14
Left aligned: Hi        
Right aligned:         Hi
Centered:     Hi     
Combining Text and Formatting
You can include both literal text and format instructions together easily.
price = 49.99
print("The price is ${:.2f}".format(price))
Output:
The price is $49.99
Advantages of str.format()
- More readable and flexible than old % formatting.
 - Supports positional, keyword, and object formatting.
 - Allows complex formatting rules (precision, width, alignment).
 - Works with all Python data types (strings, numbers, objects, etc.).
 
Limitations Compared to f-Strings
While .format() was a major improvement over % formatting, it’s now largely replaced by f-strings (Python 3.6+).
f-strings are preferred because:
- They are shorter and cleaner — you can embed variables directly inside strings.
 - They are faster — evaluated at runtime.
 - They can evaluate expressions inline (e.g., {x * y}).
 
For example:
name = "Alice"
age = 25
# Using format()
print("My name is {} and I am {} years old.".format(name, age))
# Using f-string
print(f"My name is {name} and I am {age} years old.")
Both produce the same output, but the f-string version is more readable
 
f-strings (formatted string literals) — recommended (Python 3.6+)
f-strings, introduced in Python 3.6, are a modern and highly readable way to embed expressions directly inside string literals. They make string formatting concise, expressive, and efficient.
What are f-Strings?
An f-string is simply a string prefixed with the letter f or F. Any expression inside curly braces {} within the string is evaluated at runtime, and the result is inserted into the string.
name = "Alice"
age = 25
print(f"My name is {name} and I am {age} years old.")
Output:
My name is Alice and I am 25 years old.
Here, both variables name and age are automatically converted to strings and inserted where specified — no additional formatting calls needed.
How f-Strings Differ from Older Formatting Methods
Before f-strings, Python supported older ways of formatting:
| Method | Example | Introduced In | Notes | 
|---|---|---|---|
| Old-style (%) formatting | "My name is %s and I am %d years old." % (name, age) | Python 2 | Less readable, prone to type mismatches. | 
| str.format() method | "My name is {} and I am {} years old.".format(name, age) | Python 2.6 | More flexible but verbose with multiple variables. | 
| f-Strings | f"My name is {name} and I am {age} years old." | Python 3.6 | Most concise, readable, and efficient. | 
f-strings evaluate expressions directly, avoiding the overhead of creating tuples or passing arguments to .format().
Why f-Strings Are Preferred
f-strings improve both readability and performance. They are faster because they are evaluated at runtime and compiled as part of the string literal rather than processed afterward. This makes them more efficient for frequent or large-scale string operations.
They also make code much cleaner — you can see the variables and their positions directly within the string, which helps maintain clarity in longer or dynamic strings.
width = 5
height = 10
print(f"Area: {width * height} square units")
Output:
Area: 50 square units
Embedding Expressions and Calculations
One of the biggest advantages of f-strings is that you can include any valid Python expression inside the curly braces — not just variables.
a, b = 5, 3
print(f"Sum: {a + b}, Product: {a * b}, Power: {a ** b}")
Output:
Sum: 8, Product: 15, Power: 125
This makes them ideal for quick calculations, inline evaluations, or debugging complex code.
Formatting Numbers and Dates
f-strings also support advanced formatting options using format specifiers — similar to str.format(), but more direct.
Example — Numbers:
price = 1234.5678
print(f"Price: {price:.2f}")      # Two decimal places
print(f"Price: {price:,.2f}")     # Thousand separator with commas
Output:
Price: 1234.57
Price: 1,234.57
Example — Dates:
from datetime import datetime
today = datetime.now()
print(f"Today's date: {today:%B %d, %Y}")
Output:
Today's date: October 28, 2025
Using Dictionaries and Object Attributes
You can reference keys of dictionaries or attributes of objects directly inside an f-string.
person = {"name": "Alice", "age": 25}
print(f"{person['name']} is {person['age']} years old.")
class User:
    def __init__(self, name):
        self.name = name
u = User("Bob")
print(f"User: {u.name}")
This eliminates the need for additional variable unpacking or concatenation.
Escaping Braces
If you want to display curly braces {} literally inside an f-string, simply double them:
print(f"Use {{}} to enclose expressions in f-strings.")
Output:
Use {} to enclose expressions in f-strings.
Multiline f-Strings
f-strings can also span multiple lines using triple quotes, making them useful for generating formatted messages or reports.
name = "Alice"
age = 25
print(f"""
Name: {name}
Age: {age}
Status: {'Adult' if age >= 18 else 'Minor'}
""")
When to Avoid f-Strings
While f-strings are versatile, they may not be ideal in every situation.
Avoid using them if:
- You need to maintain compatibility with Python versions earlier than 3.6.
 - You’re building dynamic templates or strings at runtime (for example, localization or translation systems where the string itself changes dynamically).
 
Best practice
- Use f-strings for clarity and performance.
 - Keep complex logic out of f-strings; compute values before formatting if it hurts readability.
 
9. Python literals (numeric, string, boolean, special literals)
Literals are notations for fixed values in source code.
Numeric literals
- Integers: 0, 42, -7, 0b101 (binary), 0o77 (octal), 0x1f (hex).
 - Floating point: 3.14, -0.001, scientific notation 1e3 (1000.0).
 - Complex: 1+2j, 3j.
 
String literals
- Single quotes: 'text'
 - Double quotes: "text"
 - Triple quotes for multi-line: """multi\nline""" or '''...'''
 - Raw strings: prefix with r to avoid escape processing: r"\n" keeps backslash+n.
 - Byte literals: b'bytes'
 
Boolean literals
- True, False (note capitalization).
 
Special literal
- None — denotes absence of value.
 
Examples
num = 0xFF
text = "Hello\nWorld"
raw_text = r"C:\new\test"
flag = True
nothing = None
Best practice
- Use raw strings for file paths or regex patterns to avoid mistaken escape sequences.
 
10. Basic coding exercises
Below are targeted exercises that build on the topics above. Each problem includes a short hint and a sample solution.
Exercise 1 — Indentation & conditionals
Problem: Read an integer from input and print whether it is positive, negative, or zero.
Hint: Use int() to convert input and if/elif/else for branches.
Solution
n = int(input("Enter an integer: "))
if n > 0:
    print("Positive")
elif n < 0:
    print("Negative")
else:
    print("Zero")
Exercise 2 — Strings & formatting
Problem: Ask for the user's name and balance (float). Print: Hi , your balance is ₹ formatted to two decimal places using an f-string.
Hint: Convert balance with float() and use {balance:.2f}.
Solution
name = input("Name: ")
balance = float(input("Balance: "))
print(f"Hi {name}, your balance is ₹{balance:.2f}")
Exercise 3 — Lists and type conversion
Problem: Take a space-separated list of integers from input, convert to a list of int, and print their sum.
Hint: Use split() and map(int, ...) or list comprehension.
Solution
nums = input("Enter numbers: ").split()
nums = [int(x) for x in nums]
print("Sum:", sum(nums))
Exercise 4 — Safe conversion with validation
Problem: Prompt the user for an integer until they enter a valid one. Then print the integer.
Hint: Use try/except ValueError.
Solution
while True:
    s = input("Enter an integer: ")
    try:
        n = int(s)
        break
    except ValueError:
        print("Invalid integer, try again.")
print("You entered:", n)
Exercise 5 — Working with dictionaries (literals + types)
Problem: Create a dictionary that maps three product names to prices. Print each product and price on separate lines using formatting.
Hint: Use a dict literal and iterate .items().
Solution
products = {"pen": 10.0, "notebook": 45.5, "eraser": 2.0}
for name, price in products.items():
    print(f"{name}: ₹{price:.2f}")
Exercise 6 — Boolean logic & keywords
Problem: Given a and b (integers), print True if a is between 10 and 20 (inclusive) or b is negative.
Hint: Use chained comparisons and or.
Solution
a = int(input("a: "))
b = int(input("b: "))
result = (10 <= a <= 20) or (b < 0)
print(result)
Closing notes and further reading
- Practice: The best way to internalize these fundamentals is practice. Implement small scripts and experiment interactively with the REPL.
 - Tools: Use a modern editor (VS Code, PyCharm) and a formatter (black) plus a linter for clean code.
 - Next steps: After mastering these basics, progress to functions, modules & packages, error handling, file I/O, and object-oriented programming.
 
                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                
                                                                