Python Arena
Step 3 of 4

Classes are blueprints

Floating point numbers can be slightly off, as you have seen: 0.1 + 0.2 isn't quite 0.3. When a program needs exact answers, for a recipe scaled to three people or a share of a bill, Python's fractions module can help. It has a kind of object called Fraction, a number that is kept as a numerator and a denominator and is never off:

from fractions import Fraction

print(0.1 + 0.2)
print(Fraction(1, 10) + Fraction(2, 10))

share = Fraction(3, 4)
print(share)
print(share + Fraction(1, 6))
print(Fraction(4, 10))
Output
0.30000000000000004
3/10
3/4
11/12
2/5

Fraction(3, 4) creates a new Fraction object with the numerator 3 and the denominator 4, and it reduces the fraction to its simplest form on the way, so Fraction(4, 10) is 2/5. Fractions can be added, multiplied and compared like numbers.

Where objects come from

You made objects this way before. In part 7, datetime(2026, 7, 20) gave you a new datetime object and timedelta(days=3) a new time difference. A call like these, the name of a kind of object followed by the values the new object needs in parentheses, is a constructor call: it builds a new object and gives it to you.

Some objects need no constructor call, because Python lets you write them straight into your code: numbers such as 42 and 3.5, True, False and None, strings, lists, dictionaries and tuples. Most other kinds of objects, such as fractions and dates, have no such shorthand, and a constructor call is how you get one.

One class, many objects

The kind of an object is its class, as type showed in the first step. A class describes one kind of object: what data each object of that kind holds and which methods it has. Think of the blueprint of a house: from one blueprint you can build as many houses as you like, and each house has its own address and its own paint. An object made from a class is called an instance of the class, and the variables that each object has are its attributes.

Every Fraction object has its own values for the attributes numerator and denominator. You read an attribute with the object, a dot and the attribute's name:

from fractions import Fraction

small = Fraction(3, 12)
big = Fraction(7, 2)

print(small.numerator, small.denominator)
print(big.numerator, big.denominator)
Output
1 4
7 2

(3/12 was reduced to 1/4 when the object was made.)

You have read attributes before: meeting.year and meeting.hour in part 7 were attributes of a datetime object. The datetime module also has a smaller class, date, for a day without a time of day. Its objects have just the attributes year, month and day:

In the Python interpreter
>>> from datetime import date
>>> launch = date(2026, 7, 20)
>>> print(launch)
2026-07-20
>>> launch.year
2026
>>> launch.month
7
>>> type(launch)
<class 'datetime.date'>
>>> from fractions import Fraction
>>> type(Fraction(1, 2))
<class 'fractions.Fraction'>

type names the module a class comes from, then the class. Notice that Fraction starts with a capital letter and date doesn't. A capital letter is the custom for the classes you write yourself (PEP 8 asks for it, as the next module shows), and many library classes, such as Fraction, follow it. It's a habit, though, not a rule: Python's own classes int, str and list have small letters, and so do some library classes, such as date and datetime.

Writing programs out of classes and the objects made from them is called object-oriented programming. In the next module you'll write classes of your own. First, a closer look at the objects of classes that Python already has.

Your task

Challenge 1 of 3

Fill in the blanks, so that the program imports the class, then prints the fraction and its denominator:

1/4
4

Challenge 2

What does this program print? Type each line it prints.

Challenge 3

A fraction like 7/4 is easier to read as a mixed number: 1 3/4. Write a function as_mixed(fraction) that takes a Fraction object and returns it as a string in this form: the whole part, a space, then the rest as a fraction. When there's no whole part, return only the fraction (3/4), and when there's no rest, only the whole number (2). The fractions are always positive.

This code:

print(as_mixed(Fraction(7, 4)))
print(as_mixed(Fraction(3, 4)))
print(as_mixed(Fraction(8, 4)))

prints

1 3/4
3/4
2