Programming Basics

Expressions, Style, and Debugging

Let’s get programming!

The first goal of this lecture is to demonstrate that some Python programming is as familiar as using a calculator, which you have likely used before.

The second goal is to introduce programming terminology—expressions, names, assignments, data types, etc. Learning this terminology is like learning grammar; these terms help us describe precisely what our programs are doing. Getting a handle on the terminology earlier will make it easier to describe the programming concepts. But it does take some memorization…!

Read Inferential Thinking

An existing text, Inferential Thinking, defines the terminology and describes the programming concepts quite well. We reference the text chapters (mainly Chapters 3 and 4) below.

When our notes reference other texts, we will provide the terminology/ideas that you should be familiar with after reading those texts.

Expressions

Read Inferential Thinking

Read Ch 3.1, which describes in detail how Python evaluates numeric expressions.

Before continuing, make sure you understand the terminology:

  • expression
  • evaluation
  • syntax
  • operators
  • operands

Summary of Numeric Operators

Common Python operators for numeric data types
Operator Symbol Example Expression Expression Value
Addition + 2 + 3 5
Subtraction - 15 - 4 11
Multiplication * -2 * 9 -18
Division / 15 / 2 7.5
Integer division Cuts off remainder // 15 // 2
Remainder/Modulo % 19 % 3 1
(19 ÷ 3 = 6 Remainder 1)
Exponentiation ** 3 ** 2 9

Names and Call Expressions

Read Inferential Thinking

Read Ch 3.2 and Ch 3.3, which define names and call expressions.

Before continuing, make sure you understand the following:

  • In Python, a name can be given to a value using an assignment statement (which involves the assignment operator, =).
  • A function is a named operation.
  • A call expression invokes functions: a function is called on arguments, the argument values are passed into the function; the function then returns the final value to the larger call expression.
  • In Jupyter Notebooks, placing a ? after a function name will bring up a built-in description of that function.
  • Most functions in Python are stored in modules (e.g., math) that can be imported via import then called with a dot (e.g., math.log(10)).

Terminology:

  • name
  • assignment statement
  • function, arguments, return value
  • call expression

One analogy for names is suitcase tags. Consider the following assignment statement:

x = 3

This statement assigns the name x to the value 3. Like a suitcase tag, the name x is bound to the value 3.

x
3

Python first evaluates the expression on the right-hand side of the = assignment operator, then binds the name x to the resulting value.

The below statement re-assigns the name x. Think of this as moving the suitcase tag to a different suitcase.

x = 1 + 2 * 3 - 4 // 5
x
7

A note on function calls

We will use the term function call interchangeably with call expression. You will see why when we talk more about defining our own functions

Assignment statements are not expressions!

Statements, when executed, do something. Expressions are a type of statement that, when executed, evaluate to values. In Jupyter Notebook code cells, if the last statement in a cell is not an expression, executing that last statement will not produce an output.

The first cell above does not end in an expression and therefore does not produce output. The second cell above has two statements; the last one is an expression, which is displayed in the cell output.

Consider the below Python code:

x = 4
y = max(-2, 9) + x

Python executes these two statements sequentially: first, Line 1 is an assignment statement that assigns the name x to 4. Then, Line 2 assigns the name y to the result of evaluating the right-hand-side.

Style and Debugging

You may have noticed by now that Jupyter Notebooks are not just by computers to run code. Data scientists also use notebooks to understand how the code facilitates data analysis. We’d therefore like to establish two habits early:

Programming Style and Comments

Programming style involves writing code that is self-evident and understandable by other human beings. It is not sufficient for your code to be functional, i.e., perform the correct computation. It should also be readable and interpretable, for others to reuse and adapt.

Good style practices can involve comments, meaningful names, whitespace, markdown cells interspersed with code cells, etc. Ch 3.2 of Inferential Thinking describes meaningful names; we discuss comments below.

Comments are used to explain what code does. Good programmers write code that is self-evident and use comments only where necessary.

In Python, you can write comments in the same line as code (“in-line” comments) using #:

3 + 4     # simple arithmetic
7

The above shows that both code and comments can be on the same line. In that line, anything after # is a comment and is not evaluated.

Debugging

Debugging is the process of fixing errors, i.e., bugs, in code. Debugging is a huge process and can take up the majority of your coding time.

Errors in your code can pop up for any number of reasons! Here are some tips:

Test your code early and often. If you write a lot of code before testing, then you have that much more code to debug and check. Instead, write a bit, test and check, and keep writing. This will require you to know how to decompose, or break down, your solutions into multiple steps that you can test individually. Once you’re comfortable with one step, move onto the next step. That’s right—it’s abstraction!_ Debugging your code will help you better understand computational concepts.

Get familiar with reading error messages. When Python errors, it may give messages that are initially cryptic. Try the following.

  1. Take a deep breath.
  2. Actually read the message—don’t just focus on what you think it might say. The error message will often include a meaningful name (e.g., SyntaxError or ZeroDivisionError), the line, and an arrow (marked by ^) to where the error occurred.
  3. Then, try to explain to yourself why this error occurred, before fixing the error. Many beginning programmers will want skip this step, opting to throw everything at the wall and then, once things are fixed, explain what happened. Instead, slow down and try to understand the problem first. Then the solution will be straightforward.

Trace your code, but not at the expense of testing. Code tracing is the process of analyzing Python code, statement by statement and line by line, to understand program execution. This is a visual process and can sometimes be helped along by diagrams. Learning to trace code is learning procedural thinking—it is a key skill that helps break down exactly what your code is doing. Once you get the hang of tracing your code, you may be tempted to debug by just staring at your code—don’t do this! Instead, develop a healthy balance between developing an understanding of your code and testing if your code does what you expect.

Practice with Errors

Try these on for size:

Syntax errors are errors in writing “valid” Python that cannot even create nonsensical Python code.

3 ** / 4
  Cell In[6], line 1
    3 ** / 4
         ^
SyntaxError: invalid syntax

Why might the below code not error? (Hint: What does - represent?)

9 ** - .5
0.3333333333333333

Once you fix syntax errors, you may still encounter functionality errors, which can be errors caused during execution that leads to your program crashing. Here’s one common one:

5 / 0
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
Cell In[8], line 1
----> 1 5 / 0

ZeroDivisionError: division by zero

```

Summary

We write code to tell our computer what to do.

  • In this class, and in many other settings, we use the Python programming language.
  • We write all of our code in Jupyter Notebooks, which allow us to see the output of our code in the same document in which we wrote our code. They’re commonly used in data science.

Basic Python can be thought of as a calculator language, that takes expressions and computes their values.

  • We learned several different arithmetic operators, each of which can be used in an expression.
  • Python stores integers and decimals in different ways.

Debugging and good style make good programmers.

  • Comments help make our code more readable and sustainable.
  • Choose names that are concise but descriptive.
  • When our code has an error, the error message can help us fix it.
Common Python operators for numeric data types
Operator Symbol Example Expression Expression Value
Addition + 2 + 3 5
Subtraction - 15 - 4 11
Multiplication * -2 * 9 -18
Division / 15 / 2 7.5
Integer division Cuts off remainder // 15 // 2
Remainder/Modulo % 19 % 3 1
(19 ÷ 3 = 6 Remainder 1)
Exponentiation ** 3 ** 2 9

External Reading