<jupyter_start><jupyter_text>SLU15 | Debugging*** PART 1 | Principles/best practices to write good code to avoid bugs/problems: PART 2 | Debugging strategies and tips: PART 3 | Exception types:- SyntaxError- NameError- AttributeError- TypeError- IndexError***  IntroOften, programmers (also data scientists, engineers and whoever writes code) have difficulties understanding why some part of their program doesn't work as expected, why some errors appear, and what to do with them.The main purpose of this notebook is to give you a brief introduction how you can think and what techniques you can use in such a situation.  PART 1 | Principles/best practices to write good code to avoid bugs/problems:There are a few general suggestions that you can use to make your life simpler.  **Divide your code into function and modules**As soon as you create some part of code that does a particular piece of logic, create a function to abstract it.The main reason behind this is that you always have some main part of code that you're working on, and you want to keep it as easy to understand as possible. Let's say that we want to implement the famous FizzBuzz problem:Write a program that prints the numbers from 1 to n. But for multiples of three print “Fizz” instead of the number, and for the multiples of five print “Buzz”. For numbers that are multiples of both three and five print “FizzBuzz”.n is user input. We need to make sure that n is an integer and that it's higher than 1 and lower than 1000.And let's also modify the problem a little bit: instead of printing, we need to create a list of numbers or fizzbuzzes.And only at the end, we want to print the whole list.Take a look at the code below and tell me which option is easier to understand:```n = input()assert isinstance(n, int), "Not an integer."assert n > 1, "Too small"assert n < 1000, "Too big"fizzbuzz_list = []for i in range(1, n+1):    if i % 3 == 0 and i % 5 == 0:        fizzbuzz_list.append("fizzbuzz")    elif i % 3 == 0:        fizzbuzz_list.append("fizz")    elif i % 5 == 0:        fizzbuzz_list.append("buzz")    else:        fizzbuzz_list.append(i)print(fuzzbuzz_list)```VS```n = input()validate_input(n)fizzbuzz_list = create_fizzbuzz_list(n)print(fuzzbuzz_list)```Of course, we'd still need to implement all the logic in the `validate_input` and `create_fizzbuzz_list` functions, but it's much easier to understand the logic of the code this way.Besides that, if we want to modify our program, it is much easier to make no mistakes if we need to make changes in just one of the functions we developed, and not the whole code.  **Try to understand each line of the code that you write, what’s the expected input and output.**We know it's difficult when you just start learning to program, but it will become easier with time, especially when you deal with your own code (and not something written years ago by someone else).Try to read the code line by line, google some methods that you are not sure about, google some examples.If you face a new function or method, try to play around with it so that it’s easier to understand how it works.  **Try to keep the code as simple as possible**I know it's obvious, but it's really important.With time you might learn some more advanced methods, and discover how to use unusual methods that solves a particular thing you want to implement in just 1 line of code. But if it's not obvious how it works, you'll have even more difficulties understanding it after years. Keep it simple even if it takes longer. You'll get to the more complex methods in time.  PART 2 | Debugging strategies and tips:It's completely okay to have difficulties finding a source of a bug. Everyone knows this feeling, and it's a big part of programming.Here are a couple of tips that could help you while debugging your code.  Read the error. Yes. Read it. Read all of it. Read it again. Comparing to other programming languages, Python produces really nice errors that are easy to understand.Here are a few suggestions how to understand them.1. Read from the bottom to the top.2. The last line contains an Exception type and an error message. Try to understand the message. If you're not familiar with the exception type, try to google it.3. While going through the error (from the bottom to the top), you'll find lots of lines like this:```File "/path/to/file.py", line_number, module_name```This messages includes both the code you created, as well as the source code. Try to find the part of your code that called the exception to understand which code line contains the bug.  Go through the code line by lineIf you don't find the bug by reading the error, try to read your code line by line and make sure that you understand its behavior.If you’re not sure what a particular line does, try to print the variable before and after this line and see it’s type. Print everything you’re not sure about.```print(variable)print(type(variable))```When you get familiar with some IDEs (e.g. Pycharm), you can start using breakpoints that allow you to pause a program execution before any line of the code, take a look at all the variables and their type.As we don't cover Pycharm in this course, we will not dive into this topic for now.Keep Pycharm in the back of your mind for later, I strongly suggest you start using Pycharm debugger when you start developing more advanced programs.  Try to change only one thing at a time. Change one line of code, see if it solves the problem. If not, undo the changes and look for other options. Don't try to change the code in multiple places at the same time, as it's very likely that you'll create even more bugs this way.  Google itFinally, if you were not able to find the problem, try to google it. There is a 99% chance that someone already faced it. Stackoverflow is your best friend.  PART 3 | Errors types.Let's take a look at some of the most common exceptions' types and discuss what to do with them.  SyntaxErrorException caused by not following the proper structure (syntax) of the language.There are a few common mistakes people usually do: Forgetting to add semicolon after if/else/for/while/def<jupyter_code>for i in range(10)
    print(i)<jupyter_output><empty_output><jupyter_text>Misspellings<jupyter_code>fr i in range(10):
    print(i)<jupyter_output><empty_output><jupyter_text>While operating on a string, you forgot to add quotes<jupyter_code>print(hey folks)<jupyter_output><empty_output><jupyter_text>Different number of open and close brackets<jupyter_code>print((10, 20, 30)<jupyter_output><empty_output><jupyter_text>NameErrorException caused by trying to access a variable that doesn't exist. The variable is called before it's declared. In jupyter notebooks it happens pretty often, when a cell that declares the variable is created AFTER the cell that uses this variable<jupyter_code>print(a)
a = 10<jupyter_output><empty_output><jupyter_text>The variable name is misspelled.<jupyter_code>hello_world = "Hello world"

print(hello_word)<jupyter_output><empty_output><jupyter_text>A module with some function is not imported<jupyter_code>pd.DataFrame()<jupyter_output><empty_output><jupyter_text>While operating on a single-word-string, you forgot to add quotes<jupyter_code>print(hello)<jupyter_output><empty_output><jupyter_text>AttributeError These errors usually appear when you're calling a method on a wrong type of object.<jupyter_code>a = 10
a.append(11)<jupyter_output><empty_output><jupyter_text>TypeError  Using a wrong parameter type with a function<jupyter_code>open([])
### Using a wrong number of parameters with a function
def say_hello_world():
    print("Hello world")
say_hello_world(10)
def add_ten(i):
    return i + 10
add_ten()<jupyter_output><empty_output><jupyter_text>IndexErrorIt usually happens when you try to access an element that is out of range in an array.<jupyter_code>nums_list = [10]
print(nums_list[1])<jupyter_output><empty_output><jupyter_text>It often happens in for loops:<jupyter_code>nums_list = [10, 20, 30]
for i in range(4):
    print(nums_list[i])<jupyter_output>10
20
30
{'fraction_non_alphanumeric': 0.060744772980329084, 'fraction_numerical': 0.008783867375974266, 'mean_word_length': 4.909356725146199, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '12', 'dir': 'jupyter-structured-clean-dedup', 'id': '402772', 'license': 'MIT', 'n_tokens_mistral': 2269, 'n_tokens_neox': 2150, 'n_words': 1175, 'path': 'Week 09/SLU15 - Debugging/Learning notebook.ipynb', 'repo_name': 'LDSSA/ds-prep-course-2021', 'size': '8083'}