# Python Crash Course ![rw-book-cover](https://images-na.ssl-images-amazon.com/images/I/51A4cWQgMtL._SL200_.jpg) ## Metadata - Author: [[Eric Matthes]] - Full Title: Python Crash Course - Category: #python ## Highlights - The method title() appears after the variable in the print() statement. A method is an action that Python can perform on a piece of data. The dot (.) after name in name.title() tells Python to make the title() method act on the variable name. Every method is followed by a set of parentheses, because methods often need additional information to do their work. That information is provided inside the parentheses. The title() function doesn’t need any additional information, so its parentheses are empty. ([Location 1047](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1047)) - Python uses the plus symbol (+) to combine strings. In this example, we use + to create a full name by combining a first_name, a space, and a last_name ➊, giving this result: ([Location 1069](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1069)) - In programming, whitespace refers to any nonprinting character, such as spaces, tabs, and end-of-line symbols. You can use whitespace to organize your output so it’s easier for users to read. To add a tab to your text, use the character combination \t as shown at ➊ ([Location 1088](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1088)) - To add a newline in a string, use the character combination \n: ([Location 1094](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1094)) - Extra whitespace can be confusing in your programs. To programmers 'python' and 'python ' look pretty much the same. But to a program, they are two different strings. Python detects the extra space in 'python ' and considers it significant unless you tell it otherwise. It’s important to think about whitespace, because often you’ll want to compare two strings to determine whether they are the same. For example, one important instance might involve checking people’s usernames when they log in to a website. Extra whitespace can be confusing in much simpler situations as well. Fortunately, Python makes it easy to eliminate extraneous whitespace from data that people enter. Python can look for extra whitespace on the right and left sides of a string. To ensure that no whitespace exists at the right end of a string, use the rstrip() method. ([Location 1103](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1103)) - You can also strip whitespace from the left side of a string using the lstrip() method or strip whitespace from both sides at once using strip() ([Location 1130](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1130)) - One kind of error that you might see with some regularity is a syntax error. A syntax error occurs when Python doesn’t recognize a section of your program as valid Python code. For example, if you use an apostrophe within single quotes, you’ll produce an error. This happens because Python interprets everything between the first single quote and the apostrophe as a string. It then tries to interpret the rest of the text as Python code, which causes errors. Here’s how to use single and double quotes correctly. Save this program as apostrophe.py and then run ([Location 1143](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1143)) - In the output you can see that the error occurs at ➊ right after the second single quote. This syntax error indicates that the interpreter doesn’t recognize something in the code as valid Python code. ([Location 1157](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1157)) - You can add (+), subtract (-), multiply (*), and divide (/) integers in Python. ([Location 1193](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1193)) - Python uses two multiplication symbols to represent exponents: ([Location 1199](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1199)) - Python supports the order of operations too, so you can use multiple operations in one expression. ([Location 1202](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1202)) - Python calls any number with a decimal point a float. This term is used in most programming languages, and it refers to the fact that a decimal point can appear at any position in a number. Every programming language must be carefully designed to properly manage decimal numbers so numbers behave appropriately no matter where the decimal point appears. ([Location 1207](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1207)) - This is a type error. It means Python can’t recognize the kind of information you’re using. In this example Python sees at ➊ that you’re using a variable that has an integer value (int), but it’s not sure how to interpret that value. Python knows that the variable could represent either the numerical value 23 or the characters 2 and 3. ([Location 1228](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1228)) - Python 2 returns a slightly different result when you divide two integers: >>> python2.7 >>> 3 / 2 1 Instead of 1.5, Python returns 1. Division of integers in Python 2 results in an integer with the remainder truncated. Note that the result is not a rounded integer; the remainder is simply omitted. To avoid this behavior in Python 2, make sure that at least one of the numbers is a float. By doing so, the result will be a float as well: ([Location 1241](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1241)) - In Python, the hash mark (#) indicates a comment. Anything following a hash mark in your code is ignored by the Python interpreter. ([Location 1262](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1262)) - The main reason to write comments is to explain what your code is supposed to do and how you are making it work. When you’re in the middle of working on a project, you understand how all of the pieces fit together. But when you return to a project after some time away, you’ll likely have forgotten some of the details. You can always study your code for a while and figure out how segments were supposed to work, but writing good comments can save you time by summarizing your overall approach in clear English. ([Location 1267](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1267)) - A list is a collection of items in a particular order. ([Location 1328](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1328)) - In Python, square brackets ([]) indicate a list, and individual elements in the list are separated by commas. Here’s a simple example of a list that contains a few kinds of bicycles: bicycles.py bicycles = ['trek', 'cannondale', 'redline', 'specialized'] print(bicycles) ([Location 1333](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1333)) - Lists are ordered collections, so you can access any element in a list by telling Python the position, or index, of the item desired. To access an element in a list, write the name of the list followed by the index of the item enclosed in square brackets. For example, let’s pull out the first bicycle in the list bicycles:    bicycles = ['trek', 'cannondale', 'redline', 'specialized'] ➊ print(bicycles[0]) The syntax for this is shown at ➊. When we ask for a single item from a list, Python returns just that element without square brackets or quotation marks: trek ([Location 1340](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1340)) - Index Positions Start at 0, Not 1 ([Location 1353](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1353)) - Python has a special syntax for accessing the last element in a list. By asking for the item at index -1, Python always returns the last item in the list: ([Location 1362](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1362)) - ➊ motorcycles = ['honda', 'yamaha', 'suzuki']    print(motorcycles) ➋ motorcycles[0] = 'ducati'    print(motorcycles) The code at ➊ defines the original list, with 'honda' as the first element. The code at ➋ changes the value of the first item to 'ducati'. The output shows that the first item has indeed been changed, and the rest of the list stays the same: ([Location 1396](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1396)) - The simplest way to add a new element to a list is to append the item to the list. When you append an item to a list, the new element is added to the end of the list. Using the same list we had in the previous example, we’ll add the new element 'ducati' to the end of the list:    motorcycles = ['honda', 'yamaha', 'suzuki']    print(motorcycles) ➊ motorcycles.append('ducati')    print(motorcycles) ([Location 1407](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1407)) - Removing an Item Using the pop() Method Sometimes you’ll want to use the value of an item after you remove it from a list. For example, you might want to get the x and y position of an alien that was just shot down, so you can draw an explosion at that position. In a web application, you might want to remove a user from a list of active members and then add that user to a list of inactive members. The pop() method removes the last item in a list, but it lets you work with that item after removing it. The term pop comes from thinking of a list as a stack of items and popping one item off the top of the stack. In this analogy, the top of a stack corresponds to the end of a list. ([Location 1451](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1451)) - You can actually use pop() to remove an item in a list at any position by including the index of the item you want to remove in parentheses. ([Location 1475](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1475)) - Sometimes you won’t know the position of the value you want to remove from a list. If you only know the value of the item you want to remove, you can use the remove() method. For example, let’s say we want to remove the value 'ducati' from the list of motorcycles.    motorcycles = ['honda', 'yamaha', 'suzuki', 'ducati']    print(motorcycles) ➊ motorcycles.remove('ducati') ([Location 1488](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1488)) - too_expensive = 'ducati' ➌ motorcycles.remove(too_expensive)    print(motorcycles) ➍ print("\nA " + too_expensive.title() + " is too expensive for me.") ([Location 1501](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1501)) - The remove() method deletes only the first occurrence of the value you specify. If there’s a possibility the value appears more than once in the list, you’ll need to use a loop to determine if all occurrences of the value have been removed. You’ll learn how to do this in Chapter 7. ([Location 1512](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1512)) - Python’s sort() method makes it relatively easy to sort a list. ([Location 1549](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1549)) - You can also sort this list in reverse alphabetical order by passing the argument reverse=True to the sort() method. The following example sorts the list of cars in reverse alphabetical order: cars = ['bmw', 'audi', 'toyota', 'subaru'] cars.sort(reverse=True) print(cars) ([Location 1556](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1556)) - To maintain the original order of a list but present it in a sorted order, you can use the sorted() function. The sorted() function lets you display your list in a particular order but doesn’t affect the actual order of the list. ([Location 1563](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1563)) - To reverse the original order of a list, you can use the reverse() method. ([Location 1584](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1584)) - You can quickly find the length of a list by using the len() function. ([Location 1593](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1593)) - Python initially reads the first line of the loop: for magician in magicians: This line tells Python to retrieve the first value from the list magicians and store it in the variable magician. This first value is 'alice'. Python then reads the next line:    print(magician) Python prints the current value of magician, which is still 'alice'. Because the list contains more values, Python returns to the first line of the loop: for magician in magicians: Python retrieves the next name in the list, 'david', and stores that value in magician. Python then executes the line:    print(magician) ([Location 1685](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1685)) - When you’re using loops for the first time, keep in mind that the set of steps is repeated once for each item in the list, no matter how many items are in the list. ([Location 1699](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1699)) - You can also write as many lines of code as you like in the for loop. Every indented line following the line for magician in magicians is considered inside the loop, and each indented line is executed once for each value in the list. Therefore, you can do as much work as you like with each value in the list. ([Location 1720](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1720)) - Any lines of code after the for loop that are not indented are executed once without repetition. ([Location 1739](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1739)) - Python uses indentation to determine when one line of code is connected to the line above it. In the previous examples, the lines that printed messages to individual magicians were part of the for loop because they were indented. Python’s use of indentation makes code very easy to read. ([Location 1756](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1756)) - Python’s range() function makes it easy to generate a series of numbers. For example, you can use the range() function to print a series of numbers like this: numbers.py for value in range(1,5):     print(value) ([Location 1845](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1845)) - If you want to make a list of numbers, you can convert the results of range() directly into a list using the list() function. When you wrap list() around a call to the range() function, the output will be a ([Location 1860](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1860)) - list of numbers. In the example in the previous section, we simply printed out a series of numbers. We can use list() to convert that same set of numbers into a list: numbers = list(range(1,6)) print(numbers) ([Location 1863](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1863)) - even_numbers.py even_numbers = list(range(2,11,2)) print(even_numbers) In this example, the range() function starts with the value 2 and then adds 2 to that value. It adds 2 repeatedly until it reaches or passes the end value, 11, and produces this result: [2, 4, 6, 8, 10] ([Location 1868](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1868)) - To write this code more concisely, omit the temporary variable square and append each new value directly to the list:    squares = []    for value in range(1,11): ➊     squares.append(value**2)    print(squares) ([Location 1887](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1887)) - The approach described earlier for generating the list squares consisted of using three or four lines of code. A list comprehension allows you to generate this same list in just one line of code. ([Location 1905](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1905)) - It takes practice to write your own list comprehensions, but you’ll find them worthwhile once you become comfortable creating ordinary lists. ([Location 1920](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1920)) - Slices are very useful in a number of situations. For instance, when you’re creating a game, you could add a player’s final score to a list every time that player finishes playing. ([Location 1980](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1980)) - For example, imagine we have a list of our favorite foods and want to make a separate list of foods that a friend likes. This friend likes everything in our list so far, so we can create their list by copying ours: foods.py ➊ my_foods = ['pizza', 'falafel', 'carrot cake'] ➋ friend_foods = my_foods[:] ([Location 1989](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=1989)) - A tuple looks just like a list except you use parentheses instead of square brackets. Once you define a tuple, you can access individual elements by using each item’s index, just as you would for a list. For example, if we have a rectangle that should always be a certain size, we can ensure that its size doesn’t change by putting the dimensions into a tuple: ([Location 2063](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=2063)) - Basically, because we’re trying to alter a tuple, which can’t be done to that type of object, Python tells us we can’t assign a new value to an item in a tuple: ([Location 2076](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=2076)) - Although you can’t modify a tuple, you can assign a new value to a variable that holds a tuple. So if we wanted to change our dimensions, we could redefine the entire tuple: ([Location 2086](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=2086)) - When compared with lists, tuples are simple data structures. Use them when you want to store a set of values that should not be changed throughout the life of a program. ([Location 2097](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=2097)) - At the heart of every if statement is an expression that can be evaluated as True or False and is called a conditional test. Python uses the values True and False to decide whether the code in an if statement should be executed. If a conditional test evaluates to True, Python executes the code following the if statement. If the test evaluates to False, Python ignores the code following the if statement. ([Location 2190](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=2190)) - When you want to determine whether two values are not equal, you can combine an exclamation point and an equal sign (!=). ([Location 2241](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=2241)) - Boolean values provide an efficient way to track the state of a program or a particular condition that is important in your program. ([Location 2340](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=2340)) - However, sometimes it’s important to check all of the conditions of interest. In this case, you should use a series of simple if statements with no elif or else blocks. This technique makes sense when more than one condition could be True, and you want to act on every condition that is True ([Location 2494](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=2494)) - As an example, let’s check whether the list of requested toppings is empty before building the pizza. If the list is empty, we’ll prompt the user and make sure they want a plain pizza. If the list is not empty, we’ll build the pizza just as we did in the previous examples: ([Location 2600](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=2600)) - A dictionary in Python is a collection of key-value pairs. Each key is connected to a value, and you can use a key to access the value associated with that key. A key’s value can be a number, a string, a list, or even another dictionary. In fact, you can use any object that you can create in Python as a value in a dictionary. In Python, a dictionary is wrapped in braces, {}, with a series of key-value pairs inside the braces, as shown in the earlier example: alien_0 = {'color': 'green', 'points': 5} A key-value pair is a set of values associated with each other. When you provide a key, Python returns the value associated with that key. Every key is connected to its value by a colon, and individual key-value pairs are separated by commas. You can store as many key-value pairs as you want in a dictionary. The simplest dictionary has exactly one key-value pair, as shown in this modified version of the alien_0 dictionary: alien_0 = {'color': 'green'} This dictionary stores one piece of information about alien_0, namely the alien’s color. The string 'color' is a key in this dictionary, and its associated value is 'green'. ([Location 2709](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=2709)) - Dictionaries are dynamic structures, and you can add new key-value pairs to a dictionary at any time. For example, to add a new key-value pair, you would give the name of the dictionary followed by the new key in square brackets along with the new value. ([Location 2740](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=2740)) - print("The alien is " + alien_0['color'] + ".") alien_0['color'] = 'yellow' print("The alien is now " + alien_0['color'] + ".") We first define a dictionary for alien_0 that contains only the alien’s color; then we change the value associated with the key 'color' to 'yellow'. The output shows that the alien has indeed changed from green to yellow: ([Location 2770](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=2770)) - The second half of the for statement at ➊ includes the name of the dictionary followed by the method items(), which returns a list of key-value pairs. ([Location 2886](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=2886)) - Sometimes you’ll want to store a set of dictionaries in a list or a list of items as a value in a dictionary. This is called nesting. You can nest a set of dictionaries inside a list, a list of items inside a dictionary, or even a dictionary inside another dictionary. Nesting is a powerful feature, as the following examples will demonstrate. ([Location 3024](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3024)) - Rather than putting a dictionary inside a list, it’s sometimes useful to put a list inside a dictionary. For example, consider how you might describe a pizza that someone is ordering. If you were to use only a list, all you could really store is a list of the pizza’s toppings. With a dictionary, a list of toppings can be just one aspect of the pizza you’re describing. In the following example, two kinds of information are stored for each pizza: a type of crust and a list of toppings. The list of toppings is a value associated with the key 'toppings'. To use the items in the list, we give the name of the dictionary and the key 'toppings', as we would any value in the dictionary. Instead of returning a single value, we get a list of toppings: pizza.py    # Store information about a pizza being ordered. ➊ pizza = {        'crust': 'thick',        'toppings': ['mushrooms', 'extra cheese'],        }    # Summarize the order. ➋ print("You ordered a " + pizza['crust'] + "-crust pizza " +        "with the following toppings:") ➌ for topping in pizza['toppings']:        print("\t" + topping) ([Location 3087](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3087)) - You can nest a list inside a dictionary any time you want more than one value to be associated with a single key in a dictionary. In the earlier example of favorite programming languages, if we were to store each person’s responses in a list, people could choose more than one favorite language. ([Location 3108](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3108)) - You can nest a dictionary inside another dictionary, but your code can get complicated quickly when you do. ([Location 3137](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3137)) - The input() function takes one argument: the prompt, or instructions, that we want to display to the user so they know what to do. In this example, when Python runs the first line, the user sees the prompt Tell me something, and I will repeat it back to you:. The program waits while the user enters their response and continues after the user presses ENTER. ([Location 3212](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3212)) - If you’re using Python 2.7, you should use the raw_input() function when prompting for user input. This function interprets all input as a string, just as input() does in Python 3. Python 2.7 has an input() function as well, but this function interprets the user’s input as Python code and attempts to run the input. At best you’ll get an error that Python doesn’t understand the input; at worst you’ll run code that you didn’t intend to run. If you’re using Python 2.7, use raw_input() instead of input() ([Location 3294](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3294)) - (The += operator is shorthand for current_number = current_number + 1.) ([Location 3317](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3317)) - For a program that should run only as long as many conditions are true, you can define one variable that determines whether or not the entire program is active. This variable, called a flag, acts as a signal to the program. We can write our programs so they run while the flag is set to True ([Location 3374](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3374)) - We set the variable active to True ➊ so the program starts in an active state. Doing so makes the while statement simpler because no comparison is made in the while statement itself; the logic is taken care of in other parts of the program. As long as the active variable remains True, the loop will continue running ➋. In the if statement inside the while loop, we check the value of message once the user enters their input. If the user enters 'quit' ➌, we set active to False, and the while loop stops. If the user enters anything other than 'quit' ➍, we print their input as a message. ([Location 3389](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3389)) - To exit a while loop immediately without running any remaining code in the loop, regardless of the results of any conditional test, use the break statement. The break statement directs the flow of your program; you can use it to control which lines of code are executed and which aren’t, so the program only executes code that you want it to, when you want it to. ([Location 3407](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3407)) - Every programmer accidentally writes an infinite while loop from time to time, especially when a program’s loops have subtle exit conditions. If your program gets stuck in an infinite loop, press CTRL-C or just close the terminal window displaying your program’s output. ([Location 3458](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3458)) - You can prompt for as much input as you need in each pass through a while loop. Let’s make a polling program in which each pass through the loop prompts for the participant’s name and response. We’ll store the data we gather in a dictionary, because we want to connect each response with a particular user: ([Location 3531](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3531)) - This example shows the simplest structure of a function. The line at ➊ uses the keyword def to inform Python that you’re defining a function. This is the function definition, which tells Python the name of the function and, if applicable, what kind of information the function needs to do its job. The parentheses hold that information. In this case, the name of the function is greet_user(), and it needs no information to do its job, so its parentheses are empty. (Even so, the parentheses are required.) Finally, the definition ends in a colon. Any indented lines that follow def greet_user(): make up the body of the function. The text at ➋ is a comment called a docstring, which describes what the function does. Docstrings are enclosed in triple quotes, which Python looks for when it generates documentation for the functions in your programs. ([Location 3600](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3600)) - The variable username in the definition of greet_user() is an example of a parameter, a piece of information the function needs to do its job. The value 'jesse' in greet_user('jesse') is an example of an argument. ([Location 3635](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3635)) - An argument is a piece of information that is passed from a function call to a function. ([Location 3638](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3638)) - Because a function definition can have multiple parameters, a function call may need multiple arguments. You can pass arguments to your functions in a number of ways. You can use positional arguments, which need to be in the same order the parameters were written; keyword arguments, where each argument consists of a variable name and a value; and lists and dictionaries of values. ([Location 3652](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3652)) - When you call a function, Python must match each argument in the function call with a parameter in the function definition. The simplest way to do this is based on the order of the arguments provided. Values matched up this way are called positional arguments. ([Location 3656](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3656)) - A keyword argument is a name-value pair that you pass to a function. You directly associate the name and the value within the argument, so when you pass the argument to the function, there’s no confusion (you won’t end up with a harry named Hamster). ([Location 3700](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3700)) - describe_pet(animal_type='hamster', pet_name='harry') The function describe_pet() hasn’t changed. But when we call the function, we explicitly tell Python which parameter each argument should be matched with. When Python reads the function call, it knows to store the argument 'hamster' in the parameter animal_type and the argument 'harry' in pet_name. The output correctly shows that we have a hamster named Harry. ([Location 3708](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3708)) - When writing a function, you can define a default value for each parameter. If an argument for a parameter is provided in the function call, Python uses the argument value. ([Location 3719](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3719)) - Note that the order of the parameters in the function definition had to be changed. Because the default value makes it unnecessary to specify a type of animal as an argument, the only argument left in the function call is the pet’s name. ([Location 3734](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3734)) - A function doesn’t always have to display its output directly. Instead, it can process some data and then return a value or set of values. The value the function returns is called a return value. ([Location 3794](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3794)) - To make the middle name optional, we can give the middle_name argument an empty default value and ignore the argument unless the user provides a value. ([Location 3827](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3827)) - A function can return any kind of value you need it to, including more complicated data structures like lists and dictionaries. ([Location 3855](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3855)) - The function build_person() takes in a first and last name, and packs these values into a dictionary at ➊. ([Location 3862](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3862)) - We add a message that informs the user how to quit, and then we break out of the loop if the user enters the quit value at either prompt. Now the program will continue greeting people until someone enters 'q' for either name: ([Location 3907](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3907)) - When you pass a list to a function, the function can modify the list. Any changes made to the list inside the function’s body are permanent, allowing you to work efficiently even when you’re dealing with large amounts of data. ([Location 3943](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3943)) - At ➊ we define the function print_models() with two parameters: a list of designs that need to be printed and a list of completed models. Given these two lists, the function simulates printing each design by emptying the list of unprinted designs and filling up the list of completed models. At ➋ we define the function show_completed_models() with one parameter: the list of completed models. Given this list, show_completed_models() displays the name of each model that was printed. ([Location 3974](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3974)) - We set up a list of unprinted designs and an empty list that will hold the completed models. Then, because we’ve already defined our two functions, all we have to do is call them and pass them the right arguments. ([Location 3984](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3984)) - This program is easier to extend and maintain than the version without functions. If we need to print more designs later on, we can simply call print_models() again. ([Location 3989](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=3989)) - The slice notation [:] makes a copy of the list to send to the function. If we didn’t want to empty the list of unprinted designs in printing_models.py, we could call print_models() like this: ([Location 4005](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4005)) - The function in the following example has one parameter, *toppings, but this parameter collects as many arguments as the calling line provides: ([Location 4029](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4029)) - The asterisk in the parameter name *toppings tells Python to make an empty tuple called toppings and pack whatever values it receives into this tuple. ([Location 4033](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4033)) - Sometimes you’ll want to accept an arbitrary number of arguments, but you won’t know ahead of time what kind of information will be passed to the function. In this case, you can write functions that accept as many key-value pairs as the calling statement provides. One example involves building user profiles: you know you’ll get information about a user, but you’re not sure what kind of information you’ll receive. ([Location 4063](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4063)) - The definition of build_profile() expects a first and last name, and then it allows the user to pass in as many name-value pairs as they want. The double asterisks before the parameter **user_info cause Python to create an empty dictionary called user_info and pack whatever name-value pairs it receives into this dictionary. Within the function, you can access the name-value pairs in user_info just as you would for any dictionary. ([Location 4077](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4077)) - One advantage of functions is the way they separate blocks of code from your main program. By using descriptive names for your functions, your main program will be much easier to follow. You can go a step further by storing your functions in a separate file called a module and then importing that module into your main program. An import statement tells Python to make the code in a module available in the currently running program file. ([Location 4110](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4110)) - To start importing functions, we first need to create a module. A module is a file ending in .py that contains the code you want to import into your program. ([Location 4119](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4119)) - When Python reads this file, the line import pizza tells Python to open the file pizza.py and copy all the functions from it into this program. ([Location 4130](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4130)) - If the name of a function you’re importing might conflict with an existing name in your program or if the function name is long, you can use a short, unique alias—an alternate name similar to a nickname for the function. You’ll give the function this special nickname when you import the function. Here we give the function make_pizza() an alias, mp(), by importing make_pizza as mp. The as keyword renames a function using the alias you provide: from pizza import make_pizza as mp ([Location 4155](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4155)) - You can also provide an alias for a module name. Giving a module a short alias, like p for pizza, allows you to call the module’s functions more quickly. Calling p.make_pizza() is more concise than calling pizza.make_pizza(): import pizza as p ([Location 4170](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4170)) - You can tell Python to import every function in a module by using the asterisk (*) operator: from pizza import * ([Location 4183](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4183)) - You need to keep a few details in mind when you’re styling functions. Functions should have descriptive names, and these names should use lowercase letters and underscores. ([Location 4195](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4195)) - Object-oriented programming is one of the most effective approaches to writing software. In object-oriented programming you write classes that represent real-world things and situations, and you create objects based on these classes. ([Location 4253](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4253)) - When you write a class, you define the general behavior that a whole category of objects can have. ([Location 4254](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4254)) - Making an object from a class is called instantiation, and you work with instances of a class. ([Location 4257](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4257)) - Each instance created from the Dog class will store a name and an age, and we’ll give each dog the ability to sit() and roll_over() ([Location 4273](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4273)) - At ➋ we write a docstring describing what this class does. The __init__() Method A function that’s part of a class is a method. Everything you learned about functions applies to methods as well; the only practical difference for now is the way we’ll call methods. The __init__() method at ➌ is a special method Python runs automatically whenever we create a new instance based on the Dog class. This method has two leading underscores and two trailing underscores, a convention that helps prevent Python’s default method names from conflicting with your method names. ([Location 4289](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4289)) - We define the __init__() method to have three parameters: self, name, and age. The self parameter is required in the method definition, and it must come first before the other parameters. ([Location 4295](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4295)) - The two variables defined at ➍ each have the prefix self. Any variable prefixed with self is available to every method in the class, and we’ll also be able to access these variables through any instance created from the class. ([Location 4307](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4307)) - The Dog class has two other methods defined: sit() and roll_over() ➎. Because these methods don’t need additional information like a name or age, we just define them to have one parameter, self. The instances we create later will have access to these methods. ([Location 4314](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4314)) - Working with Classes and Instances You can use classes to represent many real-world situations. Once you write a class, you’ll spend most of your time working with instances created from that class. One of the first tasks you’ll want to do is modify the attributes associated with a particular instance. You can modify the attributes of an instance directly or write methods that update attributes in specific ways. ([Location 4403](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4403)) - Every attribute in a class needs an initial value, even if that value is 0 or an empty string. ([Location 4436](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4436)) - You can change an attribute’s value in three ways: you can change the value directly through an instance, set the value through a method, or increment the value (add a certain amount to it) through a method. Let’s look at each of these approaches. ([Location 4461](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4461)) - You don’t always have to start from scratch when writing a class. If the class you’re writing is a specialized version of another class you wrote, you can use inheritance. When one class inherits from another, it automatically takes on all the attributes and methods of the first class. The original class is called the parent class, and the new class is the child class. The child class inherits every attribute and method from its parent class but is also free to define new attributes and methods of its own. ([Location 4552](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4552)) - The super() function at ➍ is a special function that helps Python make connections between the parent and child class. This line tells Python to call the __init__() method from ElectricCar’s parent class, which gives an ElectricCar instance all the attributes of its parent class. The name super comes from a convention of ([Location 4592](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4592)) - calling the parent class a superclass and the child class a subclass. ([Location 4596](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4596)) - When we want to describe the battery, we need to work through the car’s battery attribute: my_tesla.battery.describe_battery() This line tells Python to look at the instance my_tesla, find its battery attribute, and call the method describe_battery() that’s associated with the Battery instance stored in the attribute. ([Location 4699](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4699)) - Let’s create a module containing just the Car class. This brings up a subtle naming issue: we already have a file named car.py in this chapter, but this module should be named car.py because it contains code representing a car. ([Location 4772](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4772)) - At ➊ we include a module-level docstring that briefly describes the contents of this module. You should write a docstring for each module you create. Now we make a separate file called my_car.py. This file will import the Car class and then create an instance from that class: ([Location 4805](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4805)) - A few styling issues related to classes are worth clarifying, especially as your programs become more complicated. Class names should be written in CamelCaps. To do this, capitalize the first letter of each word in the name, and don’t use underscores. Instance and module names should be written in lowercase with underscores between words. ([Location 4984](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=4984)) - The open() function needs one argument: the name of the file you want to open. Python looks for this file in the directory where the program that’s currently being executed is stored. ([Location 5033](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=5033)) - The keyword with closes the file once access to it is no longer needed. Notice how we call open() in this program but not close(). You could open and close the file by calling open() and close(), but if a bug in your program prevents the close() statement from being executed, the file may never close. ([Location 5038](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=5038)) - Once we have a file object representing pi_digits.txt, we use the read() method in the second line of our program to read the entire contents of the file and store it as one long string in contents. ([Location 5047](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=5047)) - Recall that Python’s rstrip() method removes, or strips, any whitespace characters from the right side of a string. Now the output matches the contents of the original file exactly: ([Location 5057](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=5057)) - When you’re reading a file, you’ll often want to examine each line of the file. You might be looking for certain information in the file, or you might want to modify the text in the file in some way. ([Location 5094](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=5094)) - At ➊ we store the name of the file we’re reading from in the variable filename. This is a common convention when working with files. Because the variable filename doesn’t represent the actual file—it’s just a string telling Python where to find the file—you can easily swap out 'pi_digits.txt' for the name of another file you want to work with. After we call open(), an object representing the file and its contents is stored in the variable file_object ➋. We again use the with syntax to let Python open and close the file properly. To examine the file’s contents, we work through each line in the file by looping over the file object ➌ ([Location 5103](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=5103)) - These blank lines appear because an invisible newline character is at the end of each line in the text file. The print statement adds its own newline each time we call it, so we end up with two newline characters at the end of each line: one from the file and one from the print statement. Using rstrip() on each line in the print statement eliminates these extra blank lines: ([Location 5112](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=5112)) - Python uses special objects called exceptions to manage errors that arise during a program’s execution. Whenever an error occurs that makes Python unsure what to do next, it creates an exception object. ([Location 5273](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=5273)) - Of course Python can’t do this, so we get a traceback:    Traceback (most recent call last):      File "division.py", line 1, in <module>        print(5/0) ➊ ZeroDivisionError: division by zero The error reported at ➊ in the traceback, ZeroDivisionError, is an exception object. ([Location 5284](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=5284)) - When you think an error may occur, you can write a try-except block to handle the exception that might be raised. You tell Python to try running some code, and you tell it what to do if the code results in a particular kind of exception. Here’s what a try-except block for handling the ZeroDivisionError exception looks like: try:     print(5/0) except ZeroDivisionError:     print("You can't divide by zero!") We put print(5/0), the line that caused the error, inside a try block. If the code in a try block works, Python skips over the except block. If the code in the try block causes an error, Python looks for an except block whose error matches the one that was raised and runs the code in that block. ([Location 5292](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=5292)) - One common issue when working with files is handling missing files. The file you’re looking for might be in a different location, the filename may be misspelled, or the file may not exist at all. You can handle all of these situations in a straightforward way with a try-except block. ([Location 5368](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=5368)) - Many of your programs will ask users to input certain kinds of information. You might allow users to store preferences in a game or provide data for a visualization. Whatever the focus of your program is, you’ll store the information users provide in data structures such as lists and dictionaries. When users close a program, you’ll almost always want to save the information they entered. A simple way to do this involves storing your data using the json module. The json module allows you to dump simple Python data structures into a file and load the data from that file the next time the program runs. ([Location 5516](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=5516)) - Often, you’ll come to a point where your code will work, but you’ll recognize that you could improve the code by breaking it up into a series of functions that have specific jobs. This process is called refactoring. Refactoring makes your code cleaner, easier to understand, and easier to extend. We can refactor remember_me.py by moving the bulk of its logic into one or more functions. The focus of remember_me.py is on greeting the user, so let’s move all of our existing code into a function called greet_user() ([Location 5602](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=5602)) - First, we import unittest and the function we want to test, get_formatted_name(). At ➊ we create a class called NamesTestCase, which will contain a series of unit tests for get_formatted_name(). You can name the class anything you want, but it’s best to call it something related to the function you’re about to test and to use the word Test in the class name. This class must inherit from the class unittest.TestCase so Python knows how to run the tests you write. ([Location 5742](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=5742)) - Python provides a number of assert methods in the unittest.TestCase class. As mentioned earlier, assert methods test whether a condition you believe is true at a specific point in your code is indeed true. If the condition is true as expected, your assumption about how that part of your program behaves is confirmed; you can be confident that no errors exist. If the condition you assume is true is actually not true, Python raises an exception. ([Location 5873](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=5873)) - In test_survey.py we created a new instance of AnonymousSurvey in each test method, and we created new responses in each method. The unittest.TestCase class has a setUp() method that allows you to create these objects once and then use them in each of your test methods. When you include a setUp() method in a TestCase class, Python runs the setUp() method before running each method starting with test_. Any objects created in the setUp() method are then available in each test method you write. ([Location 5995](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=5995)) - First, we import the sys and pygame modules. The pygame module contains the functionality needed to make a game. We’ll use the sys module to exit the game when the player quits. ([Location 6241](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6241)) - The screen object is called a surface. A surface in Pygame is a part of the screen where you display a game element. Each element in the game, like the aliens or the ship, is a surface. ([Location 6251](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6251)) - The game is controlled by a while loop ➌ that contains an event loop and code that manages screen updates. ([Location 6254](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6254)) - Each time we introduce new functionality into our game, we’ll typically introduce some new settings as well. Instead of adding settings throughout the code, let’s write a module called settings that contains a class called Settings to store all the settings in one place. ([Location 6294](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6294)) - The safest and cheapest way to start is to use freely licensed graphics that you can modify from a website like http://pixabay.com/. ([Location 6330](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6330)) - You can use almost any type of image file in your game, but it’s easiest if you use a bitmap (.bmp) file because Pygame loads bitmaps by default. ([Location 6332](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6332)) - First, we import the pygame module. The __init__() method of Ship takes two parameters: the self reference and the screen where we’ll draw the ship. To load the image, we call pygame.image.load() ➊. This function returns a surface representing the ship, which we store in self.image. ([Location 6359](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6359)) - Once the image is loaded, we use get_rect() to access the surface’s rect attribute ➋. One reason Pygame is so efficient is that it lets you treat game elements like rectangles (rects), even if they’re not exactly shaped like rectangles. ([Location 6364](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6364)) - When working with a rect object, you can use the x- and y-coordinates of the top, bottom, left, and right edges of the rectangle, as well as the center. ([Location 6368](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6368)) - In Pygame, the origin (0, 0) is at the top-left corner of the screen, and coordinates increase as you go down and to the right. ([Location 6379](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6379)) - We draw the ship onscreen by calling ship.blitme() after filling the background, so the ship appears on top of the background ➋ ([Location 6410](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6410)) - In larger projects, you’ll often refactor code you’ve written before adding more code. Refactoring simplifies the structure of the code you’ve already written, making it easier to build on. ([Location 6416](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6416)) - We’ll start by moving the code that manages events to a separate function called check_events(). This will simplify run_game() and isolate the event management loop. Isolating the event loop allows you to manage events separately from other aspects of the game, like updating the screen. ([Location 6421](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6421)) - We no longer need to import sys directly into the main program file, because it’s only being used in the game_functions module now. ([Location 6441](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6441)) - Because we wanted to start out working with code in a single file, we didn’t introduce the game_functions module right away. This approach gives you an idea of a realistic development process: you start out writing your code as simply as possible, and refactor it as your project becomes more complex. ([Location 6466](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6466)) - When a KEYDOWN event is detected, we need to check whether the key that was pressed is one that triggers a certain event. For example, if the right arrow key is pressed, we increase the ship’s rect.centerx value to move the ship to the right: ([Location 6481](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6481)) - We give the check_events() function a ship parameter, because the ship needs to move to the right when the right arrow key is pressed. ([Location 6493](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6493)) - We’ll have our game detect a pygame.KEYUP event so we’ll know when the right arrow key is released; then we’ll use the KEYDOWN and KEYUP events together with a flag called moving_right to implement continuous motion. ([Location 6508](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6508)) - At ➊, we modify how the game responds when the player presses the right arrow key: instead of changing the ship’s position directly, we merely set moving_right to True. At ➋, we add a new elif block, which responds to KEYUP events. ([Location 6550](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6550)) - Finally, we modify the while loop in alien_invasion.py so it calls the ship’s update() method on each pass through the loop: ([Location 6556](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6556)) - The ship’s position will update after we’ve checked for keyboard events and before we update the screen. This allows the ship’s position to be updated in response to player input and ensures the updated position is used when drawing the ship to the screen. ([Location 6561](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6561)) - In __init__(), we add a self.moving_left flag. In update(), we use two separate if blocks rather than an elif in update() to allow the ship’s rect.centerx value to be increased and then decreased if both arrow keys are held down. ([Location 6576](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6576)) - If a KEYDOWN event occurs for the K_LEFT key, we set moving_left to True. If a KEYUP event occurs for the K_LEFT key, we set moving_left to False. ([Location 6596](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6596)) - Currently, the ship moves one pixel per cycle through the while loop, but we can take finer control of the ship’s speed by adding a ship_speed_factor attribute to the Settings class. ([Location 6605](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6605)) - At ➊, we add ai_settings to the list of parameters for __init__(), so the ship will have access to its speed setting. ([Location 6642](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6642)) - Now any value of ship_speed_factor greater than one will make the ship move faster. ([Location 6665](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=6665)) - In this chapter you’ll learn how to write a self-contained program to generate a visualization based on data that it retrieves. Your program will use a web application programming interface (API) to automatically request specific information from a website rather than entire pages. ([Location 9619](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=9619)) - The API returns the information in JSON format, so we use the json() method ➎ to convert the information to a Python dictionary. We store the resulting dictionary in response_dict. Finally, we print the keys from response_dict and see this: Status code: 200 dict_keys(['items', 'total_count', 'incomplete_results']) Because the status code is 200, we know that the request was successful. ([Location 9680](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=9680)) - GitHub’s API returns a lot of information about each repository: there are 68 keys in repo_dict ➊. When you look through these keys, you’ll get a sense of the kind of information you can extract about a project. (The only way to know what information is available through an API is to read the documentation or to examine the information through code, as we’re doing here.) ([Location 9720](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=9720)) - Let’s refine the styling of our chart. We’ll be making a few different customizations, so first restructure the code slightly by creating a configuration object that contains all of our customizations to pass to Bar(): ([Location 9828](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=9828)) - We set up an empty list called submission_dicts at ➌ to store these dictionaries. We then loop through the IDs of the top 30 submissions. We make a new API call for each submission by generating a URL that includes the current value of submission_id ➍. We print the status of each request so we can see whether it is successful. ([Location 9973](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=9973)) - A full spec details the project goals, describes the project’s functionality, and discusses its appearance and user interface. Like any good project or business plan, a spec should keep you focused and help keep your project on track. We won’t write a full project spec here, but we’ll lay out a few clear goals to keep our development process focused. Here’s the spec we’ll use: We’ll write a web app called Learning Log that allows users to log the topics they’re interested in and to make journal entries as they learn about each topic. The Learning Log home page should describe the site and invite users to either register or log in. Once logged in, a user should be able to create new topics, add new entries, and read and edit existing entries. ([Location 10030](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10030)) - A virtual environment is a place on your system where you can install packages and isolate them from all other Python packages. Separating one project’s libraries from other projects is beneficial and will be necessary when we deploy Learning Log to a server in Chapter 20 ([Location 10039](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10039)) - Because we’re working in a virtual environment, this command is the same on all systems. ([Location 10082](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10082)) - The command at ➊ tells Django to set up a new project called learning_log. The dot at the end of the command creates the new project with a directory structure that will make it easy to deploy the app to a server when we’re finished developing it. ([Location 10092](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10092)) - Running the ls command (dir on Windows) ➋ shows that Django has created a new directory called learning_log. It also created a file called manage.py, which is a short program that takes in commands and feeds them to the relevant part of Django to run them. ([Location 10098](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10098)) - The learning_log directory contains four files ➌, the most important of which are settings.py, urls.py, and wsgi.py. The settings.py file controls how Django interacts with your system and manages your project. We’ll modify a few of these settings and add some settings of our own as the project evolves. The urls.py file tells Django which pages to build in response to browser requests. The wsgi.py file helps Django serve the files it creates. The filename is an acronym for web server gateway interface. ([Location 10102](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10102)) - Any time we modify a database, we say we’re migrating the database. Issuing the migrate command for the first time tells Django to make sure the database matches the current state of the project. ([Location 10115](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10115)) - Django starts a server so you can view the project on your system to see how well it works. When you request a page by entering a URL in a browser, the Django server responds to that request by building the appropriate page and sending that page to the browser. ([Location 10129](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10129)) - The command startapp appname tells Django to create the infrastructure needed to build an app. If you look in the project directory now, you’ll see a new folder called learning_logs ➊. Open that folder to see what Django has created ➋. The most important files are models.py, admin.py, and views.py. We’ll use models.py to define the data we want to manage in our app. We’ll get to admin.py and views.py a little later. ([Location 10163](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10163)) - A module called models is being imported for us, and we’re being invited to create models of our own. A model tells Django how to work with the data that will be stored in the app. Code-wise, a model is just a class; it has attributes and methods, just like every class we’ve discussed. Here’s the model for the topics users will store: ([Location 10173](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10173)) - We’ve created a class called Topic, which inherits from Model—a parent class included in Django that defines the basic functionality of a model. Only two attributes are in the Topic class: text and date_added. The text attribute is a CharField—a piece of data that’s made up of characters, or text ➊. ([Location 10182](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10182)) - Grouping apps together in a project helps to keep track of them as the project grows to include more apps. Here we start a section caled My apps, which includes only learning_logs for now. ([Location 10220](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10220)) - The command makemigrations tells Django to figure out how to modify the database so it can store the data associated with any new models we’ve defined. The output here shows that Django has created a migration file called 0001_initial.py. This migration will create a table for the model Topic in the database. ([Location 10226](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10226)) - Django allows you to create a user who has all privileges available on the site, called a superuser. A privilege controls the actions a user can take. The most restrictive privilege settings allow a user to only read public information on the site. ([Location 10243](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10243)) - The Entry class inherits from Django’s base Model class, just as Topic did ➊. The first attribute, topic, is a ForeignKey instance ➋. A foreign key is a database term; it’s a reference to another record in the database. This is the code that connects each entry to a specific topic. Each topic is assigned a key, or ID, when it’s created. When Django needs to establish a connection between two pieces of data, it uses the key associated with each piece of information. We’ll use these connections shortly to retrieve all the entries associated with a certain topic. ([Location 10306](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10306)) - At ➍ we nest the Meta class inside our Entry class. Meta holds extra information for managing a model; here it allows us to set a special attribute telling Django to use Entries when it needs to refer to more than one entry. ([Location 10316](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10316)) - When you click Save, you’ll be brought back to the main admin page for entries. Here you’ll see the benefit of using text[:50] as the string representation for each entry; it’s much easier to work with multiple entries in the admin interface if you see only the first part of an entry rather than the entire text of each entry. ([Location 10348](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10348)) - The command python manage.py shell (run in an active virtual environment) launches a Python interpreter that you can use to explore the data stored in your project’s database. ([Location 10364](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10364)) - We can loop over a queryset just as we’d loop over a list. Here’s how you can see the ID that’s been assigned to each topic object: ([Location 10370](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10370)) - We store the queryset in topics, and then print each topic’s id attribute and the string representation of each topic. ([Location 10374](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10374)) - To get data through a foreign key relationship, you use the lowercase name of the related model followed by an underscore and the word set ➊ ([Location 10387](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10387)) - We’ll use this kind of syntax when we begin to code the pages users can request. The shell is very useful for making sure your code retrieves the data you want it to. If your code works as you expect it to in the shell, you can expect it to work properly in the files you write within your project. If your code generates errors or doesn’t retrieve the data you expect it to, it’s much easier to troubleshoot your code in the simple shell environment than it is within the files that generate web pages. ([Location 10393](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10393)) - To make it clear which urls.py we’re working in, we add a docstring at the beginning of the file ➊. We then import the url function, which is needed when mapping URLs to views ➋. We also import the views module ➌; the dot tells Python to import views from the same directory as the current urls.py module. The variable urlpatterns in this module is a list of individual pages that can be requested from the learning_logs app ➍ ([Location 10457](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10457)) - A template sets up the structure for a web page. The template defines what the page should look like, and Django fills in the relevant data each time the page is requested. A template allows you to access any data provided by the view. Because our view for the home page provided no data, this template is fairly simple. ([Location 10497](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10497)) - When building a website, you’ll almost always require some elements to be repeated on each page. Rather than writing these elements directly into each page, you can write a base template containing the repeated elements and then have each page inherit from the template. This approach lets you focus on developing the unique aspects of each page and makes it much easier to change the overall look and feel of the project. ([Location 10527](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10527)) - We’ll start by creating a template called base.html in the same directory as index.html. This file will contain elements common to all pages; every other template will inherit from base.html. ([Location 10531](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10531)) - The first part of this file creates a paragraph containing the name of the project, which also acts as a link to the home page. To generate a link, we use a template tag, indicated by braces and percent signs {% %}. ([Location 10537](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10537)) - At ➋ we insert a pair of block tags. This block, named content, is a placeholder; the child template will define the kind of information that goes in the content block. ([Location 10549](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10549)) - If you compare this to the original index.html, you can see that we’ve replaced the Learning Log title with the code for inheriting from a parent template ➊. A child template must have an {% extends %} tag on the first line to tell Django which parent template to inherit from. ([Location 10562](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10562)) - We start by using the {% extends %} tag to inherit from base.html, just as the index template does, and then open a content block. The body of this page contains a bulleted list of the topics that have been entered. In standard HTML, a bulleted list is called an unordered list, indicated by the tags <ul></ul>. We begin the bulleted list of topics at ([Location 10629](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10629)) - Inside the loop, we want to turn each topic into an item in the bulleted list. To print a variable in a template, wrap the variable name in double braces. The code {{ topic }} at ➌ will be replaced by the value of topic on each pass through the loop. The braces won’t appear on the page; they just indicate to Django that we’re using a template variable. The HTML tag <li></li> indicates a list item. ([Location 10642](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10642)) - Next, we need to create a page that can focus on a single topic, showing the topic name and all the entries for that topic. We’ll again define a new URL pattern, write a view, and create a template. We’ll also modify the topics page so each item in the bulleted list links to its corresponding topic page. ([Location 10663](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10663)) - The simplest version of a ModelForm consists of a nested Meta class telling Django which model to base the form on and which fields to include in the form. At ➋ we build a form from the Topic model and include only the text field ➌. The code at ➍ tells Django not to generate a label for the text field. ([Location 10791](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10791)) - The new_topic() function needs to handle two different situations: initial requests for the new_topic page (in which case it should show a blank form) and the processing of any data submitted in the form. It then needs to redirect the user back to the topics page: ([Location 10805](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10805)) - We import the class HttpResponseRedirect, which we’ll use to redirect the reader back to the topics page after they submit their topic. The reverse() function determines the URL from a named URL pattern, meaning that Django will generate the URL when the page is requested. We also import the form we just wrote, TopicForm. ([Location 10823](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10823)) - The two main types of request you’ll use when building web apps are GET requests and POST requests. You use GET requests for pages that only read data from the server. You usually use POST requests when the user needs to submit information through a form. ([Location 10827](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10827)) - The test at ➊ determines whether the request method is GET or POST. If the request method is not POST, the request is probably GET, so we need to return a blank form (if it’s another kind of request, it’s still safe to return a blank form). ([Location 10833](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10833)) - We can’t save the submitted information in the database until we’ve checked that it’s valid ➍. The is_valid() function checks that all required fields have been filled in (all fields in a form are required by default) and that the data entered matches the field types expected—for example, that the length of text is less than 200 characters, as we specified in models.py in Chapter 18. ([Location 10843](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10843)) - Django uses the template tag {% csrf_token %} ➋ to prevent attackers from using the form to gain ([Location 10865](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10865)) - unauthorized access to the server (this kind of attack is called a cross-site request forgery). ([Location 10866](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10866)) - The as_p modifier tells Django to render all the form elements in paragraph format, which is a simple way to display the form neatly. ([Location 10869](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10869)) - We first update the import statement to include Entry as well as Topic. The new class EntryForm inherits from forms.ModelForm and has a nested Meta class listing the model it’s based on and the field to include in the form. We again give the field 'text' a blank label ([Location 10894](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10894)) - At ➋ we include the widgets attribute. A widget is an HTML form element, such as a single-line text box, multi-line text area, or drop-down list. By including the widgets attribute you can override Django’s default widget choices. By telling Django to use a forms.Textarea element, we’re customizing the input widget for the field 'text' so the text area will be 80 columns wide instead of the default 40. This will give users enough room to write a meaningful entry. ([Location 10899](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10899)) - This URL pattern matches any URL with the form http://localhost:8000/new_entry/id/, where id is a number matching the topic ID. The code (?P<topic_id>\d+) captures a numerical value and stores it in the variable topic_id. ([Location 10911](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10911)) - We update the import statement to include the EntryForm we just made. The definition of new_entry() has a topic_id parameter to store the value it receives from the URL. ([Location 10937](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10937)) - When we call save(), we include the argument commit=False ➎ to tell Django to create a new entry object and store it in new_entry without saving it to the database yet. ([Location 10947](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10947)) - At ➐ we redirect the user to the topic page. The reverse() call requires two arguments—the name of the URL pattern we want to generate a URL for and an args list containing any arguments that need to be included in the URL. ([Location 10953](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=10953)) - We first need to import the Entry model. At ➊ we get the entry object that the user wants to edit and the topic associated with this entry. In the if block, which runs for a GET request, we make an instance of EntryForm with the argument instance=entry ➋. This argument tells Django to create the form prefilled with information from the existing entry object. The user will see their existing data and be able to edit that data. When processing a POST request, we pass the instance=entry argument and the data=request.POST argument ➌ to tell Django to create a form instance based on the information associated with the existing entry object, updated with any relevant data from request.POST. We then check if the form is valid; if it is, we call save() with no arguments ➍. We then redirect to the topic page ➎, where the user should see the updated version of the entry they edited. ([Location 11015](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11015)) - We first import the default login view ➊. The login page’s pattern matches the URL http://localhost:8000/users/login/ ➋. When Django reads this URL, the word users tells Django to look in users/urls.py, and login tells it to send requests to Django’s default login view (notice the view argument is login, not views.login). Because we’re not writing our own view function, we pass a dictionary telling Django where to find the template we’re about to write. This template will be part of the users app, not the learning_logs app. ([Location 11101](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11101)) - If the form’s errors attribute is set, we display an error message ➊, reporting that the username and password combination don’t match anything stored in the database. We want the login view to process the form, so we set the action argument as the URL of the login page ➋. The login view sends a form to the template, and it’s up to us to display the form ➌ and add a submit button ➍. At ➎ we include a hidden form element, 'next'; the value argument tells Django where to redirect the user after they’ve logged in successfully. In this case, we send the user back to the home page. ([Location 11121](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11121)) - We import the logout() function from django.contrib.auth ➊. In the function, we call logout() ➋, which requires the request object as an argument. We then redirect to the home page ➌. ([Location 11172](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11172)) - We first import the render() function. We then import the login() and authenticate() functions to log in the user if their registration information is correct. We also import the default UserCreationForm. In the register() function, we check whether or not we’re responding to a POST request. If we’re not, we make an instance of UserCreationForm with no initial data ➊. ([Location 11221](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11221)) - If we’re responding to a POST request, we make an instance of UserCreationForm based on the submitted data ➋. ([Location 11226](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11226)) - When the user’s information is saved, we log them in, which is a two-step process: we call authenticate() with the arguments new_user.username and their password ➎. When they register, the user is asked to enter two matching passwords, and because the form is valid, we know the passwords match so we can use either one. Here we get the value associated with the 'password1' key in the form’s POST data. ([Location 11233](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11233)) - We use the as_p method again so Django will display all the fields in the form appropriately, including any error messages if the form is not filled out correctly. ([Location 11248](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11248)) - Django makes it easy to restrict access to certain pages to logged-in users through the @login_required decorator. A decorator is a directive placed just before a function definition that Python applies to the function before it runs to alter how the function code behaves. Let’s look at an example. ([Location 11275](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11275)) - We first import the login_required() function. We apply login_required() as a decorator to the topics() view function by prepending login_required with the @ symbol so Python knows to run the code in login_required() before the code in topics(). ([Location 11286](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11286)) - Now when an unauthenticated user requests a page protected by the @login_required decorator, Django will send the user to the URL defined by LOGIN_URL in settings.py. You can test this setting by logging out of any user accounts and going to the home page. Next, click the Topics link, which should redirect you to the login page. Then log in to any of your accounts, and from the home page click the Topics link again. You should be able to reach the topics page. ([Location 11297](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11297)) - Now we need to connect the data submitted to the user who submitted it. We need to connect only the data highest in the hierarchy to a user, and the lower-level data will follow. For example, in Learning Log, topics are the highest level of data in the app, and all entries are connected to a topic. As long as each topic belongs to a specific user, we’ll be able to trace the ownership of each entry in the database. We’ll modify the Topic model by adding a foreign key relationship to a user. We’ll then have to migrate the database. Finally, we’ll have to modify some of the views so they only show the data associated with the currently logged-in user. ([Location 11321](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11321)) - We first import the User model from django.contrib.auth. We then add an owner field to Topic, which establishes a foreign key relationship to the User model. ([Location 11336](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11336)) - We start by issuing the makemigrations command ➊. In the output at ➋, Django indicates that we’re trying to add a required (non-nullable) field to an existing model (topic) with no default value specified. Django gives us two options at ➌: we can provide a default right now, or we can quit and add a default value in models.py. At ➍ we’ve chosen the first option. Django then asks us to enter the default value ➎. To associate all existing topics with the original admin user, ll_admin, I entered the user ID of 1 at ➏. You can use the ID of any user you’ve created; it doesn’t have to be a superuser. Django then migrates the database using this value and generates the migration file 0003_topic_owner.py, which adds the field owner to the Topic model. ([Location 11365](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11365)) - When a user is logged in, the request object has a request.user attribute set that stores information about the user. The code fragment Topic.objects.filter(owner=request.user) tells Django to retrieve only the Topic objects from the database whose owner attribute matches the current user. Because we’re not changing how the topics are displayed, we don’t need to change the template for the topics page at all. ([Location 11406](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11406)) - A 404 response is a standard error response that’s returned when a requested resource doesn’t exist on a server. Here we import the Http404 exception ➊, which we’ll raise if the user requests a topic they shouldn’t see. ([Location 11430](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11430)) - When we first call form.save(), we pass the commit=False argument because we need to modify the new topic before saving it to the database ➊. We then set the new topic’s owner attribute to the current user ➋. Finally, we call save() on the topic instance just defined ➌. Now the topic has all the required data and will save successfully. ([Location 11475](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11475)) - For the styling we’ll use the Bootstrap library, a collection of tools for styling web applications so they look professional on all modern devices, from a large flat-screen monitor to a smartphone. ([Location 11507](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11507)) - We need django-bootstrap3 to include jQuery, a JavaScript library that enables some of the interactive elements that the Bootstrap template ([Location 11534](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11534)) - The head of an HTML file doesn’t contain any content: it just tells the browser what it needs to know to display the page correctly. ([Location 11565](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11565)) - At ➐ we place a second list of navigation links, this time using the selector navbar-right. The navbar-right selector styles the set of links so it appears at the right edge of the navigation bar where you typically see login and registration links. Here we’ll display the user greeting and logout link or links to register or log in. The rest of the code in this section closes out the elements that contain the navigation bar ➑. ([Location 11617](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11617)) - At ➊ is an opening div with the class container. A div is a section of a web page that can be used for any purpose and can be styled with a border, space around the element (margins), space between the contents and the border (padding), background colors, and other style rules. This particular div acts as a container into which we place two elements: a new block called header ➋ and the content block we used in Chapter 18 ➌. The header block contains information telling the user what kind of information the page holds and what they can do on a page. It has the class page-header, which applies a set of style rules to the block. The content block is in a separate div with no specific style classes. ([Location 11631](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11631)) - The package dj-database-url helps Django communicate with the database Heroku uses, dj-static and static3 help Django manage static files correctly, and gunicorn is a server capable of serving apps in a live environment. (Static files contain style rules and JavaScript files.) ([Location 11798](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11798)) - Next, we need to add psycopg2, which helps Heroku manage the live database, to the list of packages. Open requirements.txt and add the line psycopg2>=2.6.1. This will install version 2.6.1 of psycopg2, or a newer version if it’s available: ([Location 11817](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11817)) - At ➊ we use the function getcwd(), which gets the current working directory the file is running from. In a Heroku deployment, the directory is always /app. During the build process, the project runs from a temporary directory that starts with /tmp. In a local deployment, the directory is usually the name of the project folder (learning_log in our case). The if test ensures that the settings in this block apply only when the project is deployed on Heroku. This structure allows us to have one settings file that works for our local development environment as well as the live server. At ➋ we import dj_database_url to help configure the database on Heroku. Heroku uses PostgreSQL (also called Postgres), a more advanced database than SQLite, and these settings configure the project to use Postgres on Heroku. The rest of the settings support HTTPS requests ➌, ensure that Django will serve the project from Heroku’s URL ➍, and set up the project to serve static files correctly on Heroku ➎. ([Location 11859](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11859)) - This line tells Heroku to use gunicorn as a server and to use the settings in learning_log/wsgi.py to launch the app. The log-file flag tells Heroku the kinds of events to log. ([Location 11874](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11874)) - We import Cling, which helps serve static files correctly, and use it to launch the application. This code will work locally as well, so we don’t need to put it in an if block. ([Location 11881](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11881)) - The first time you run heroku local, a number of packages from the Heroku Toolbelt will be installed. The output shows that gunicorn has been started with a process id of 12875 in this example ➊. At ➋ gunicorn is listening for requests on port 5000. In addition, gunicorn has started a worker process (12878) to help it serve requests ➌. Visit http://localhost:5000/ to make sure everything is working; you should see the Learning Log home page, just as it appears when you use the Django server (runserver). Press CTRL-C to stop the processes started by heroku local. You should continue to use runserver for local development. ([Location 11900](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11900)) - Using Git means you can try implementing new features without worrying about breaking your project. ([Location 11915](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11915)) - We don’t need Git to track every file in the project, so we’ll tell Git to ignore some files. Make a file called .gitignore in the folder that contains manage.py. Notice that this filename begins with a dot and has no file extension. Here’s what goes in .gitignore: ([Location 11928](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11928)) - We tell Git to ignore the entire directory ll_env, because we can re-create it automatically at any time. We also don’t track the __pycache__ directory, which contains the .pyc files that are created automatically when Django runs the .py files. We don’t track changes to the local database, because it’s a bad habit: if you’re ever using SQLite on a server, you might accidentally overwrite the live database with your local test database when you push the project to the server. ([Location 11932](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11932)) - At ➊ we issue the git init command to initialize an empty repository in the directory containing Learning Log. At ➋ we use the git add . command, which adds all the files that aren’t being ignored to the repository. (Don’t forget the dot.) At ➌ we issue the command git commit -am commit message: the -a flag tells Git to include all changed files in this commit, and the -m flag tells Git to record a log message. Issuing the git status command ➍ indicates that we’re on the master branch and that our working directory is clean. This is the status you’ll want to see any time you push your project to Heroku. ([Location 11951](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11951)) - Then tell Heroku to build an empty project ➋. Heroku generates a name made up of two words and a number; you can change this later on. We then issue the command git push heroku master ➌, which tells Git to push the master branch of the project to the repository Heroku just created. Heroku then builds the project on its servers using these files. At ➍ is the URL we’ll use to access the live project. When you’ve issued these commands, the project is deployed but not fully configured. To check that the server process started correctly, use the heroku ps command: ([Location 11974](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11974)) - The output shows how much more time the project can be active in the next 24 hours ➊. At the time of this writing, Heroku allows free deployments to be active for up to 18 hours in any 24-hour period. If a project exceeds these limits, a standard server error page will be displayed; we’ll customize this error page shortly. At ➋ we see that the process defined in Procfile has been started. ([Location 11984](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=11984)) - We first issue the command heroku run python manage.py migrate ➊. Heroku then creates a terminal session to run the migrate command ➋. At ➌ Django applies the default migrations and the migrations we generated during the development of Learning Log. ([Location 12008](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=12008)) - You’ve already seen that we can run one-off commands using the heroku run command. But you can also run commands by opening a Bash terminal session while connected to the Heroku server using the command heroku run bash. Bash is the language that runs in many Linux terminals. We’ll use the Bash terminal session to create a superuser so we can access the admin site on the live app: ([Location 12020](https://readwise.io/to_kindle?action=open&asin=B018UXJ9RI&location=12020))