All courses › Intermediate Programming

Intermediate Programming: free practice, theory and problems

Object-oriented programming (OOP) lets you bundle data together with the functions that belong to it, in one unit: an object. A class is the blueprint, and an object is a concrete instance of it. As an engineer you use this to model real things – a sensor, a component, a simulation – so the code mirrors the problem and is easier to build on.

3 parts56 problems12 concepts explainedPractice examFree
Start practising for free →

Contents

  1. Object orientation
  2. Algorithms and data structures
  3. Numerics with NumPy

1. Object orientation

What is it about?

Object-oriented programming (OOP) lets you bundle data together with the functions that belong to it, in one unit: an object. A class is the blueprint, and an object is a concrete instance of it. As an engineer you use this to model real things – a sensor, a component, a simulation – so the code mirrors the problem and is easier to build on.

Concepts and formulas

How to solve the problems

  1. Work out whether an attribute is a class variable (shared) or an instance variable (set with self. in __init__).
  2. Follow each object separately: which methods are called on which object, and in what order?
  3. With inheritance: check which class's version of the method actually runs (the most specific one defined for that object).
  4. With a class variable: remember that a change made through one object can affect all others, unless a new instance variable with the same name is created.

Example

class Account:
    rate = 0.02          # class variable, shared by all accounts
    def __init__(self, balance):
        self.balance = balance  # instance variable

    def add_interest(self):
        self.balance += self.balance * Account.rate

a = Account(1000)
b = Account(500)
Account.rate = 0.05
a.add_interest()
print(round(a.balance), round(b.balance))
  1. a and b each get their own balance (instance variables): 1000 and 500.
  2. Account.rate = 0.05 changes the class variable for every object, since neither of them has its own rate.
  3. Only a.add_interest() is called: 1000+1000⋅0.05=10501000 + 1000\cdot 0.05 = 1050.
  4. b.balance is unchanged since add_interest was never called on b.

The output is 1050 500.

Common mistakes

An object is data (attributes) + behavior (methods) bundled into one thing. Instance variables are private per object; class variables are shared until something overrides them locally.

Concepts in this part

Practise object orientation in the app →

2. Algorithms and data structures

What is it about?

When data grows large, it is not enough that the code works – it also has to be fast enough. Complexity analysis (Big-O) gives you a language for describing how much work an algorithm does as the amount of data nn grows, independent of the computer. As an engineer you need this to choose the right data structure and algorithm before the code becomes slow on real, large datasets – for example measurement series with millions of points.

Concepts and formulas

How to solve the problems

  1. Find which part of the code repeats the most as nn grows – that is what dominates the complexity.
  2. Count nested loops: one loop over nn gives O(n)O(n), a loop inside a loop gives O(n2)O(n^2).
  3. For recursion: write out the calls until the base case is reached, and count them.
  4. For sorting: follow the algorithm step by step with a concrete list, noting every comparison and every swap.

Example

Insertion sort swaps an element backward until it is in the right place, one step at a time:

def sort(a):
    swaps = 0
    for i in range(1, len(a)):
        j = i
        while j > 0 and a[j-1] > a[j]:
            a[j-1], a[j] = a[j], a[j-1]
            j -= 1
            swaps += 1
    return swaps

print(sort([3, 1, 2]))
  1. i=1i=1: compare a[0]=3a[0]=3 and a[1]=1a[1]=1. 3>13>1, so they are swapped: [1,3,2][1, 3, 2], swaps = 1.
  2. i=2i=2: compare a[1]=3a[1]=3 and a[2]=2a[2]=2. 3>23>2, swap: [1,2,3][1, 2, 3], swaps = 2. Now a[0]=1≤a[1]=2a[0]=1 \leq a[1]=2, so the inner loop stops.
  3. The list is sorted, and the function returns 2.

The output is 2, which is the number of inversions in the original list (the pairs 3–1 and 3–2).

Common mistakes

Count how many times the heaviest operation repeats as nn grows. That, and only that, decides the Big-O.

Concepts in this part

Practise algorithms and data structures in the app →

3. Numerics with NumPy

What is it about?

NumPy gives Python fast, vectorized computation with numeric arrays – essential for engineering calculations on large datasets, such as measurement series and simulations. You will also learn basic numerical methods: Newton's method for finding the roots of a function, and Euler's method for solving differential equations approximately, step by step. try/except lets the program handle bad data without crashing.

Concepts and formulas

How to solve the problems

  1. Check whether the code computes elementwise or does matrix arithmetic – look for * versus @/np.dot.
  2. With boolean indexing: work out the condition for every element first, then keep only the ones that are True.
  3. For Newton/Euler: plug the numbers into the formula, one step at a time, and keep track of which value is xnx_n/yny_n for the next step.
  4. Check the shapes of the arrays before adding them – do they match, or can they broadcast?

Example

A sensor logs 5 measurements. We want the mean of the measurements above 20:

import numpy as np
a = np.array([15, 24, 31, 18, 27])
above = a[a > 20]
print(above, round(above.mean(), 2))
  1. a > 20 gives a boolean array [False, True, True, False, True].
  2. a[a > 20] uses it to pick out the values where the condition is true: [24, 31, 27].
  3. The mean is (24+31+27)/3=27.33(24+31+27)/3 = 27.33.

The output is [24 31 27] 27.33.

Common mistakes

Elementwise is the default in NumPy. Boolean indexing together with .mean()/.sum() is the most common way to filter and summarize measurement data.

Concepts in this part

Practise numerics with NumPy in the app →

Example problems with solutions

Here are some of the problems in intermediate Programming. In the app, calculation problems get new numbers every time, so you can practise until it sticks – and take a graded practice exam before the real one.

Object orientation: What is __init__ in a Python class?

Answer: The constructor that runs when an object is created

It sets up the object's attributes.

Algorithms and data structures: What is the time complexity of binary search in a sorted list?

Answer: O(log⁡n)O(\log n)

The search range halves at every step.

Numerics with NumPy: What does np.linspace(0, 1, 5) give?

Answer: [0, 0.25, 0.5, 0.75, 1]

Five evenly spaced points, including both end points.

Object orientation: What does self refer to in a method?

Answer: The object (instance) the method is called on

obj.method() becomes Class.method(obj).

Practise all the problems →

Matches these university courses

The content covers the syllabus found in engineering degrees, for example: