Please enable JavaScript to use CodeHS

Intro to Brython - Calculator

By Zach Galant

Co-Founder of CodeHS

Brython: Browser Based Python

Introduction

This tutorial explains how to develop an application that runs in the browser using the Python programming language. We will take the example of writing a calculator.

The contents of this tutorial assumes that you have at least a basic knowledge of HTML (general page structure, most usual tags), of stylesheets (CSS) and of the Python language.

In the text editor, create an HTML page with the following content. You can do this in your CodeHS Sandbox or just follow along in this tutorial with the examples.

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/brython@3.8.8/brython.min.js"></script>
    </head>

    <body onload="brython()">
        <script type="text/python">
        from browser import document

        document <= "Hello !"
        </script>
    </body>
</html>
HTML

HTML Page Structure

Let’s take a look at the page contents. In the <head> zone we load the script brython.js: it is the Brython engine, the program that will find and execute the Python scripts included in the page. In this example we get it from a CDN, so that there is nothing to install.

Note the version number (brython@3.8.8): it can be updated for each new Brython version.

The <body> tag has an attribute onload="brython()". It means that when the page has finished loading, the browser has to call the function brython(), which is defined in the Brython engine loaded in the page. The function searches all the <script> tags that have the attribute type="text/python" and executes them.

Our index.html page embeds this script:

from browser import document
document <= "Hello !"
Python

This is a standard Python program, starting by the import of a module, browser (in this case, a module shipped with the Brython engine brython.js). The module has an attribute document which references the content displayed in the browser window.

To add a text to the document - concretely, to display a text in the browser - the syntax used by Brython is

document <= "Hello !"
Python

You can think of the <= sign as a left arrow : the document “receives” a new element, here the string "Hello !". You will see later that it is always possible to use the standardized DOM syntax to interact with the page, by Brython provides a few shortcuts to make the code less verbose.

Text formatting with HTML tags

HTML tags allow text formatting, for instance to write it in bold letters (<B> tag), in italic (<I>), etc.

With Brython, these tags are available as functions defined in module html of the browser package. Here is how to use it:

from browser import document, html
document <= html.B("Hello !")
Python

Tags can be nested:

document <= html.B(html.I("Hello !"))
Python

Tags can also be added to each other, as well as strings:

document <= html.B("Hello, ") + "world !"
Python

The first argument of a tag function can be a string, a number, another tag. It can also be a Python “iterable” (list, comprehension, generator): in this case, all the elements produced in the iteration are added to the tag:

document <= html.UL(html.LI(i) for i in range(5))
Python

Tag attributes are passed as keyword arguments to the function:

html.A("Brython", href="http://brython.info")
Python

Drawing the calculator

We can draw our calculator as an HTML table.

The first line is made of the result zone, followed by a reset button. The next 3 lines are the calculator touches, digits and operations.

See the code and try running it below. Note that the relevant code is inside the <script type="text/python"> tag.

Note the use of Python generators to reduce the program size, while keeping it readable.

Styles

Let’s add style to the tags in a stylesheet so that the calculator looks better.

We’ll add these styles to styles.css

<style>
*{
    font-family: sans-serif;
    font-weight: normal;
    font-size: 1.1em;
}
td{
    background-color: #ccc;
    padding: 10px 30px 10px 30px;
    border-radius: 0.2em;
    text-align: center;
    cursor: default;
}
#result{
    border-color: #000;
    border-width: 1px;
    border-style: solid;
    padding: 10px 30px 10px 30px;
    text-align: right;
}
</style>
CSS

And include it with

<link rel="stylesheet" type="text/css" href="styles.css">
HTML

If you want, you can also just insert the entire text with the <style> tags into the <head> tag in your index.html file.

Event Handling: Responding to user actions

The next step is to trigger an action when the user presses the calculator touches:

  • for digits and operations : print the digit or operation in the result zone
  • for the = sign : execute the operation and print the result, or an error message if the input is invalid
  • for the C letter : reset the result zone

To handle the elements printed in the page, the program need first to get a reference to them. The buttons have been created as <TD> tags; to get a reference to all these tags, the syntax is

document.select("td")
Python

The argument passed to the select() method is a CSS selector. The most usual ones are: a tag name (td), the element’s id attribute (#result) or its attribute “class” (.classname). The result of select() is always a list of elements.

The events that can occur on the elements of a page have a normalized name: when the user clicks on a button, the event called “click” is triggered. In the program, this event will provoque the execution of a function. The association betweeen element, event and function is defined by the syntax

element.bind("click", action)
Python

For the calculator, we can associate the same function to the “click” event on all buttons by:

for button in document.select("td"):
    button.bind("click", action)
Python

To be compliant to Python syntax, the function action() must have been defined somewhere before in the program. Such “callback” functions take a single parameter, an object that represents the event.

Complete Program

Here is the code that manages a minimal version of the calculator. The most important part is in the function action(event).

from browser import document, html

calc = html.TABLE()
calc <= html.TR(html.TH(html.DIV("0", id="result"), colspan=3) +
                html.TD("C"))
lines = ["789/", "456*", "123-", "0.=+"]

calc <= (html.TR(html.TD(x) for x in line) for line in lines)

document <= calc

result = document["result"] # direct acces to an element by its id

def action(event):
    """Handles the "click" event on a button of the calculator."""
    # The element the user clicked on is the attribute "target" of the
    # event object
    element = event.target
    # The text printed on the button is the element's "text" attribute
    value = element.text
    if value not in "=C":
        # update the result zone
        if result.text in ["0", "error"]:
            result.text = value
        else:
            result.text = result.text + value
    elif value == "C":
        # reset
        result.text = "0"
    elif value == "=":
        # execute the formula in result zone
        try:
            result.text = eval(result.text)
        except:
            result.text = "error"

# Associate function action() to the event "click" on all buttons
for button in document.select("td"):
    button.bind("click", action)
Python