---
jupytext:
  formats: content_md///md:myst,content///ipynb
  text_representation:
    extension: .md
    format_name: myst
    format_version: 0.13
    jupytext_version: 1.13.8
kernelspec:
  display_name: Python 3 (ipykernel)
  language: python
  name: python3
---

(python:crash:first-program)=
# A First Python Program

We start the Python crash course with a small program. The program will ask the user for some keyboard input. If the user types `bye` the program stops, else it asks again.

## Source Code

```{code-cell} ipython3
:tags: [remove-output, raises-exception]

code = None

while code != "bye":

    print("I'm a Python program. Type 'bye' to stop me:")
    code = input()    # get some input from user

    if code == "":
        print("To lazy to type?")
    print("")

print("Bye")
```

## Line by Line

The first line
```python
code = None
```
provides space in memory to store something (this is quite unprecise, but will be made precise soon). We name this piece of memory `code` since we want to store a code typed by the user. At the moment there is nothing to store, which is expressed by `None`.

The second line
```python
while code != "bye":
```
is the head of a loop. The subsequent indented code block is executed again and again as long as the condition `code != "bye"` is satisfied. Here, `!=` means unequal. Thus the line
```python
print("Bye")
```
is not executed before the variable `code` holds the value `bye`.

```python
   print("I'm a Python program. Type 'bye' to stop me:")
```
prints a message on screen and
```python
    code = input()    # get some input from user
```
waits for user input, which then is stored in the variable `code`. Text following a `#` symbol is ignored by the Python interpreter.

```python
    if code == "":
```
checks whether the variable `code` contains an empty string. If so,
```python
        print("To lazy to type?")
```
is executed. Else, execution continues printing a blank line:
```python
    print("")
```

The line
```python
print("Bye")
```
is only executed if the user types `bye`. Then, after executing this, the program stops. There is no other way for the user to stop the program (next to killing it with the operating system's help).

## Some More Details

In our first Python script we can make several important observations:
* The symbol `=` does not mean that the stuff on its left-hand side is the same as on its right-hand side. Instead, the value on the right-hand side is assigned to the variable on the left-hand side. The process of assignment will be made more precise later on.
* Strings are surrounded by quotation marks. Again, details will follow.
* Contrary to most other programming languages, code indentation matters. Subblocks of code have to be indented to be recognized as such by the Python interpreter. Usual indentation width is 4 spaces, but other widths and also tabs may be used as long as indentation is consistent throughout the file.
* There is something we call a function. Functions in our script are `print` and `input`. We can pass arguments to functions to influence their behavior (what to print?) and functions may return some value. The latter is the case for the `input` function. The return value is stored in the variable `code`. Note, that even if we don't want to pass arguments to a function, we have to write parentheses: `input()`.

## Errors

Programming is a very error-prone sport. There are two types of errors:
::::{grid}

:::{grid-item-card}
**Syntax Errors**
^^^
If the Python interpreter does not understand our code, we say that the code contains a syntax error. The interpreter will complain about a syntax error and stop program execution.
:::

:::{grid-item-card}
**Semantic Errors**
^^^
If the Python interpreter understands our code, but the program behaves differently from what we expected it to do, the code contains semantic errors. Some types of semantic errors, like division by zero, are detected by the Python interpreter. Other types won't be detected automatically. If the interpreter sees a semantic error, program execution stops with some hint on the problem.
:::
::::

The following code contains a syntax error: missing `)` in the first call to `print`.

```{code-cell} ipython3
:tags: [raises-exception]

code = None

while code != "bye":

    print("I'm a Python program. Type 'bye' to stop me:"
    code = input()    # get some input from user

    if code == "":
        print("To lazy to type?")
    print("")

print("Bye")
```

The next code example contains a semantic error not detectable by the interpreter: instead of `==` there is `!=` in the `if` statement, which checks for inequality instead of equality. Thus, the program will print the `To lazy to type?` message if the user has typed something. No message will appear if the user has provided no input. That's not what we want the program to do.

```{code-cell} ipython3
:tags: [remove-output, raises-exception]

code = None

while code != "bye":

    print("I'm a Python program. Type 'bye' to stop me:")
    code = input()    # get some input from user

    if code != "":
        print("To lazy to type?")
    print("")

print("Bye")
```

````{important}
Writing code is not too hard. But **writing code without errors is almost impossible**. Finding and correcting errors is an essential task and will consume considerable resources (time and nerves). Some advice for finding errors:
* Always read and understand the error message (if there is one).
* If you do not understand an error message, ask a search engine for explanation.
* Line numbers shown in an error message often are correct, but sometimes the erroneous code is located above (not below) the indicated position.
* Test run your code as often as possible. Write some lines, then test these lines. The less code you write between tests, the more obvious is the reason for an error.
* For each error there is a solution. You just have to find it.
* The Python interpreter is always right! If it says, that there is an error, then THERE IS AN ERROR.
````
