<style> .markdown-body h1:first-of-type { margin-top: 24px; } .markdown-body h1 { margin-top: 64px; } .markdown-body h1 + h2 { margin-top: 32px; } .markdown-body h2 { margin-top: 48px; } .markdown-body h2.topics { font-size: 1.8em; border-bottom: none; } .markdown-body h3 { color: cornflowerblue; } .markdown-body p strong { font-weight: normal; color: red; } .exercise { font-size: 150%; font-weight: bold; color: rgb(227,112,183); } .icon-large { font-size: 3em; } .flex { display: flex; align-items: center; } .note { font-weight: bold; color: red; } </style> # ACIT 1515 - Lesson 2 <h2 class="topics">Topics</h2> - [Command-Line I/O](#Command-Line-IO) - [Variables](#Variables) - [Data Types](#Data-Types) - [Operators](#Operators) - [Intro to Debugging](#Intro-to-Debugging) - [Pathlib](#Pathlib) - [Assignment Two](#Assignment-Two) ## Output and Input (a.k.a. "Command-Line I/O") In any programming language you are likely to learn, the first program you typically write is called "Hello, World!", which outputs a simple message to the screen. In Python, the function we use to ==output== text is `print()`, and the "Hello, World!" program would be as simple as: ```python= print('Hello World!') ``` If we require the user to ==input== any text - for example to enter an age - we use the `input()` function, as shown below: ```python= input('Please enter your age') ``` The `input()` function makes it possible for a user (i.e. you!) to _enter_ text into a terminal prompt that can then be captured and used in your script. When we need to capture what the user enters (e.g. in response to the question 'Please enter your age'), we need to create a ==variable==. ## Variables A variable is simply a ==value==, stored somewhere in memory, with a ==name== assigned to it. Note that in Python, we don't care _where_ the value is stored, we just need to use the correct _name_ to access it. The previous example demonstrated how to allow the user to enter a value, but since no variable was created, the value was never stored! Below is the updated version: ```python= age = input('Please enter your age') ``` In this updated example, we have created a variable named 'age' and _assigned_ it whatever value is typed in by the user. Note that this statement (i.e. line of code) runs right-to-left: first, the text 'Please enter your age' appears on the screen. Next, the user types in a value and hits the enter key. Finally, whatever text they typed in is stored into a variable named 'age' using the = symbol, called the ==assignment operator== ('operators' are symbols with a special meaning and use in Python). How do we know that 'age' is a variable? As long as the word on the left-hand side of the assignment operator is not a [reserved word](https://flexiple.com/python/python-reserved-words), and has not previously appeared in our program, a ==variable== is created. ### A Note On Variable Naming Valid variable names in Python must: 1. Not start with a number 2. Not be a Python [keyword](https://realpython.com/python-keywords/) 3. Contain only alphanumeric characters (a-z, A-Z, 0-9) and the underscore _ ### Variables Continued Below are even simpler examples of variables being created: ```python= program = 'ACIT' course = '1515' ``` Now that the variables have been created, we can _output_ them using `print()`, and even _update_ them using another _assignment operator_. ```python= print(course) course = '2515' print(course) ``` The above example first outputs the original _value_ of the 'course' variable, '1515'. Then the variable is reassigned the value '2515', and output again, resulting in: ``` 1515 2515 ``` What if we wanted to combine both values into a single line of output, e.g.: ACIT1515? To accomplish this we need another ==operator== called the ==addition== operator. By 'adding' all the variable's values together, we can _join_ (a.k.a. 'concatenate') them into a single value: ```python= print(program + course) ``` There are several things to note about the line above: 1. In a `print()` statement, referring to an (unquoted) _variable name_, e.g. `program`, will output the _value_ 2. The space between the variable names and the + symbol are not required - they are added purely for readability 3. If we need space between the values, we have to manually insert it ourselves! e.g. `print(program + ' ' + course)` 4. **Not every _type_ of value can be added together!** ## Data Types The previous example works because both values are ==strings==, characters inside of single or double quotes. Adding two strings together using + is called _concatenation_. Values stored in variables are allowed to change _types_ over time, meaning that the following is perfectly valid: ```python= course_number = '1515' course_number = 1515 ``` In this case we are creating a new variable named 'course_number' and assigning it the _string_ '1515'. On the next line we _update_ the value to the _number_ 1515. Python has two basic numeric types, ==int== for whole numbers (10, 20, 35) and ==float== for decimal numbers (10.1, 20.5, 32.75). Like strings, ints and floats can be added together using the addition operator. Two other basic data types we will use in this course are ==booleans== (the keywords ==True== and ==False==), and the special value ==None== for emptiness. <span class="icon-large">⚠️</span> Note the capitalization of True, False, and None! Python is case-sensitive! ### Conversion Functions Each of the above-mentioned data types: string, int, float, and boolean, all have associated functions that can be used to convert one (compatible) data type to another. The conversion functions are named: ```python= str() int() float() bool() ``` and example usage is provided below: ```python= course_string = '1515' course_number = int(course_string) print('In ACIT' + str(course_number) + ' we are learning Python') ``` ## Operators Python has several families of operators, that allow us to perform various operations. There are _arithmetic_ operators for all the typical mathematical operations: ``` + addition - subtraction * multiplication / division ** exponentiation ``` <!-- _Comparison_ operators for comparing two values: ``` > greater than < less than == equal to >= greater than or equal to <= less than or equal to != not equal to ``` --> _Assignment_ operators: ``` = assignment operator += addition assignment operator -= subtraction assignment operator *= multiplication assignment operator /= division assignment operator ``` And many more. As hinted at [above](#nope), not every combination of data type and operator will work together. Strings can be _concatenated_ using +, and numbers can be added together using +, but what about other values? Try adding the examples below to a script to see the results: ```python= print(2 + 2) print('ACIT' + '1515') print('ACIT' + 1515) print(True + None) ``` ## Intro to Debugging Last week we discussed ==syntax== errors - incorrectly written code that prevents your program from running. ```python= print('Hello World!) ``` The example above generates a syntax error because the string is not 'terminated', meaning we forgot to include the closing quote after the exclamation mark. Some examples from the previous section, e.g.: ```python= print('ACIT' + 1515) ``` are not incorrectly written and do not generate syntax errors, but they still cause the script to crash (stop running)! These types of errors are called ==runtime== errors, and they occur when the Python interpreter does not know how to interpret code that is _syntactically_ valid. A runtime error occurs when the syntax is correct, but the *operation* fails or is invalid. The Python interpreter, for instance, does not understand how to add strings and numbers together, so a `TypeError` is generated. If you run this code in the terminal, you will see the message: ``` TypeError: can only concatenate str (not "int") to str ``` A final type of error is a ==logical== error - this refers to code that is syntactically correct (follows the rules of Python syntax), and does not contain invalid operations, but *does not do what you intend it to*. Take the previous example: ```python= print('ACIT' + '1515') ``` This would output 'ACIT1515' and does not generate a runtime error, but if the intended output was 'ACIT 1515' - with a space between the words - you have a *logical* error. Logical errors can be hard to detect, and often have unintended consequences elsewhere in our scripts. Fixing syntax, runtime, and logical errors is referred to as ==debugging==, and it is a separate skill that needs to be developed as you learn how to code. ### Handling errors with `try` and `except` Ideally, the Python scripts we write will never crash. Well-written software should be able to anticipate and handle the many problems that can and will occur. To facilitate this, Python provides the `try` and `except` keywords. Any statements that may cause a script to crash (due to a runtime error) can be placed inside a `try`/`except` block (the term 'block' refers to one or more lines of code with the same indentation), which gracefully recovers from any runtime errors that occur. ### `input()` (again) Remember that the `input()` function allows us to capture text entered by a user. Below is an example: ```python= year = input('Please enter your birth year') ``` If we wanted to calculate a person's age, we could theoretically subtract their birth year from the current year, like so: ```python= current_year = 2025 year = input('Please enter your birth year') age = current_year - year print('You are ' + age + ' years old') ``` However, the code above **does not work!** Why? Because `current_year` is an `int` and the `input()` function **always returns a string**, even if that string is numeric! The Python interpreter does not know how to subtract a number from a string of text, so an error is generated. If we wanted to prevent the above code from crashing our script, we could place the statements inside a `try` block: ```python= try: current_year = 2025 year = input('Please enter your birth year') age = current_year - year print('You are ' + age + ' years old') except: print('An error occurred!') ``` If code placed in the `try` block generates a runtime error, the script will not crash and any statements in the `except` block will run. If the code in the `try` block does not generate a runtime error, the `except` block is not executed. ### Debugging using `print()` and `type()` The `try` and `except` keywords are very useful and convenient, but we don't want to simply place *all* of our code in `try`/`except` blocks. As (aspiring) professional software developers, we need to understand *where* and *why* errors do or might occur. One way for us to make sense of what happens when our scripts run is to _output_ values using the `print()` function. An equally important tool when dealing with variables is the `type()` function, which tells us the _type_ of any value we are using. In the case above, we could add a few temporary lines to our code that use `type()` and `print()` to help us realize that `year` is a string, and `current_year` is an int. ```python= current_year = 2025 year = input('Please enter your birth year') print(type(current_year)) # outputs <class 'int'> print(type(year)) # outputs <class 'string'> ``` Knowing that Python cannot perform this operation, we could then convert `year` to an int using the `int()` function (and then remove or comment out our 'debug' statements). Lines 3 and 4 also demonstrate something important about how functions like `print()` and `type()` work: any operations that are nested happen first, much like order of operations in arithmetic. The result of the following two operations are very different: ``` 2 * 3 + 2 = 8 2 * (3 + 2) = 12 ``` similarly, in the code ```python= print(type(year)) ``` the `type()` function _runs first_ and once completed sends its value to print() to be output. ### Best Practices in Programming and Debugging Here are a few tips to help you as you start to learn coding. These tips apply to every language you will learn inside and outside of BCIT, and will continue to be beneficial as you become a more skilled developer: 1. Slow down and think about problems before coding solutions. Ask yourself "What is the problem I'm trying to solve?", and "what are the possible errors that can happen?" before you start writing any code 2. Debug as you go. Test as frequently as possible and try to avoid writing too much code in between tests 3. Use functions like `type()` and `print()` to ensure you are always clear what types of values you are using 4. Read error messages in the terminal, looking specifically for messages that reference particular line numbers in your program (and focus on testing and changing only those lines!) 5. Read documentation and example code whenever necessary to help understand how Python works 6. If a solution to a problem starts to become more and more complex, start again and look for a simpler solution ## Pathlib In this course we will focus on writing scripts that can automate or improve repetitive tasks related to coding: installing tools, creating project files and folders, and tracking project statuses. To interact with our Linux filesystem (reading and writing files and folders) from within a script, we will need the Pathlib module. A ==Path== object represents a *location* in our filesystem. It could be the location of an existing file or folder, or simply a place where we want to *create* a new folder. For example: ```python= home = Path('/home/you') ``` The code above creates a variable named `home` that contains the *location* of your home folder. If we wanted to create a new file or folder *inside* of the home folder, we could either a) create an entirely new path, or b) *add* to the path we already have inside our `home` variable. Below is an example of adding to our existing path with the `joinpath()` method: ```python= new_location = home.joinpath('test') ``` The `new_location` variable now points to something named test *inside of your home folder*. Note that the variable is called `new_location`, not `new_file` or `new_folder`. Why? Because `new_location` is just that: a location. What we decide to put there is up to us. If we want to turn `new_location` into a folder, we can use the `mkdir()` method: ```python= new_location.mkdir() ``` Alternatively, if we want to turn the location into a file, we can use the `touch()` method: ```python= new_location.touch() ``` All of the above examples are our first look at ==Object Oriented Programming==. OOP (Object-Oriented Programming) is not discussed in this course, but we will *use* objects (and classes) (see the brief introduction [here](https://hackmd.io/@charris17/python-language-quick-reference)). For this course, you are not to expected to understand object-oriented programming, but we can begin to *recognize* when objects are being used by the appearance of so-called ==dot notation==. Any time we see a dot in a Python statement that is not in between quotes, we are interacting with objects. On the left-hand side of a dot is always an object, and on the right-hand side is always a method or property. Object methods (e.g. `joinpath()` and `touch()`) can be 'chained' together, i.e. we can perform several operations in a single line: ```python= Path('/home/you').joinpath('test').touch() ``` In this case, the code runs left to right: first we create a Path object representing our home folder, then we add to it with `joinpath`, and finally we create a file. By 'chaining' the methods together, we accomplish in one line *all* the operations that we previously wrote in three separate steps! ## Assignment Two Assignment Two will give you an introduction to command-line I/O, creating variables, and using the Pathlib library to create files and folders on your filesystem. Starter code is provided for you in the Git repository, and an invitation link will be published on the Learning Hub during the lecture period. As a reminder: to help me mark everyone's submissions in a timely manner, please only push your code when you are finished, or need feedback on your progress. Indicate the status of each push in your commit message, e.g.: ```shell git commit -m "Please help!" ``` or ```shell git commit -m "Complete" ```