Python Fundamentals#

Information

Details

Learning Objectives

• Write Python programs using core language features
• Transition smoothly from MATLAB to Python
• Apply programming concepts to engineering calculations
• Debug common errors in Python scripts
• Create reusable functions and simple classes

Prerequisites

Basic programming experience (MATLAB preferred)

Estimated Time

2 hours

Topics

Variables, data types, conditional statements, loops, functions, simple classes, error handling

Introduction#

Python has become a dominant programming language in engineering and scientific computing. This lesson teaches Python fundamentals with a focus on helping MATLAB users transition smoothly. We’ll start with basic Python concepts and gradually introduce engineering applications.

It is our goal that, by the end of this lesson, you will be comfortable writing Python programs for engineering calculations. But just like learning other programming languages, practice is key.

For MATLAB Users

This lesson includes explicit comparisons to MATLAB throughout. Look for the “MATLAB Comparison” boxes to understand key differences and similarities.

MATLAB to Python Quick Reference#

If you’re coming from MATLAB, here are the critical differences you need to know:

Concept

MATLAB

Python

Key Difference

Indexing

1-based

0-based

First element is a[0] not a[1]

Code blocks

end statement

Indentation

Python uses indentation, not end

Arrays

Everything is matrix

Lists vs NumPy

Use lists for general data, NumPy for math

Comments

%

#

Python uses # for comments

Power

^

**

2**3 equals 8, not 2^3

Output

Semicolon suppresses

No semicolon needed

Python doesn’t auto-display results

Division

/ always float

/ vs //

/ gives float, // gives “floor” integer division

Critical Warning: Zero-Based Indexing

The single biggest source of errors for MATLAB users is forgetting that Python uses 0-based indexing. The first element of a list is list[0], not list[1].

Getting Started with Simple Calculations#

Let’s start with a basic calculation that you might do in any engineering context. This will introduce Python’s syntax for variables, operations, and output.

Basic Arithmetic#

# Calculate electrical power
voltage = 120  # Volts
current = 10   # Amperes
power = voltage * current  # Watts

print(f"Power: {power} W")
Power: 1200 W

Notice that:

  • Python doesn’t require variable type declarations

  • Comments use # instead of MATLAB’s %

  • We must explicitly print() to see output (no automatic display for assignment statements)

Using the Math Module#

import math

# Calculate power in AC circuit
voltage_rms = 120
current_rms = 10
phase_angle_deg = 30  # degrees

# Convert to radians and calculate
phase_angle_rad = math.radians(phase_angle_deg)
real_power = voltage_rms * current_rms * math.cos(phase_angle_rad)

print(f"Real power: {real_power:.1f} W")
print(f"Power factor: {math.cos(phase_angle_rad):.3f}")
Real power: 1039.2 W
Power factor: 0.866

Tip: F-strings for Formatting

Python’s f-strings (the f"..." syntax) are the most readable way to format output. Use {variable:.Nf} to display N decimal places.

Variables and Data Types#

Python provides several built-in data types for different kinds of information. Let’s explore the most common ones you’ll use in engineering calculations.

Numbers: Integers and Floats#

Python distinguishes between integers (whole numbers) and floating-point numbers (decimals).

# Integer values
num_components = 5
rated_voltage = 230  # V

# Floating-point values
resistance = 10.5  # Ohms
temperature = 25.3  # Celsius
# Check types
print(f"Type of num_components: {type(num_components)}")
print(f"Type of resistance: {type(resistance)}")
Type of num_components: <class 'int'>
Type of resistance: <class 'float'>

Type Conversion#

# Converting between types
voltage_string = "240"
voltage_int = int(voltage_string)
voltage_float = float(voltage_string)

print(f"String: {voltage_string} (type: {type(voltage_string)})")
print(f"Integer: {voltage_int} (type: {type(voltage_int)})")
print(f"Float: {voltage_float} (type: {type(voltage_float)})")
String: 240 (type: <class 'str'>)
Integer: 240 (type: <class 'int'>)
Float: 240.0 (type: <class 'float'>)

MATLAB Comparison: Variable Types

Unlike MATLAB where everything is a matrix by default, Python has distinct types for integers, floats, and strings. Python is dynamically typed - you don’t declare types, but they matter for operations.

Strings for Labels and Names#

# String variables
component_name = "Resistor_R1"
unit_label = "kW"

# String operations
full_label = component_name + " (10" + unit_label + ")"
print(full_label)
Resistor_R1 (10kW)
# String methods
equipment_id = "GEN_001_ACTIVE"
print(f"Lowercase: {equipment_id.lower()}")
print(f"Contains 'GEN': {'GEN' in equipment_id}")
print(f"First 7 characters: {equipment_id[:7]}")
Lowercase: gen_001_active
Contains 'GEN': True
First 7 characters: GEN_001

Lists: Collections of Values#

Lists are Python’s most versatile data structure for storing collections.

# Creating lists
measurements = [23.5, 24.1, 23.8, 24.3, 23.9]  # Temperature readings
components = ["R1", "R2", "C1", "L1"]  # Component names

print(f"Measurements: {measurements}")
print(f"Number of measurements: {len(measurements)}")
Measurements: [23.5, 24.1, 23.8, 24.3, 23.9]
Number of measurements: 5

List Operations#

# Basic operations
avg_temp = sum(measurements) / len(measurements)
max_temp = max(measurements)
min_temp = min(measurements)

print(f"Average: {avg_temp:.2f}°C")
print(f"Range: {min_temp}°C to {max_temp}°C")
Average: 23.92°C
Range: 23.5°C to 24.3°C
# Accessing elements (remember: 0-based indexing!)
print(f"First measurement: {measurements[0]}")
print(f"Last measurement: {measurements[-1]}")
print(f"Middle three: {measurements[1:4]}")
First measurement: 23.5
Last measurement: 23.9
Middle three: [24.1, 23.8, 24.3]

Warning: Zero-Based Indexing

Remember: Python uses 0-based indexing. The first element is at index 0, not 1. Negative indices count from the end: -1 is the last element.

Modifying Lists#

# Adding elements
measurements.append(24.5)  # Add to end
print(f"After append: {measurements}")

# Removing elements
measurements.pop()  # Remove last
print(f"After pop: {measurements}")
After append: [23.5, 24.1, 23.8, 24.3, 23.9, 24.5]
After pop: [23.5, 24.1, 23.8, 24.3, 23.9]

Dictionaries: Named Values#

Dictionaries store data with named keys, similar to MATLAB structures.

# Creating a dictionary
circuit = {
    "voltage": 12,
    "current": 2.5,
    "resistance": 4.8,
    "power": 30
}

print(f"Voltage: {circuit['voltage']} V")
print(f"Current: {circuit['current']} A")
Voltage: 12 V
Current: 2.5 A
# Adding and modifying values
circuit["frequency"] = 60  # Add new key
circuit["power"] = circuit["voltage"] * circuit["current"]  # Update

print(f"Updated power: {circuit['power']} W")
print(f"All keys: {list(circuit.keys())}")
Updated power: 30.0 W
All keys: ['voltage', 'current', 'resistance', 'power', 'frequency']

MATLAB Comparison: Dictionaries vs Structures

Python dictionaries are like MATLAB structures but use bracket notation (dict['key']) instead of dot notation (struct.field). Keys must be strings (or other immutable types).

Exercise 1: Working with Data Types#

Create a dictionary called component to represent an electrical component with these properties:

  • Key "name" with value "R1"

  • Key "resistance" with value 47 (ohms)

  • Key "tolerance" with value 5 (%)

  • Key "temp_coefficients" with value [0.002, 0.003, 0.0025]

Calculate the resistance range based on tolerance:

  • Store the nominal resistance in a variable r

  • Store the tolerance percentage in a variable tol

  • Calculate r_min as the minimum resistance (r × (1 - tol/100))

  • Calculate r_max as the maximum resistance (r × (1 + tol/100))

  • Print the component name and resistance range

Finally, calculate the average temperature coefficient from the list and print it with 4 decimal places.

Hint

Access dictionary values using component["key_name"]. Use sum() and len() to calculate the average of a list.

Hide code cell content

# Solution
component = {
    "name": "R1",
    "resistance": 47,
    "tolerance": 5,
    "temp_coefficients": [0.002, 0.003, 0.0025]
}

# Solution
component = {
    "name": "R1",
    "resistance": 47,
    "tolerance": 5,
    "temp_coefficients": [0.002, 0.003, 0.0025]
}

# Calculate resistance range
r = component["resistance"]
tol = component["tolerance"]
r_min = r * (1 - tol/100)
r_max = r * (1 + tol/100)

print(f"Component: {component['name']}")
print(f"Resistance range: {r_min:.1f} - {r_max:.1f} Ω")

# Average temperature coefficient
avg_coeff = sum(component["temp_coefficients"]) / len(component["temp_coefficients"])
print(f"Average temp coefficient: {avg_coeff:.4f}")
Component: R1
Resistance range: 44.6 - 49.4 Ω
Average temp coefficient: 0.0025

Conditional Statements and Loops#

Programs need to make decisions and repeat operations. Python provides several constructs for program flow control.

If-Elif-Else Statements#

Conditional statements allow different code to run based on conditions.

Important: Indentation

Python uses indentation to define code blocks. Always use 4 spaces for each indentation level. Most editors handle this automatically.

# Simple voltage check
voltage = 118

if voltage < 110:
    print("Voltage too low")
elif voltage > 125:
    print("Voltage too high")
else:
    print("Voltage within acceptable range")
Voltage within acceptable range

Multiple Conditions#

# Temperature and humidity check
temperature = 28
humidity = 65

if temperature > 30 and humidity > 70:
    print("High temperature and humidity - cooling required")
elif temperature > 30 or humidity > 70:
    print("Either temperature or humidity high - monitor closely")
else:
    print("Operating conditions normal")
Operating conditions normal

MATLAB Comparison: if-elif-else

Python uses elif instead of MATLAB’s elseif. Conditions must end with a colon (:), and the code block must be indented. No end statement is needed.

For Loops#

For loops iterate over sequences (lists, ranges, etc.).

# Loop through a list
resistances = [10, 22, 47, 100, 220]

print("Resistance values:")
for r in resistances:
    conductance = 1 / r
    print(f"  R = {r} Ω, G = {conductance:.4f} S")
Resistance values:
  R = 10 Ω, G = 0.1000 S
  R = 22 Ω, G = 0.0455 S
  R = 47 Ω, G = 0.0213 S
  R = 100 Ω, G = 0.0100 S
  R = 220 Ω, G = 0.0045 S

Using range() for Counting#

# Generate sequence of numbers
print("Counting from 0 to 4:")
for i in range(5):
    print(f"  Index {i}")
Counting from 0 to 4:
  Index 0
  Index 1
  Index 2
  Index 3
  Index 4
# Using range with start, stop, step
print("\nVoltage steps from 100V to 130V:")
for v in range(100, 131, 10):
    print(f"  {v} V")
Voltage steps from 100V to 130V:
  100 V
  110 V
  120 V
  130 V

While Loops#

While loops continue as long as a condition is true.

# Iterative calculation
value = 100
iterations = 0

print("Halving until below 10:")
while value > 10:
    value = value / 2
    iterations += 1
    print(f"  Iteration {iterations}: value = {value:.2f}")

print(f"Final value: {value:.2f} after {iterations} iterations")
Halving until below 10:
  Iteration 1: value = 50.00
  Iteration 2: value = 25.00
  Iteration 3: value = 12.50
  Iteration 4: value = 6.25
Final value: 6.25 after 4 iterations

Tip: enumerate() and zip()

Use enumerate() when you need both index and value. Use zip() to iterate over multiple lists together.

# Using enumerate for index and value
components = ["R1", "R2", "C1"]
for i, name in enumerate(components):
    print(f"Component {i}: {name}")
Component 0: R1
Component 1: R2
Component 2: C1
# Using zip to combine lists
names = ["R1", "R2", "R3"]
values = [10, 22, 47]
for name, value in zip(names, values):
    print(f"{name}: {value} Ω")
R1: 10 Ω
R2: 22 Ω
R3: 47 Ω

Exercise 2: Temperature Monitoring#

Given a list of hourly temperature readings, write code that counts how many readings exceed 25°C and identifies the hours when temperature was highest.

Use this data: temps = [22, 23, 24, 26, 28, 27, 26, 24, 23, 22] (representing hours 0-9)

Hint

Use a for loop with enumerate to get both index (hour) and temperature. Keep track of the maximum temperature and its hour.

Hide code cell content

# Solution
temps = [22, 23, 24, 26, 28, 27, 26, 24, 23, 22]

# Count readings above 25°C
count_high = 0
max_temp = temps[0]
max_hour = 0

for hour, temp in enumerate(temps):
    if temp > 25:
        count_high += 1
    if temp > max_temp:
        max_temp = temp
        max_hour = hour

print(f"Readings above 25°C: {count_high}")
print(f"Maximum temperature: {max_temp}°C at hour {max_hour}")
Readings above 25°C: 4
Maximum temperature: 28°C at hour 4

Functions#

Functions allow you to organize code into reusable blocks. They make programs more modular and easier to test.

Defining Functions#

Best Practice: Docstrings

Always include a docstring (triple-quoted string) after the function definition to describe what it does.

def calculate_power(voltage, current):
    """
    Calculate electrical power.
    
    Parameters:
    -----------
        voltage: Voltage in volts
        current: Current in amperes
    
    Returns:
    --------
        Power in watts
    """
    power = voltage * current
    return power
# Using the function
p = calculate_power(120, 2.5)
print(f"Power: {p} W")
Power: 300.0 W

Functions with Default Parameters#

def calculate_resistance(voltage, current, safety_factor=1.0):
    """
    Calculate resistance using Ohm's law.
    
    Parameters:
    -----------
        voltage: Voltage in volts
        current: Current in amperes
        safety_factor: Optional multiplier (default 1.0)
    """
    if current == 0:
        return float('inf')  # Infinite resistance
    
    resistance = (voltage / current) * safety_factor
    return resistance
# Using with and without default parameter
r1 = calculate_resistance(12, 0.5)  # Uses default safety_factor=1.0
r2 = calculate_resistance(12, 0.5, safety_factor=1.2)

print(f"Standard: {r1} Ω")
print(f"With safety factor: {r2} Ω")
Standard: 24.0 Ω
With safety factor: 28.799999999999997 Ω

Returning Multiple Values#

def analyze_measurements(data):
    """
    Calculate statistics for a list of measurements.
    
    Returns:
    --------
        (mean, minimum, maximum)
    """
    mean_val = sum(data) / len(data)
    min_val = min(data)
    max_val = max(data)
    
    return mean_val, min_val, max_val
# Get multiple return values
readings = [23.5, 24.1, 23.8, 24.3, 23.9]
avg, min_r, max_r = analyze_measurements(readings)

print(f"Average: {avg:.2f}")
print(f"Range: {min_r} to {max_r}")
Average: 23.92
Range: 23.5 to 24.3

MATLAB Comparison: Functions

Python functions use def instead of function. They don’t need an end statement. Multiple return values are automatically packed into a tuple.

Exercise 3: Temperature Conversion Function#

Write a function that converts temperature between Celsius and Fahrenheit. The function should take a temperature value and a unit (‘C’ or ‘F’), and return the converted temperature.

Formulas: F = C × 9/5 + 32, C = (F - 32) × 5/9

Hint

Use an if-elif statement to check the unit parameter. Consider what to return if an invalid unit is provided.

Hide code cell content

# Solution
def convert_temperature(temp, unit):
    """
    Convert temperature between Celsius and Fahrenheit.
    
    Parameters:
    -----------
        temp: Temperature value
        unit: 'C' for Celsius, 'F' for Fahrenheit
    
    Returns:
    --------
        Converted temperature
    """
    if unit.upper() == 'C':
        # Convert Celsius to Fahrenheit
        return temp * 9/5 + 32
    elif unit.upper() == 'F':
        # Convert Fahrenheit to Celsius
        return (temp - 32) * 5/9
    else:
        return None  # Invalid unit

# Test the function
print(f"25°C = {convert_temperature(25, 'C'):.1f}°F")
print(f"77°F = {convert_temperature(77, 'F'):.1f}°C")
25°C = 77.0°F
77°F = 25.0°C

Error Handling#

Real programs need to handle unexpected inputs and errors gracefully. Python provides exception handling mechanisms for this.

Important: When to Use Try-Except

Use try-except for exceptional conditions, not normal program flow. It’s better to check conditions explicitly when possible.

Basic Exception Handling#

def safe_divide(a, b):
    """
    Safely divide two numbers.
    """
    try:
        result = a / b
        return result
    except ZeroDivisionError:
        print("Error: Division by zero")
        return None
# Test with different inputs
print(f"10 / 2 = {safe_divide(10, 2)}")
print(f"10 / 0 = {safe_divide(10, 0)}")
10 / 2 = 5.0
Error: Division by zero
10 / 0 = None

Input Validation#

def calculate_current(voltage, resistance):
    """
    Calculate current using Ohm's law with validation.
    """
    # Validate inputs
    if resistance <= 0:
        raise ValueError("Resistance must be positive")
    
    if voltage < 0:
        raise ValueError("Voltage cannot be negative")
    
    return voltage / resistance
# Test with various inputs
test_cases = [(12, 4), (12, 0), (-5, 10)]

for v, r in test_cases:
    try:
        i = calculate_current(v, r)
        print(f"V={v}, R={r}: I = {i:.2f} A")
    except ValueError as e:
        print(f"V={v}, R={r}: Error - {e}")
V=12, R=4: I = 3.00 A
V=12, R=0: Error - Resistance must be positive
V=-5, R=10: Error - Voltage cannot be negative

Warning: Specific Exceptions

Always catch specific exception types (like ValueError or ZeroDivisionError) rather than using bare except: clauses. This helps identify real errors.

Handling Missing Data#

def process_sensor_data(data_dict):
    """
    Process sensor data with missing value handling.
    """
    # Required fields
    required = ['temperature', 'pressure']
    
    # Check for missing fields
    for field in required:
        if field not in data_dict:
            print(f"Warning: Missing {field}, using default")
            # Set defaults
            if field == 'temperature':
                data_dict[field] = 25.0
            elif field == 'pressure':
                data_dict[field] = 101.3
    
    return data_dict
# Test with incomplete data
sensor1 = {'temperature': 23.5, 'pressure': 102.1}
sensor2 = {'temperature': 24.0}  # Missing pressure

print("Sensor 1:", process_sensor_data(sensor1))
print("Sensor 2:", process_sensor_data(sensor2))
Sensor 1: {'temperature': 23.5, 'pressure': 102.1}
Warning: Missing pressure, using default
Sensor 2: {'temperature': 24.0, 'pressure': 101.3}

Introduction to Classes#

Classes allow you to bundle data and functions together into objects. This is useful when you want to model real-world entities with both properties and behaviors.

What is a Class?

A class is like a blueprint. When you create a class, you’re defining what properties and behaviors objects of that type should have. An “instance” is a specific object created from that blueprint.

Simple Sensor Class#

class Sensor:
    """A simple sensor class."""
    
    def __init__(self, name, unit):
        """Initialize the sensor."""
        self.name = name
        self.unit = unit
        self.readings = []
    
    def add_reading(self, value):
        """Add a new reading."""
        self.readings.append(value)
    
    def get_average(self):
        """Calculate average of readings."""
        if self.readings:
            return sum(self.readings) / len(self.readings)
        return 0
    
    def get_latest(self):
        """Get the most recent reading."""
        if self.readings:
            return self.readings[-1]
        return None

Using the Sensor Class#

# Create sensor instances
temp_sensor = Sensor("Temperature", "°C")
pressure_sensor = Sensor("Pressure", "kPa")

# Add readings
temp_sensor.add_reading(23.5)
temp_sensor.add_reading(24.1)
temp_sensor.add_reading(23.8)

# Use methods
print(f"{temp_sensor.name} sensor:")
print(f"  Latest: {temp_sensor.get_latest()}{temp_sensor.unit}")
print(f"  Average: {temp_sensor.get_average():.2f}{temp_sensor.unit}")
Temperature sensor:
  Latest: 23.8°C
  Average: 23.80°C

Important: The self Parameter

Every method in a class must have self as its first parameter. This refers to the specific instance. Python passes it automatically when you call methods.

Equipment Class with Status#

class Equipment:
    """Represents a piece of equipment."""
    
    def __init__(self, equipment_id, rated_power):
        """Initialize equipment."""
        self.id = equipment_id
        self.rated_power = rated_power  # in kW
        self.is_running = False
        self.current_power = 0
        self.hours_run = 0
    
    def start(self):
        """Start the equipment."""
        if not self.is_running:
            self.is_running = True
            self.current_power = self.rated_power * 0.8  # 80% load
            print(f"{self.id} started")
        else:
            print(f"{self.id} already running")
    
    def stop(self):
        """Stop the equipment."""
        if self.is_running:
            self.is_running = False
            self.current_power = 0
            print(f"{self.id} stopped")
        else:
            print(f"{self.id} already stopped")
    
    def run_hours(self, hours):
        """Log running hours."""
        if self.is_running:
            self.hours_run += hours
            energy = self.current_power * hours
            return energy
        return 0
    
    def get_status(self):
        """Get equipment status."""
        status = "Running" if self.is_running else "Stopped"
        return f"{self.id}: {status}, {self.current_power:.1f}/{self.rated_power} kW, {self.hours_run} hours total"
# Create and use equipment
pump = Equipment("PUMP_01", 50)
fan = Equipment("FAN_01", 25)

# Operate equipment
pump.start()
fan.start()

# Run for some hours
energy_pump = pump.run_hours(4)
energy_fan = fan.run_hours(4)

print(f"\nEnergy consumed:")
print(f"  Pump: {energy_pump} kWh")
print(f"  Fan: {energy_fan} kWh")

# Check status
print(f"\nStatus:")
print(f"  {pump.get_status()}")
print(f"  {fan.get_status()}")
PUMP_01 started
FAN_01 started

Energy consumed:
  Pump: 160.0 kWh
  Fan: 80.0 kWh

Status:
  PUMP_01: Running, 40.0/50 kW, 4 hours total
  FAN_01: Running, 20.0/25 kW, 4 hours total

MATLAB Comparison: Classes

Python classes are simpler than MATLAB classes. The __init__ method is like MATLAB’s constructor. No need for separate property or method blocks - everything is defined together.

Data Logger Class#

class DataLogger:
    """Logs and analyzes data points."""
    
    def __init__(self, logger_name, max_points=100):
        """Initialize logger."""
        self.name = logger_name
        self.max_points = max_points
        self.data = []
        self.timestamps = []
    
    def log(self, value, timestamp=None):
        """Log a data point."""
        # Add the value
        self.data.append(value)
        self.timestamps.append(timestamp)
        
        # Keep only max_points most recent
        if len(self.data) > self.max_points:
            self.data.pop(0)
            self.timestamps.pop(0)
    
    def get_statistics(self):
        """Get statistics of logged data."""
        if not self.data:
            return None
        
        return {
            'count': len(self.data),
            'mean': sum(self.data) / len(self.data),
            'min': min(self.data),
            'max': max(self.data)
        }
    
    def clear(self):
        """Clear all logged data."""
        self.data = []
        self.timestamps = []
# Use the data logger
voltage_logger = DataLogger("Voltage Monitor", max_points=10)

# Log some readings
readings = [118, 119, 120, 122, 121, 119, 118, 120, 121, 119]
for v in readings:
    voltage_logger.log(v)

# Get statistics
stats = voltage_logger.get_statistics()
print(stats)
{'count': 10, 'mean': 119.7, 'min': 118, 'max': 122}

Final Exercise: Create a Simple Calculator Class#

Create a Calculator class with the following specifications:

Initialization:

  • Define an __init__ method that initializes self.value to 0

Methods to implement:

  • add(self, x): Add x to the current value, update self.value, and return the new value

  • subtract(self, x): Subtract x from the current value, update self.value, and return the new value

  • multiply(self, x): Multiply the current value by x, update self.value, and return the new value

  • divide(self, x): Divide the current value by x, update self.value, and return the new value

    • Check if x is not zero before dividing

    • If x is zero, print “Error: Division by zero” and don’t modify the value

    • Always return self.value

  • clear(self): Reset self.value to 0 and return 0

  • get_value(self): Return the current value without modifying it

Each method should include a docstring describing what it does.

Hint

All operation methods follow the pattern: modify self.value using the appropriate operator (+=, -=, *=, /=) and then return self.value. The divide method needs an if statement to handle division by zero.

Hide code cell content

# Solution
class Calculator:
    """Simple calculator with memory."""
    
    def __init__(self):
        """Initialize with zero."""
        self.value = 0
    
    def add(self, x):
        """Add to current value."""
        self.value += x
        return self.value
    
    def subtract(self, x):
        """Subtract from current value."""
        self.value -= x
        return self.value
    
    def multiply(self, x):
        """Multiply current value."""
        self.value *= x
        return self.value
    
    def divide(self, x):
        """Divide current value."""
        if x != 0:
            self.value /= x
        else:
            print("Error: Division by zero")
        return self.value
    
    def clear(self):
        """Reset to zero."""
        self.value = 0
        return self.value
    
    def get_value(self):
        """Get current value."""
        return self.value
# Your class should work with the following test code
calc = Calculator()
print(f"Initial: {calc.get_value()}")
print(f"Add 10: {calc.add(10)}")
print(f"Multiply by 3: {calc.multiply(3)}")
print(f"Subtract 5: {calc.subtract(5)}")
print(f"Divide by 5: {calc.divide(5)}")
print(f"Clear: {calc.clear()}")
Initial: 0
Add 10: 10
Multiply by 3: 30
Subtract 5: 25
Divide by 5: 5.0
Clear: 0

Summary#

You’ve learned Python fundamentals that form the foundation for engineering programming:

Data Types: Numbers, strings, lists, and dictionaries for storing different kinds of information.

Program Flow: Conditional statements (if-elif-else) and loops (for, while) for controlling program execution.

Functions: Creating reusable code blocks with parameters and return values.

Error Handling: Using try-except blocks and validation to handle errors gracefully.

Classes: Organizing related data and functions into objects.

MATLAB Transitions: Key differences like zero-based indexing, indentation for blocks, and Python’s simpler syntax.

These fundamentals prepare you for more advanced topics like NumPy for numerical computing and specialized libraries for power system analysis.

Next Steps

Practice these concepts by:

  • Writing functions for common engineering calculations

  • Creating classes to model system components

  • Reading data from files and processing it

  • Building small programs that combine multiple concepts