Learn by reading through in order

Python Syntax Wrap-Up Problems — Combine Control Flow, Functions, and Exceptions

Three Python syntax wrap-up problems: a filter-and-square list comprehension, a safe_divide using try / except, and a @double decorator that doubles the return value.

Problem 1: Filter and transform with a comprehension

Combine an if filter inside a list comprehension with the ` power operator. Pick out only the elements that match a condition and turn them into something new** — that's the bread-and-butter use of comprehensions.

The 3 steps in a comprehension
range(1, 16)1 to 15if n % 3 == 0or n % 5 == 03 / 5 / 6 / 9 / 10 / 12 / 15n ** 2square each element[9, 25, 36, 81,100, 144, 225]filter with if** 2as list
Build a new list in three stages: iterate → filter → transform.

From the numbers 1 through 15, pull out the multiples of 3 or 5, then collect their squares into a list and print it.

A single-line list comprehension is enough.

Python Editor

Run code to see output

Problem 2: Build a safe division function with try / except

Write safe_divide(a, b) so it doesn't crash on a zero divisor. This pulls together def for defining a function, try / except for catching an exception, and using return to send back different values depending on what happened.

How try / except routes the call
safe_divide(a, b)calltry:return a / bSuccess5.0except:print + return NoneOn errorNonesuccesszero divisor
On success, the value is returned from inside try. On error, control jumps to the matching except block.

Write a function safe_divide that takes two numbers a and b. Normally it should return a / b, but don't let a division-by-zero error crash the program — when that happens, print "Division by zero is not allowed" and return None instead.

Call safe_divide(10, 2) and safe_divide(10, 0) in turn and print() each return value to verify.

Python Editor

Run code to see output

Problem 3: Modify a function's return value with a decorator

Build a decorator @double that doubles whatever the wrapped function returns — without touching the function's body. This forces you to write the decorator pattern itself: a function that takes a function and returns a new function.

How a decorator is wired up
def add(a, b):return a + b@double= double(add)wrapper(*args)= add(*args) * 2add(3, 5) → 16(8 doubled)wrapreturns wrappercall
A decorator is a function that takes a function and returns a new one. @double is the same as add = double(add).

Write a decorator double that doubles the return value of any function it's applied to.

Then apply double to a simple function add(a, b) that returns a + b, call add(3, 5), and print() the result. If your decorator is wired up correctly, the result should differ from a plain sum.

Python Editor

Run code to see output

Nice work getting through this

That wraps up Python Syntax. You've covered control flow with conditionals, loops, and exceptions, function definitions with def / lambda, comprehensions, higher-order functions, decorators, and generators — pretty much every tool you need to drive a program. You can now write functions that take some values, transform them, and return a result on your own.

The next chapter, Python Object-Oriented Programming, is about defining your own types: writing class, setting up constructors with __init__, inheritance, polymorphism, encapsulation, special methods like __add__, context managers with with, and type hints. It's how you bundle data and behavior together into one design.