<jupyter_start><jupyter_text>Chapter 3 - Expressions ------------------------------- Welcome to the first real programming chapter. In this chapter I discuss "expressions", which are straightforward calculations which you can also do with any simple calculator. It is a small start, but you are going to need such expressions for every chapter after this one. ---  Displaying results When you write an expression in a code block in a notebook, and you run it (by selecting the code block and pressing *Ctrl+Enter*), the result of the expression is shown below it. For instance, if you run the code block below, you see the result `12`.<jupyter_code>5 + 7<jupyter_output><empty_output><jupyter_text>In this manner, the code block works like the Python shell (discussed in the previous chapter). However, if you run the code block below, which contains two expressions, you only see the result of the second one.<jupyter_code>5 + 7
9 - 2<jupyter_output><empty_output><jupyter_text>You must explicitly tell Python to display the result of both expressions, if that is what you want to see. In any case, if you run a Python program outside the shell, you have to explicitly display everything that you want to see, even if it is on the last line of the program.So, even though this chapter is about expressions, the first thing I need to explain is not an expression, but a function, that allows you to display results. The function that does that is `print`. We already saw the `print` function in several chapters before this one.The `print` function is used as follows: you write the word `print`, followed by an opening parenthesis, followed by whatever you want to display, followed by a closing parenthesis. For example (and we saw this one multiple times before):<jupyter_code>print( "Hello, world!" )<jupyter_output><empty_output><jupyter_text>If you run this code (by pressing Ctrl+Enter), you will see that it displays the text "Hello, world!" underneath the code block.**Side note**: When referring to a function by name in a text, authors of texts about programming often put an opening and closing parenthesis after the name of the function, to indicate that it is a function name. From now on, I will follow this convention. Moreover, instead of referring to a "function", authors sometimes call it a "statement" or a "command". However, these terms are usually used to refer to anything that Python can execute, not just functions. I.e., an expression can also be called a "command".You can display multiple things with one `print()` function by putting everything that you want to display between the parentheses with commas in between. The `print()` function will then display all of the items, with one space in between each pair or them. For example:<jupyter_code>print( "I", "own", "two", "apples", "and", "one", "banana" )<jupyter_output><empty_output><jupyter_text>Note that the spaces in this statement are all superfluous. The statement:<jupyter_code>print("I","own","two","apples","and","one","banana")<jupyter_output><empty_output><jupyter_text>is equivalent to the previous one. You can add such spaces for readability. You can even put spaces between the word `print` and the opening parenthesis, but by convention, for functions (and `print()` is a function), the opening parenthesis is placed against the function name.Note that you can not only use `print()` to display texts, but also to display numbers. You can even mix them up, as the following code shows.<jupyter_code>print( "I", "own", 2, "apples", "and", 1, "banana" )<jupyter_output><empty_output><jupyter_text>As was indicated in a previous chapter, you can edit the code blocks in these notebooks.**Exercise**: Edit some of the code blocks above to display different texts. But take note that if you want to display text strings, you have to enclose them in double quotes -- or single quotes, those work too. ---  Data types Before I can get to expressions, there is one more topic that requires some discussion, and that is data types. Specifically, there are three different data types that you need to be aware of at this time: strings, integers, and floats.  Strings A string is a text, consisting of zero or more characters. In Python, a string is enclosed by either double quotes, or single quotes. In principle, it does not matter which of the two you use, i.e., `"orange"` is equivalent to `'orange'`. However, if you have a text which contains a single quote, if you want to avoid problems you have to enclose it in double quotes, i.e., `"I can't stand it"` is a legal string, while `'I can't stand it'` is not. Vice versa for double quotes in a string, of course.What if a string contains both double quotes and single quotes? You can solve that issue by putting a backslash (`\`) in front of the single or double quote that is part of the string to tell Python to treat that single or double quote as a character of the string rather than something that ends the string, i.e., `'I can\'t stand it'` is a legal string. You can see that when you try to print it:<jupyter_code>print( 'I can\'t stand it' )<jupyter_output><empty_output><jupyter_text>But what if I want to put an actual backslash in a string, and that backslash is, by chance, in front of a single or double quote? Well, I can do the same thing for a backslash, namely put a backslash in front of a backslash to make it a literal backslash, rather than a backslash that changes the interpretation of the character that comes after it. For an example, check out what the next bit of code displays.<jupyter_code>print( 'I can\\\'t stand it' )<jupyter_output><empty_output><jupyter_text>If this all is a bit confusing, forget about these details for now, as I will come back to them in a later chapter. For now, just remember that a string is a text, enclosed by either single or double quotes. A string might be of any length, including zero characters long.  Integers Integers are whole numbers, which can be positive or negative (or zero). There is a certain maximum size that integers can become, which depends on the kind of computer and operating system you are running. For most purposes, however, you will not run into those boundaries. Python is not like those calculators with a 10-digit display that cannot use numbers higher than 10 billion.There are different ways of writing integers that result in the same value. `1` is the same as `+1` (there are other ways than these to write the value `1`, but these follow in a later chapter). So the following two commands produce the same output:<jupyter_code>print( 1 )
print( +1 )<jupyter_output><empty_output><jupyter_text>This is different for strings, of course. The string `"1"` is not the same as the string `"+1"`.When you use integers in Python, you cannot write them with "thousands separators" (commas in English) to make them more readable. I.e., the number one billion should be written as `1000000000` rather than `1,000,000,000`.Check out the following code and think about what it will display when you run it. Then run it.<jupyter_code>print( 1,000,000,000 )<jupyter_output><empty_output><jupyter_text>**Exercise**: If your prediction of what this code would do was not correct, find out why it produces this result. Hint: the syntax highlighting applied by the notebooks might provide an idea.  Floats Floats, or "floating-point numbers", are numbers with decimals. For instance, `3.14159265` is a float. Note that you have to use a period as the decimal separator. Many countries use a comma as the decimal separator, but Python uses the convention of English-speaking countries and uses the period.If there is an integer that for some reason you want to use as a float, you can do so by adding `.0` to it. I.e., `13` is an integer, while `13.0` is a float. Still, they represent the same value, and if you use Python to compare them (which I will get to in a short while), Python will tell you that they are the same value.Just like with integers, there are certain maximum boundaries for floats, and there is also a maximum precision. You are unlikely to ever reach those maximum boundaries, as Python will switch over to scientific notation when the numbers get very big, but if you use Python to do very precise calculations, you might run into problems with precision. That will not happen during this course, and it is unlikely to happen for most applications, but if you are a physicist whose calculations involve huge numbers of particles on the molecular or quantum level, it is something to be aware of.Note that due to the way that Python stores floats, certain numbers cannot be expressed exactly. For instance, if you run the following code:<jupyter_code>print( (431 / 100) * 100 )<jupyter_output><empty_output><jupyter_text>you will see that the answer is not 431 as you might expect. If you know that the outcome of a floating-point calculation must be an integer, then you best make sure that you round the outcome to the nearest whole number. You can use the `round()` function for that, which will be explained in a later chapter. ---  Expressions Finally, I can get to the topic of this chapter, which is "expressions". An expression is a combination of one or more values (such as strings, integers, or floats) using operators, which result in a new value. In other words, you can think of expressions as calculations.  Basic calculations Basic calculations combine two values with one operator in between them. Some straightforward operators are:    +   addition    -   subtraction    *   multiplication    /   division    //  integer division    **  power    %   modulo    Here are some examples:<jupyter_code>print( 15+4 )
print( 15-4 )
print( 15*4 )
print( 15/4 )
print( 15//4 )
print( 15**4 )
print( 15%4 )<jupyter_output><empty_output><jupyter_text>I assume you know what each of these operators entails, except perhaps the integer division andmodulo operators. The integer division (also called "floor division") is simply a division that rounds down to a whole number. If you involve floats in the calculation, the result will still be a float, but rounded down. If you only involve integers in the calculation, the result will be an integer.The modulo operator (`%`) takes the remainder of a division. For example: If I divide 14 by 5, the result is 2.8, right? This means I can subtract 5 twice from 14, and still have a positive result, but if I subtract it a third time, the result will become negative. So, after subtracting 5 twice from 14 I have a remainder that is less than 5. This remainder is what the modulo operator produces.In very simplistic terms: if I have 14 cookies which I have to divide over 5 children, each child gets 2 cookies. And I still have 4 cookies left, because there are more children than I have cookies at that point. Thus, dividing 14 by 5 as an integer division is 2 (cookies per child), while 14 modulo 5 is the remainder 4 (cookies I have left in my hand).**Side note**: The code shown above consists of multiple lines. Each line is said to be a "statement", and it consists of one command that Python executes (in the code above, a `print()` function on every line). Most programming languages make it mandatory to end each statement with a special character, usually a semi-colon (`;`). Python does not require a semi-colon after each statement, but each statement must (in general) be on its own line. In principle, you are allowed to place multiple Python statements on one line, but then you should put semi-colons between the statements. However, it is Python practice and convention not to do that, as it makes code ugly, hard to read, and difficult to maintain. So, please stick to the convention and give each statement its own line.  More complex calculations You are allowed to combine operators into bigger calculations, just as you can do on the more advanced calculators. To help you out, you are also allowed to used parentheses in your calculations, and you can even nest these parentheses. Python will process the operators in the order prescribed by mathematicians, often referred to as PEMDAS. Check out the calculation below, and try to predict what it will result in before you run the code.<jupyter_code>print( 5*2-3+4/2 )<jupyter_output><empty_output><jupyter_text>There are a couple of things to note about this calculation. First, the end result is a float (even though it has no decimals, or, if you will, only zero as a decimal). The reason is that a division is part of the calculation, and for Python that means that it should turn this into a floating-point calculation.Second, just as explained above, spaces are ignored by Python, so the code above is the same as:<jupyter_code>print( 5 * 2 - 3 + 4 / 2 )<jupyter_output><empty_output><jupyter_text>It is even the same as:<jupyter_code>print( 5*2 - 3+4    / 2 )<jupyter_output><empty_output><jupyter_text>I have been in long discussions with people who keep arguing that the code above should result in 6.5 or 1.5, because clearly you have to calculate the `5*2` and the `3+4` before you do the subtraction and division. That is hogwash. It does not matter how close you place operands together, spaces are ignored. If you really want to calculate the `3+4` first, you have to put it between parentheses. You can then still use spaces to improve readability, but they mean nothing to Python.<jupyter_code>print( (5*2) - (3+4)/2 )
print( ((5*2)-(3+4)) / 2 )<jupyter_output><empty_output><jupyter_text>**Exercise**: Now it is time to write your first program. In the code block below, write a program that displays the number of seconds in a week. You should, of course, not grab your calculator or smartphone to do the calculation and then just print the resulting number, but you should do the calculation in the Python code.<jupyter_code># Display the number of seconds in a week<jupyter_output><empty_output><jupyter_text>Note that I wrote a "comment line" in this code block. For Python, if there appears a hash mark (``) in a line of code, that means that it should ignore everything on that line to the right of the hash mark. This way you can add textual explanations to your code. More on comments will follow later.  String expressions Some of the operators given above can also be used for strings, though not all of them.In particular, you can use the addition operator (`+`) to concatenate two strings, and you can use the multiplication operator (`*`) with a number and a string to create a string that contains a repetition of the original string. Check it out:<jupyter_code>print( "hello"+"world" )
print( 3*"hello" )
print( "goodbye"*3 )<jupyter_output><empty_output><jupyter_text>You cannot add a number to a string, or multiply two strings. Such use of the operators is undefined, and will give error messages. None of the other operators listed for numbers will work on strings either.  Type casting Sometimes you need to change the data type of a value into a different data type. You can do that using type casting functions. I will discuss functions in a lot more detail in a later chapter, but for now you just need to know that a function has a name, and may have parameters (values) between parentheses after the name. It will do something with the parameters, and then may give back a result. For instance, the `print()` function displays the parameter values that are given to it between the parentheses, and gives nothing in return. The type casting functions take the parameter value between the parentheses and give back a value that is the (almost) the same as the parameter value, but of a different data type. The three main type casting functions are the following:- `int()` will return the value between the parentheses as an integer (rounding down if necessary);- `float()` will return the value between the parentheses as a float (adding `.0` if necessary); and- `str()` will return the value between the parentheses as a string.See the difference between the following two lines of code:<jupyter_code>print( 15/4 )
print( int( 15/4 ) )<jupyter_output><empty_output><jupyter_text>Or the following two lines of code:<jupyter_code>print( 15+4 )
print( float( 15+4 ) )<jupyter_output><empty_output><jupyter_text>I stated that you cannot use the addition operator to concatenate a number to a string. However, if you need to do something like that, you can work around the issue by using string type casting:<jupyter_code>print( "I own " + str( 15 ) + " apples." )<jupyter_output><empty_output><jupyter_text>----------  Style You might have noticed that in my example code I use white spaces a lot. For instance, for parentheses attached to functions, I almost always have a white space after the opening parenthesis and before the closing parenthesis. In calculations, I often have white spaces around operators if that makes the calculations better readable. I also often insert empty lines in my code to make it more readable, and consistently use four spaces as indentations.Most of these things are just "style". The white spaces next to the parentheses and around operators are not necessary, Python understands the code just as well when they are gone. These four statements are all equivalent:<jupyter_code>print( 2 + 3 )
print(2+3)
print( 2+3)
print                 (            2             +           3              )<jupyter_output><empty_output><jupyter_text>Attaching the opening parenthesis to a function is something that almost every programmer does, but for the rest, styles of placing white spaces differ between programmers (my style of placing a space before the closing parenthesis is rare). You can choose your own style in this respect, you do not need to follow mine. But I recommend that you use your chosen style consistently, which will make your code more readable even for programmers who use a different style. ---  What you learned In this chapter, you learned about:-  Using the `print()` function to display results -  Data types string, integer, and float-  Calculations-  Basic string expressions-  Type casting between strings, integers, and floats, using `str()`, `int()`, and `float()` -------  Exercises  Exercise 3.1 The cover price of a book is 24.95 EUR, but bookstores get a 40 percent discount. Shipping costs 3 EUR for the first copy and 75 cents for each additional copy. Calculate the total wholesale costs for 60 copies.<jupyter_code># Book store code.<jupyter_output><empty_output><jupyter_text>Exercise 3.2 Can you identify and explain the errors in the following lines of code? Correct them.<jupyter_code>print( "A message" ).
print( "A message' )
print( 'A messagef"' )<jupyter_output><empty_output><jupyter_text>Exercise 3.3 When something is wrong with your code, Python will raise errors. Often these will be "syntax errors" that signal that something is wrong with the form of your code (e.g., the code in the previous exercise raised a `SyntaxError`). There are also "runtime errors", which signal that your code was in itself formally correct, but that something went wrong during the code's execution. A good example is the `ZeroDivisionError`, which indicates that you tried to divide a number by zero (which, as you may know, is not allowed). Try to make Python raise such a `ZeroDivisionError`.<jupyter_code># ZeroDivisionError.<jupyter_output><empty_output><jupyter_text>Exercise 3.4 Here is another illustrative example of a runtime error. Run the follow code and study the error that it generates. Can you locate the problem?<jupyter_code>print( ((2*3)/4 + (5-6/7)*8 )
print( ((12*13)/14 + (15-16)/17)*18 )<jupyter_output><empty_output><jupyter_text>Exercise 3.5 You look at the clock and see that it is currently 14.00h. You set an alarm to go off 535 hours later. At what time will the alarm go off? Write a program that prints the answer. Hint: for the best solution, you will need the modulo operator. Second hint: The answer is 21.00h, but of course, this exercise is not about the answer, but about how you get it.<jupyter_code># Clock.<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.06278675443846, 'fraction_numerical': 0.01186914023538799, 'mean_word_length': 4.588907469342252, 'pattern_counts': {'":': 0, '<': 109, '<?xml version=': 0, '>': 109, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 1, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '27', 'dir': 'jupyter-structured-clean-dedup', 'id': '573845', 'license': 'MIT', 'n_tokens_mistral': 5238, 'n_tokens_neox': 4961, 'n_words': 3113, 'path': 'notebooks uni/PC03 - Expressions.ipynb', 'repo_name': 'tintin10q/RandomPythonProjects', 'size': '20052'}