Python Basics: Syntax, Variables, and Data Types

Python Syntax Philosophy (Readability Matters)

Python’s syntax is designed with one core principle in mind: readability. This isn’t just a nice-to-have; it’s enshrined in “The Zen of Python,” which you can access by typing import this in your Python interpreter. The idea is that code is read more often than it’s written, so it should be as clear and concise as possible.

For juniors coming from languages like C++ or Java, Python feels liberating because it uses indentation (whitespace) instead of curly braces to define code blocks. This enforces clean formatting—no more mismatched braces! But it also means you can’t be sloppy with tabs and spaces; mixing them can lead to IndentationError.

Consider a simple function in Python versus Java:

In Java:

Java

public int add(int a, int b) {
    return a + b;
}

In Python:

Python

def add(a, b):
    return a + b

See the difference? No semicolons, no type declarations (Python is dynamically typed), and the colon (:) starts the block. Readability shines through—it’s almost like pseudocode.

Python also emphasizes “one obvious way to do it” (another Zen principle). For example, to loop over a list, use a for loop instead of while when it fits naturally:

Python

# Good: Readable for loop
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
    print(fruit)

# Avoid: Less readable while loop for the same task
i = 0
while i < len(fruits):
    print(fruits[i])
    i += 1

As a middle dev, start thinking about how your code reads to others. Use meaningful variable names and avoid clever tricks that obscure intent. Tools like PEP 8 (Python’s style guide) can help; install flake8 or black to auto-format your code. Remember, readable code reduces bugs and speeds up collaboration in team settings.

This philosophy extends to everything in Python, including how we handle variables and data types, which we’ll dive into next.

Variables and Naming Conventions

Variables in Python are like labels you stick on data. Unlike statically typed languages, you don’t declare a type upfront—Python infers it at runtime. To create a variable, just assign a value with the equals sign (=).

Python

# Simple assignment
age = 25
name = "Alice"

Python variables are case-sensitive: Age and age are different. Naming conventions follow PEP 8:

  • Use lowercase with underscores for variables and functions: user_name, calculate_sum.
  • Constants in uppercase: MAX_USERS = 100.
  • Classes in CamelCase: UserProfile.
  • Avoid single-letter variables except in short loops (e.g., for i in range(10)).

Why conventions? They make code predictable. In a large codebase, spotting a constant like PI = 3.14159 is instant.

Variables can be reassigned freely, but be cautious—reassigning can change types:

Python

x = 10  # int
x = "ten"  # now str

For juniors: Think of variables as references to objects in memory. When you assign y = x, y points to the same object as x. We’ll revisit this in mutable vs. immutable.

Practice: Write a script that calculates BMI. Use descriptive names:

Python

# Full example: BMI Calculator
height_in_meters = 1.75
weight_in_kg = 70

bmi = weight_in_kg / (height_in_meters ** 2)
print(f"Your BMI is: {bmi:.2f}")

if bmi < 18.5:
    category = "Underweight"
elif 18.5 <= bmi < 25:
    category = "Normal"
else:
    category = "Overweight"

print(f"Category: {category}")

This script demonstrates variables in action. Run it in your IDE (like VS Code with Python extension) to see output. As a middle dev, add input validation— what if height is zero? That leads to division errors, a pitfall we’ll cover later.

Core Data Types: int, float, str, bool

Python’s core data types are the building blocks. Let’s break them down.

  • int: Integers, whole numbers without decimals. No size limit in Python 3 (thanks to arbitrary precision).

Python

positive_int = 42
negative_int = -100
large_int = 12345678901234567890  # Handles big numbers effortlessly

Operations: +, -, *, / (float division), // (integer division), % (modulo), ** (exponent).

  • float: Floating-point numbers for decimals. Approximate due to binary representation.

Python

pi = 3.14159
half = 0.5
scientific = 1.23e-4  # 0.000123

Watch for precision issues: 0.1 + 0.2 == 0.3 is False! Use decimal module for finance.

  • str: Strings, sequences of characters. Immutable (can’t change in place).

Python

greeting = "Hello, World!"
multiline = """This is a
multi-line string."""
escaped = "He said, \"Python is fun!\""

Methods: .upper(), .split(), .format(). f-strings (Python 3.6+) are modern: f”Age: {age}”.

  • bool: Booleans, True or False. Subclass of int (True=1, False=0).

Python

is_adult = True
has_access = False

Used in conditions: if is_adult: print(“Welcome”).

Full example combining types:

Python

# Inventory Checker
item_name = "Laptop"  # str
quantity = 5  # int
price = 999.99  # float
in_stock = quantity ># bool

print(f"Item: {item_name}")
print(f"Quantity: {quantity}")
print(f"Price: ${price:.2f}")
print(f"In stock: {in_stock}")

total_value = quantity * price
print(f"Total value: ${total_value:.2f}")

This shows how types interact. For middle devs: Explore type hints (from typing import List) for better IDE support: def add(a: int, b: int) -> int:.

Type Conversion and Type Checking

Python is dynamically typed, but you often need to convert types. Use built-ins: int(), float(), str(), bool().

Python

# Conversions
num_str = "42"
num_int = int(num_str)  # 42
num_float = float("3.14")  # 3.14
truthy = bool(1)  # True
falsy = bool(0)  # False

Be careful: int(“abc”) raises ValueError.

Type checking with type() or isinstance():

Python

x = 10.5
print(type(x))  # <class 'float'>
if isinstance(x, float):
    print("It's a float!")

Full script: User input converter.

Python

# Input Converter
user_input = input("Enter a number: ")  # str by default
try:
    as_int = int(user_input)
    print(f"As int: {as_int}")
    as_float = float(user_input)
    print(f"As float: {as_float}")
except ValueError:
    print("Invalid number!")

# Check type
if isinstance(as_int, int):
    print("Successfully converted to int.")

This handles errors gracefully. Middle devs: Use this in APIs where data comes as strings from JSON.

Mutable vs Immutable Objects (Critical Concept)

This is where things get interesting—and buggy if misunderstood. Immutable objects can’t be changed after creation; mutable can.

  • Immutable: int, float, str, bool, tuple. Changing creates a new object.

Python

s = "hello"
s_upper = s.upper()  # New string "HELLO", s unchanged
print(s)  # "hello"
  • Mutable: list, dict, set. Changes affect the object in place.

Python

my_list = [1, 2, 3]
my_list.append(4)  # Modifies original: [1,2,3,4]

Why critical? Aliasing: Multiple variables referencing the same mutable object.

Python

a = [1, 2, 3]
b = a  # b references same list
b.append(4)
print(a)  # [1,2,3,4] — a changed too!

For immutable:

Python

x = 10
y = x
y += 1  # New int for y
print(x)  # 10 unchanged

Full example: Mutable pitfall in functions.

Python

def modify_list(lst):
    lst.append("modified")

original = ["original"]
modify_list(original)
print(original)  # ["original", "modified"]

# To avoid: Pass copy
def modify_copy(lst):
    copy = lst[:]  # Shallow copy
    copy.append("modified")
    return copy

new = modify_copy(original)
print(original)  # Unchanged
print(new)  # Modified

Middle devs: Deep copies with copy.deepcopy() for nested mutables. This concept is key for debugging unexpected changes in data structures.

NoneType and Truthy/Falsy Values

None is Python’s null, representing absence. It’s a singleton—always the same object.

Python

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

Use is None not == None for identity check.

Truthy/Falsy: In conditions, values evaluate to True or False.

  • Falsy: False, 0, 0.0, “”, [], {}, None, etc.
  • Truthy: Everything else.

Python

if []:  # Falsy, skips
    print("Not printed")
if "hello":  # Truthy
    print("Printed")

Full example: Default values.

Python

def greet(name=None):
    if name:  # Checks if truthy
        print(f"Hello, {name}")
    else:
        print("Hello, stranger")

greet()  # "Hello, stranger"
greet("Bob")  # "Hello, Bob"

This avoids explicit if name is not None. Juniors: Overuse can lead to bugs—be explicit when needed.

Common Pitfalls with Python Data Types

Even seniors trip up. Here are gotchas:

  1. Floating-point precision: 0.1 + 0.2 != 0.3. Solution: Use math.isclose() or Decimal.

Python

import math
print(0.1 + 0.2 == 0.3)  # False
print(math.isclose(0.1 + 0.2, 0.3))  # True
  1. String mutability: Can’t do s[0] = ‘H’. Use slicing: s = ‘H’ + s[1:].
  2. Integer division in Python 2 vs 3: In 3, / is float, // is int.
  3. None in lists: lst = [None] * 5 is fine, but for mutables, it shares references.

Python

lst = [[]] * 3  # All sublists same!
lst[0].append(1)
print(lst)  # [[1], [1], [1]]

Fix: List comprehension lst = [[] for _ in range(3)].

  1. Type conversion errors: Always wrap in try-except.

Full troubleshooting script:

Python

# Pitfall Demo
try:
    num = int("abc")  # ValueError
except ValueError:
    print("Conversion failed")

# Mutable default arg pitfall
def append_to_list(value, lst=[]):  # Bad! lst persists
    lst.append(value)
    return lst

print(append_to_list(1))  # [1]
print(append_to_list(2))  # [1,2] — surprise!

# Fix
def fixed_append(value, lst=None):
    if lst is None:
        lst = []
    lst.append(value)
    return lst

print(fixed_append(1))  # [1]
print(fixed_append(2))  # [2]

Learn these to debug faster.

Writing Clean and Predictable Code

Tie it all together: Use type hints, docstrings, and tests.

Example with clean code:

Python

from typing import List

def sum_numbers(numbers: List[int]) -> int:
    """
    Sum a list of integers.
    
    Args:
        numbers: List of ints.
    
    Returns:
        Total sum.
    """
    total = 0
    for num in numbers:
        if not isinstance(num, int):
            raise ValueError("All elements must be int")
        total += num
    return total

# Test
try:
    print(sum_numbers([1, 2, 3]))  # 6
    print(sum_numbers([1, "2"]))  # Raises error
except ValueError as e:
    print(e)

Use linters, follow DRY (Don’t Repeat Yourself), and profile with tools like cProfile for performance.

Leave a Reply

Your email address will not be published. Required fields are marked *