├── .DS_Store ├── .gitignore ├── beginner_python ├── 01-numbers.py ├── 02-strings.py ├── 03-list-basics.py ├── 04-user-input.py ├── 05-logic-and-if.py ├── 06-loop-basics.py ├── 07-more-looping.py ├── 08-nested-if-for.py ├── 09-nested-loops.py └── 10-functions.py ├── netflix_titles.csv ├── netflix_titles.jpg └── python ├── 01-intro.py ├── 02-lists.py ├── 03-sorting.py ├── 04-basic-io.py ├── 05-2d-lists.py ├── 06-modules.py ├── 07-dictionaries-sets.py ├── 08-oop-basics.py ├── 09-objects-io.py ├── 10-consume-sdk.py ├── 10-sql.py ├── 11-tk-guessing.py ├── 11-tk-list.py ├── book.py ├── booksSDK.py ├── utils.py └── webdev └── books ├── books ├── __init__.py ├── asgi.py ├── settings.py ├── urls.py └── wsgi.py ├── manage.py └── reading ├── __init__.py ├── admin.py ├── apps.py ├── migrations ├── 0001_initial.py └── __init__.py ├── models.py ├── templates └── reading │ ├── index.html │ └── info.html ├── tests.py ├── urls.py └── views.py /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CalebCurry/python/c34766df18e59b1c48f5fcef0ba75a97c2605fc3/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | env 2 | *.DS_Store 3 | *.pyc 4 | __pycache__ 5 | *.db 6 | *.sqlite3 -------------------------------------------------------------------------------- /beginner_python/01-numbers.py: -------------------------------------------------------------------------------- 1 | age = 25 2 | print(age) 3 | 4 | #this is a comment 5 | 6 | age1 = 1 7 | age_2 = 2 8 | #invalid name -> age-3 = 3 9 | #invalid name -> 4age = 4 10 | Age = 6 #not recommended 11 | age_of_user = 7 #recommend underscores for multiple words based on this guide: 12 | #https://www.python.org/dev/peps/pep-0008/#function-and-variable-names 13 | 14 | #return = 5 --> Cannot assign to keywords 15 | #https://docs.python.org/3/reference/lexical_analysis.html#keywords 16 | 17 | ########## OPERATORS ########## 18 | result = 20 / 3 #6.6666.... 19 | print(result) 20 | 21 | print("Here is a floor version (crop decimal):", 20 // 3) #6 22 | 23 | result = 5**2 #raising a number to a power (5^) 24 | print(result) 25 | 26 | #You can use round instead. 27 | print(round(20/3), 0) 28 | 29 | print(result / age) #can use variables in place of literals. This will not change variable values 30 | 31 | #guess the output: 32 | print(20 / 3 + 1) 33 | 34 | #think of it like this because of operator precedence: 35 | print((20 / 3) + 1) 36 | 37 | #You can, however, force certain operations to happen first with () 38 | print(20 / (3 + 1)) 39 | 40 | ######### MODULUS AND POWER ############ 41 | 42 | #5 * 5 * 5 * 5* 5 43 | print(5**5) 44 | 45 | #The remainder of 78 / 11 is 1. 46 | print(78 % 11) 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /beginner_python/02-strings.py: -------------------------------------------------------------------------------- 1 | me = "Caleb" 2 | 3 | #escape character example 4 | print("\n") 5 | 6 | me = "C\ta\tl\te\tb\n" 7 | 8 | print(me) 9 | 10 | #can also use single quotes 11 | you = 'Subscriber' 12 | 13 | me = "Caleb" #reset to normal 14 | 15 | #passing multiple arguments to print 16 | print(me, you) 17 | 18 | #double quotes and single quotes work the same way with the exception of working with quotes inside. 19 | #here are some examples: 20 | 21 | single_quotes = 'She said "Hi"' 22 | print(single_quotes) 23 | 24 | double_quotes = "She said \"Hi\"" 25 | print(double_quotes) 26 | 27 | single_quotes = 'I\'m learning!' 28 | print(single_quotes) 29 | 30 | double_quotes = "I'm learning!" 31 | print(double_quotes) 32 | 33 | #notice we have to escape the same quote as the surrounding quote 34 | 35 | #Here are the other escape sequences: 36 | #https://docs.python.org/2.0/ref/strings.html 37 | 38 | #Notice that if you want to print \ you must put two 39 | print("\\") 40 | 41 | #you can also prefix with r which will make a raw string (ignoring escapes except same quote) 42 | print(r'as raw as I\'ve ever seen. \/\/ () \/\/. \t' ) #only \' is escaped 43 | 44 | 45 | 46 | ########## CONCATENTATION ########## 47 | 48 | #Use a + to concatenate 49 | msg = me + " + " + you 50 | print(msg) 51 | 52 | #Can use comma separated values in print. Automatically uses spaces between 53 | print(me, "+", you) 54 | 55 | #You can automatically concatenate literals (actual values with quotes as opposed to variables) 56 | #by putting them one after the other. This is ideal if you need to split a large string up 57 | #onto multiple lines. 58 | print("my " "name " 59 | "is " "Caleb") 60 | 61 | #You can also use multiline string 62 | print("""Name: Caleb 63 | Age: 58""") 64 | 65 | #skip newline using \ (without it, it would go down a line each line) 66 | print("""\ 67 | Name: Caleb. \ 68 | Age: 58""") 69 | 70 | """You may see 71 | them as multi- 72 | line comments even 73 | if they technically 74 | are not. 75 | https://stackoverflow.com/questions/7696924/is-there-a-way-to-create-multiline-comments-in-python 76 | """ 77 | 78 | ########## INDEXES ########## 79 | 80 | #It's very common to grab particular characters within a string 81 | #this is also common for collections when we get to em. 82 | msg = "This is a very important message." 83 | print(msg[5]) 84 | 85 | #indexing is zero based. This means 0 will get the very first character: 86 | print(msg[0]) 87 | 88 | #This value is returned and can be assigned to a variable or used in an expression 89 | first_letter = msg[0] 90 | print(first_letter + "acos") 91 | 92 | #You can also index from the right. 93 | period = msg[32] #from left 94 | print(period) 95 | period = msg[-1] #from right 96 | print(period) 97 | #This may be obvious, but we do not use -0 to get the first element from the right as we would 98 | #use 0 to get the first element from the left. (Side note) -0 actually is 0: 99 | print(-0) #(side note) 100 | print(0 == -0) #0 == 0 (side note) 101 | 102 | ########## SLICING ######### 103 | 104 | #repeating this for ease of reading: 105 | msg = "This is a very important message." 106 | 107 | #We can pass two numbers in for the index to get a series of characters. 108 | #left is included. Right is excluded. 109 | 110 | #this will get 2 characters (from index 1 - 3 with 3 not included...we are left with index 1 and 2. 111 | print(msg[1:3]) #hi 112 | 113 | #You can also leave off first to start at beginning 114 | #or leave off second to go to end 115 | print(msg[:5]) #print index 0-4 (because 5 is excluded, remember) 116 | print (msg[1:]) #from index 1 to end 117 | 118 | #We can also use negatives. Here is how you get the last 8 characters: 119 | print(msg[-8:]) #start 8 from right and go to end 120 | 121 | #out of range index 122 | #Grabbing an out of range index directly will cause an error. 123 | #But incorrect ranges fail gracefully. 124 | #print(msg[42]) #doesn't work 125 | print(msg[42:43]) #works 126 | 127 | 128 | ########## IMMUTABILITY ########## 129 | 130 | #Strings are immutable, meaning they can't change. 131 | cant_change = "Java is my favorite!" 132 | 133 | #cant_change[0] = K .....nope. Sorry Kava (my dog) 134 | 135 | #generate new string from old: 136 | #Kava is my favorite! 137 | new = 'K' + cant_change[1:] 138 | print(new) 139 | 140 | #Python is my favorite! 141 | fav_language = "Python " + cant_change[5:] 142 | print(fav_language) 143 | 144 | #Java is actually coffee 145 | coffee = cant_change[:8] + "actually coffee" #grab first 7 characters (index 8 not included) 146 | print(coffee) 147 | 148 | #operations that appear to change string actually replace: 149 | #Java is actually coffee (contrary to popular belief). 150 | coffee += " (contrary to popular belief)." 151 | print(coffee) 152 | 153 | ########## GETTING STRING LENGTH ########## 154 | 155 | #There is a function we can use.... 156 | #similar to how we invoke print to do something for us (output to console) 157 | #we can invoke len to count for us: 158 | 159 | print(len(coffee)) 160 | 161 | #for those from other languages... 162 | #notice we do not say coffee.len() 163 | #coffee.len() XXXXXX 164 | #nope. 165 | 166 | #last index is always len() - 1. 167 | name = "Caleb" 168 | print("index 4:", name[4]) #b 169 | print("len(name)", len(name)) #length is 5 170 | 171 | 172 | ########## MORE STRING WORK ########## 173 | 174 | #How to convert a number to a string 175 | length = len(name) 176 | 177 | print("Length is " + str(length)) 178 | 179 | #this works however sometimes you just need one combined string instead of components. 180 | #when we use a comma, we are passing in data as separate arguments. 181 | #fortunately, print knows how to handle it. Other times, we must pass in one string. 182 | #WARNING --> Commas automatically print a space. 183 | print("length is ", length) 184 | 185 | #an example of this is if we need a variable. We cannot use a comma: 186 | 187 | #BAD 188 | msg = "length is", len(name) 189 | print(msg) #NOT WHAT WE WANTED! 190 | 191 | #GOOD 192 | length = len(name) 193 | msg = "length is " + str(length) 194 | print(msg) 195 | 196 | #EVEN BETTER 197 | #We can also nest function calls: 198 | print("length is " + str(len(name))) 199 | #The order in which these are invoked are in to out... 200 | #len(name) is first which returns a number. 201 | #this number is passed to str which converts it to a string 202 | #this string is then concatenated with the string on the left 203 | #this final string is then passed to print 204 | 205 | #That's the end of your introduction to strings! -------------------------------------------------------------------------------- /beginner_python/03-list-basics.py: -------------------------------------------------------------------------------- 1 | #What is a list? 2 | #It's a type of collection. just like what it sounds...It holds numerous things. 3 | 4 | ages = [20, 25, 20] 5 | 6 | #Here is a list of strings 7 | names = ["Caleb", "Emily", "Sabrina"] 8 | 9 | #We can even mix types of data: 10 | my_favorite_things = ["Working out", 7, ["netflix", "Amazon Prime"]] 11 | #Here we have a list of a string, number, and another list. 12 | #We will get into nested lists soon. 13 | 14 | #We can print an entire list by using the list name 15 | print(ages) 16 | print(names) 17 | print(my_favorite_things) 18 | 19 | ######### INDEXING ########## 20 | 21 | #Similar to strings, we can use indexes to grab particular elements 22 | print(ages[2]) #grab 3rd element. 23 | #remember, these are zero based! The first element is index 0. 24 | 25 | #Indexing can also return a list (doesn't modify original list) 26 | print(my_favorite_things[2]) 27 | 28 | ########## UPDATING AND SLICING ########## 29 | #lists are different than strings in that the data can be changed! 30 | #how to update a list element 31 | ages[0] = 5 32 | ages[1] = 10 33 | ages[2] = 15 34 | print(ages) #Updated! 35 | 36 | #What about slicing? 37 | print(ages[1:]) #It works! 38 | #Now all the skills you learned with strings seem more valuable, huh? 39 | 40 | #Since lists are mutable, can we combine slicing with updating data? 41 | 42 | ages[1:] = [6, 7] 43 | print(ages) #MY GOODNESS it worked. 44 | #Confused on what we did? We sliced to get all of the data index 1 and beyond... 45 | #but instead of printing it, we assigned it a new list of 6 and 7. 46 | 47 | 48 | ########## COPYING LISTS ########## 49 | 50 | #You may think copying lists is easy: 51 | names = ["Caleb", "Emily", "Sabrina"] 52 | names2 = names #copied? NOOO 53 | 54 | #The problem here is that they both point to the same list in memory. 55 | #Changes in one are visible in the other 56 | names2[0] = "Kaylub" #Change to names2 57 | print(names) #printing name1 and seeing "Kaylub" 58 | 59 | #This is great if we want an ALIAS! But not if we want a COPY! 60 | #Here is how to copy: 61 | names = ["Caleb", "Emily", "Sabrina"] 62 | names2 = names[:] 63 | #remember slicing doesn't modify the original list. 64 | #leaving no number on the left of : says "All the way from beginning" 65 | #leaving no number on right of : says "All the way to end" 66 | #in other words...[:] returns the whole list. 67 | names2[0] = "Kaylubbbbb" 68 | print(names) #Caleb YAAYYYYY 69 | 70 | #another Option is to use a method on the list...copy() 71 | names1 = ["Caleb", "Emily", "Sabrina"] 72 | names2 = names1.copy() 73 | names2[0] = "Kaylubbbbb" 74 | print(names) #Caleb YAAYYYYY 75 | 76 | #Notice that we say list.copy() instead of copy(list). 77 | #This is called a method instead of a function because it's attached to an object 78 | #We'll get into methods later. 79 | #This is also a shallow copy. Will discuss the difference in a bit. 80 | 81 | ########## NESTED LIST BASICS ########## 82 | 83 | #Earlier we created this list 84 | my_favorite_things = ["Working out", 7, ["netflix", "Amazon Prime"]] 85 | 86 | #The third element is actually a list itself. 87 | #Although we are going to get into nested lists in more detail later on, I wanted to give basics 88 | #Becuase the 3rd element is a list, you can get that list like so: 89 | 90 | streaming = my_favorite_things[2] 91 | print(streaming) 92 | 93 | #You can treat it like a normal list (because it is) 94 | print(streaming[1]) 95 | 96 | #This works, however a more useful way of grabbing an element from a nested list is like so: 97 | print(my_favorite_things[2][1]) 98 | ##first [] is outer list. second [] is inner list. 99 | 100 | #This can be repeated even deeper. 101 | nested_list = [[[[["deep dive"]]]]] 102 | print(nested_list[0][0][0][0][0]) #Got it! 103 | 104 | #Because of the versatility of lists, you'll see them a lot. 105 | 106 | 107 | ########## SHALLOW COPY EXPLAINED ########## 108 | 109 | 110 | #Copying a list as so makes a shallow copy. 111 | #This means that any complex types will not be copied but rather available in both 112 | #The easiest way to understand this is with an example. 113 | 114 | my_favorite_things = ["Working out", 7, ["netflix", "Amazon Prime"]] 115 | my_favorite_things2 = my_favorite_things.copy(); 116 | 117 | #modify the original 118 | my_favorite_things[2][0] = "Audible" 119 | print(my_favorite_things2) #CONTAINS AUDIBLE 120 | #this is because the reference to nested list is copied, not the entire list itself. 121 | #(the copy points to the same data) 122 | 123 | 124 | ########## DEEP COPY ########## 125 | 126 | 127 | #The alternative to a shallow copy is a deep copy. 128 | #In order for us to do a deep copy, we must have an import 129 | import copy 130 | #copy is an example of a module. you'll often find all the imports at the top. 131 | #but it's my project so yolo. 132 | 133 | #Now we can use copy.deepcopy method 134 | #This method returns a new list so we can assign it to a variable. 135 | my_favorite_things3 = copy.deepcopy(my_favorite_things) 136 | #now we modify the original 137 | my_favorite_things[2][0] = "Hulu" 138 | print(my_favorite_things) #contains Hulu 139 | print(my_favorite_things3) #No Hulu to be found. keeps Audible value. 140 | 141 | ########## CoOMBINING LISTS ######### 142 | 143 | #similar to how we can concatenate strings, we can combine lists 144 | msg = "he" "llo" #again, + is optional with string literals 145 | print(msg) 146 | 147 | good = ["kale", "brocoli", "spinach"] 148 | bad = ["pizza", "fries", "wings"] 149 | 150 | just_right = good + bad 151 | print(just_right) 152 | 153 | #This may be obvious by now, but any time we assign an expression to a variable, 154 | #we can skip the variable altogether and use the expression 155 | 156 | print(good + bad) 157 | 158 | -------------------------------------------------------------------------------- /beginner_python/04-user-input.py: -------------------------------------------------------------------------------- 1 | #Here is a simple exmaple on how to get user input 2 | #we've talk about output with print, but this is just half of input + output 3 | 4 | #it's besst practice to tell the user what to do: 5 | print("What is your name?") 6 | name = input() 7 | 8 | #Now where does the value they type go? 9 | #the input method actually returns it, so save it to a variable. 10 | 11 | #we can then use it like any other variable (because it is just a variabe now) 12 | print("hello " + name) 13 | 14 | #althougn this seems silly or simple, this is actually quite revolutionary. 15 | #This is the first point in time where we can make our applications dynamic 16 | #dynamic == changing. The output changes based on the input! WOW! 17 | 18 | #input always reads as a string. Example: 19 | print("What is your favorite number?") 20 | num1 = input() 21 | 22 | print("what is your second favorite mumber?") 23 | num2 = input() 24 | 25 | print(num1 + " + " + num2 + " = " + num1 + num2) # 7 + 5 = 75??? WHAT!? 26 | 27 | ########## TYPES AND CASTING ########## 28 | #At this point we know there are different types 29 | #but how do we check what type and modify it? 30 | 31 | print(type(num1)) #num1 is of type str (string, that is) 32 | 33 | #We can cast it to a new type like so: 34 | 35 | new_num1 = int(num1) 36 | new_num2 = int(num2) 37 | 38 | print(type(new_num1), type(new_num2)) 39 | 40 | print(num1 + " + " + num2 + " = " + str(new_num1 + new_num2)) #Better 41 | 42 | #if you know you're going to be getting a number, it's best to cast it right away. 43 | #Lets try it again, but this time let's showcase another type...float! 44 | #float allows values after a decimal point, such as 10.5. 45 | print("Give me a 3rd number (with a decimal this time):") 46 | num3 = float(input()) 47 | 48 | print("all the numbers added:") 49 | print(num3 + new_num1 + new_num2) -------------------------------------------------------------------------------- /beginner_python/05-logic-and-if.py: -------------------------------------------------------------------------------- 1 | #Any complex program is made possible thanks to control flow statements 2 | #control flow statements include if statements and loops 3 | 4 | ########## LOGIC ########## 5 | 6 | #You must first understand booleans. 7 | #They are either True or False (these are both keywords) 8 | # 9 | happy = True 10 | print(happy) 11 | 12 | #There are operators that will return true or false 13 | #These are known as comparison operators 14 | 15 | print(5 > 3) 16 | age = 21 17 | print("age >= 21?", age >= 21) 18 | 19 | #You can also compare strings: 20 | me = "Caleb" 21 | you = "Nerd" 22 | print("me == you?", me == you) 23 | 24 | #Even lists! 25 | my_grades = [100, 100, 100] 26 | your_grades = [100, 100, 1] 27 | print("Same grade?", my_grades == your_grades) #false 28 | 29 | your_grades = [100, 100, 100] 30 | print("Same grade?", my_grades == your_grades) #true 31 | 32 | #in some languages, == compares by memory address to see if same object 33 | #this is done in python using is. 34 | #This is known as an identity comparison 35 | print("are grades the same object?", my_grades is your_grades) #false 36 | 37 | my_grades = your_grades 38 | print("are grades the same object?", my_grades is your_grades) #true 39 | 40 | #You can also do order testing for strings 41 | #Read ABC comes before BCD? 42 | print("A before B?", "ABC" < "BCD") 43 | 44 | #Not operator can be used to negate an equality check 45 | #Read A is not equal to B? 46 | print("A != B?", "A" != "B") 47 | 48 | 49 | ########### IF STATEMENT ########## 50 | 51 | 52 | #You may be wondering the user of all of these conditions. They are used within ifs and loops. 53 | #First, the if statement. 54 | print("What's your name?") 55 | name = input() 56 | print("what's your age?") 57 | age = int(input()) 58 | 59 | if name == "Caleb": 60 | print("Hey, Caleb") 61 | #otherwise do nothing and continue 62 | #4 spaces over for indent 63 | #THIS INDENT IS IMPORTANT! 64 | 65 | #BAD: 66 | if age > 100: 67 | print("WOW!") 68 | print("You are so old") #executes EVERY time 69 | 70 | #GOOD: 71 | if age > 100: 72 | print("WOW!") 73 | print("You are so old") 74 | 75 | #It is recommended to use 4 spaces instead of a tab. 76 | 77 | ########## if elif else ########## 78 | 79 | if age > 100: 80 | print("You're old") 81 | elif age > 120: 82 | print("How are you even alive?") 83 | else: 84 | print("You may have some years left in you") 85 | 86 | 87 | ########## CONDITIONS WITH BOOLEANS ########## 88 | 89 | 90 | #When working with a boolean variable, you may think to do this 91 | caleb_is_cool = False 92 | if caleb_is_cool == True: 93 | print("Let's be friends") 94 | else: 95 | print("Eww") 96 | 97 | 98 | #since the == operator returns True or False, and the variable is already false... 99 | #We can do this instead: 100 | caleb_is_cool = False 101 | if caleb_is_cool: 102 | print("Let's be friends") 103 | else: 104 | print("Eww") 105 | 106 | 107 | ########## LOGICAL OPERTATORS ######### 108 | 109 | 110 | #Logical operators can be used to make complex expressions that ultimately evaluate to true or false. 111 | #and --> both must be true 112 | #or --> one must be true 113 | #not --> negates (flips) 114 | 115 | 116 | #An example with or 117 | thunder = False 118 | lighting = True 119 | 120 | if lighting or thunder: 121 | print("Don't go swimming!") 122 | 123 | #An example with and 124 | car_nice = True 125 | on_sale = False 126 | 127 | if car_nice and on_sale: 128 | print("Buy the car!") #This will not execute! 129 | 130 | #An example with not AND and 131 | temp_outside = 50 132 | pool_heated = False 133 | 134 | if temp_outside < 60 and not pool_heated: 135 | print("Don't go swimming!") 136 | 137 | #this can be confusing, so it might be best to read it as english 138 | #however, logically... pool_heated is false so not pool_heated is true. 139 | #therefore, both sides are true. 140 | 141 | -------------------------------------------------------------------------------- /beginner_python/06-loop-basics.py: -------------------------------------------------------------------------------- 1 | #Once you understand logic, you can apply the same principles to looping 2 | 3 | languages = ["Python", "C++", "Java"] 4 | 5 | for x in languages: 6 | print(x) 7 | 8 | #The body of this loop (the indented part) will run 3 times 9 | #Each time is known as an iteration 10 | #Each iteration, the variable x will contain one element 11 | #iteration 1 will be the first element 12 | #iteration 2 will be the next, and so on. 13 | #The loop automatically stops. 14 | 15 | #The variable name is irrelevant 16 | for language in languages: 17 | print(language) 18 | 19 | 20 | ########## PRINT WITHOUT NEWLINE ########## 21 | 22 | print("One", end=" ") 23 | print("Line") 24 | 25 | #This is useful for loops where you don't want to spam the terminal 26 | for language in languages: 27 | print(language, end =" ") 28 | print() 29 | #can end with newline tfor future prints 30 | 31 | #You could alternatively use end="\t" or end="" or whatever you want. 32 | 33 | #You might be confused why we have to put end and not just: 34 | print("DOEN'T AFFECT END", " ") 35 | 36 | #Because this is interpretted as a second argument to print 37 | #resulting in a printed " " followed by a newline. 38 | #We must use end= (This is an example of keyword argument) 39 | 40 | 41 | ########## RANGE FUNCTION ########## 42 | 43 | 44 | #instead of iterating through a list, we can use a function called range 45 | #This loop runs 10 times 46 | for i in range(10): 47 | print("loading...", end= " ") 48 | print() 49 | 50 | #i is known as in iteration variable 51 | #i will obtain a value each iteration based on the range we select. 52 | #for range(10), we get 0-9: 53 | 54 | for i in range(10): 55 | print(i, end=" ") 56 | print() 57 | 58 | #Important: the value to end at is never part of the range. 59 | #With range(10) we get 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 60 | 61 | 62 | ########## RANGE START POSITION ########## 63 | 64 | 65 | #We can count 1-10 instead of 0-9 if desired: 66 | for i in range (1, 11): 67 | print(i, end=" ") 68 | print() 69 | 70 | #We can start anywhere and end anywhere 71 | for i in range (5, 7): 72 | print(i, end=" ") 73 | print() 74 | 75 | 76 | ########## RANGE STEP ########## 77 | 78 | 79 | #Go the other way. 80 | #9 included. -1 not included (result is 9-0) 81 | for i in range (9, -1, -1): 82 | print(i, end=" ") 83 | print() 84 | 85 | #The third argument is called the step. we can set it to whatever 86 | #Count down from 100 to 0, by 10s. 87 | for i in range (100, -1, -10): 88 | print(i, end=" ") 89 | print() 90 | 91 | ########## SUM OF LIST ########## 92 | 93 | #https://docs.python.org/3/library/math.html 94 | #methods taking an iterable can take a range (sum, prod) 95 | 96 | #Sum of numbers 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 97 | print(sum(range(1, 11))) 98 | 99 | 100 | ########## LIST FROM RANGE ########## 101 | 102 | #We can make the range an official list using the list ctor 103 | #https://docs.python.org/3/library/stdtypes.html#list 104 | numbers = list(range(1, 11)) 105 | print(numbers) 106 | 107 | #This is the besr way to easily print a list 108 | #as print(range(1,11)) doesn't work as expected 109 | 110 | ########## FOR LOOP WITH INDEX ########## 111 | 112 | languages = ["Python", "C++", "Java"] 113 | for i in range(len(languages)): 114 | print(i, languages[i]) 115 | 116 | #len will return 3. Passing 3 to range gives us 0, 1, 2 -------------------------------------------------------------------------------- /beginner_python/07-more-looping.py: -------------------------------------------------------------------------------- 1 | ########## BREAK ########## 2 | #You can break out of a loop any time using the break keyword. 3 | #For example, if you are looking for a particular elemennt 4 | languages = ["Python", "C++", "Java", "Perl", "C#"] 5 | 6 | for language in languages: 7 | if language == "Python": 8 | print(language + " found") 9 | break 10 | 11 | #Things after break within same block never get hit 12 | #Things outside of the if can still be hit if break is not hit first 13 | 14 | for language in languages: 15 | if language == "C++": 16 | print(language + " found") 17 | break 18 | print("YOU CAN'T SEE ME!") 19 | print("It's JOHN CENA!!!!") #executes first iteration but not 2nd 20 | 21 | ########## CONTINUE ######### 22 | 23 | #continue works in a similar way except that it will only skip the rest of the iteration. 24 | #This may be useful if you need to continue iterating through the list 25 | #(in this context you could be looking for duplicates or other interesting lanugages) 26 | 27 | print("Searching for Java:") 28 | for language in languages: 29 | if language == "Java": 30 | print(language + " found") 31 | continue 32 | print(language + ": Not What we are looking for...") 33 | 34 | 35 | ########## ELSE INSTEAD OF CONTINUE 36 | 37 | #This same structure can be achieved with an else 38 | 39 | print("Searching for Perl:") 40 | for language in languages: 41 | if language == "Perl": 42 | print(language + " found") 43 | else: 44 | print(language + ": Not What we are looking for...") 45 | 46 | 47 | ########## HOW TO DO NOTHING ########## 48 | 49 | 50 | for x in range(10): 51 | pass 52 | 53 | #You can do this when...uh... hmm.....why WOULD you want to do this? 54 | #My bet is that this is the equivalent to TODO. AKA come back to it later to finish. 55 | #This can also be used for a busy wait... Keeping processor busy. 56 | 57 | 58 | ######### ELSE WITH FOR ########## 59 | 60 | #This one is actually new to me. You can use an else with a for. 61 | #This will execute anytime the for loop hits the end of iterable (range or list) 62 | 63 | for i in range(0,10): 64 | print(i, end=" ") 65 | else: 66 | print("done") 67 | 68 | #This can be useful for a failed search as an example because it will not be hit with break 69 | for language in languages: 70 | if language == "Alabama": 71 | print(language + " found") 72 | break 73 | else: 74 | print("Nope.") 75 | 76 | 77 | ######### While loop ########## 78 | 79 | 80 | #Another form of loop is the while loop. 81 | #Here is an example that counts 0-9 (including 0 and 9) 82 | 83 | i = 0 #initialize 84 | while(i < 10): #condition 85 | print(i, end=" ") 86 | i += 1 #update 87 | print() 88 | 89 | 90 | #customize the loop as you please! Here's how to count down by two 91 | i = 30 92 | while(i >= 0): 93 | print(i, end=" ") 94 | i -= 2 95 | print() 96 | 97 | 98 | ########## CONVERTING WHILE TO FOR AND BACK ########### 99 | 100 | 101 | #I think it is important to comfortably work with for and while 102 | #Both loops need an initialization, condition, and update. 103 | 104 | initialization = 5 105 | stop_at = 10 106 | increment = 1 107 | 108 | for i in range(initialization, stop_at, increment): 109 | print("for loop:", i) 110 | 111 | 112 | while(initialization < stop_at): 113 | print("while loop:", initialization) 114 | initialization += increment 115 | 116 | 117 | #To make them match, the update should come at the end of the while 118 | #When passing a variable to range, the variable is not affected 119 | #Range returns new data and initialization is left at 5. 120 | 121 | 122 | ########## ELSE WITH WHILE ########## 123 | #The else statement for a while will execute if no break is hit. 124 | 125 | i = 0 126 | while(i < 10): 127 | print(i, end=" ") 128 | i += 1 129 | else: 130 | print("Else of while") 131 | 132 | #Random other example 133 | #Checks to see first square > 134 | 135 | i = 0 136 | while(i < 10): 137 | if i**2 > 50: 138 | print("First square big enough:", i) 139 | break 140 | i += 1 141 | else: 142 | print("None are big enough") 143 | 144 | 145 | ########## FLAG VARIABLES ########## 146 | 147 | 148 | #You may not be comfortable with else after a loop 149 | #The equivalent without an else would be like so: 150 | index = -1 #keeps -1 until told otherwise 151 | i = 0 152 | while(i < 10): 153 | if i**2 > 500: 154 | index = i #change index if requirements are met. Not reached because > returns false 155 | break 156 | i += 1 157 | 158 | if index > -1: 159 | print("First square big enough:", i) 160 | else: 161 | print("None are big enough") 162 | 163 | #Setting a starting value (such as -1), possibly changing it, 164 | #and checking it afterwards creates a flag variable. 165 | #Just a concept. Nothing new on syntax 166 | 167 | ######### "DO WHILE" loop ########## 168 | 169 | #In other languages, there is a concept as a do-while loop. 170 | #These loops always execute at least once. 171 | #We can mimmick this in python easily. 172 | 173 | i = 15 174 | print(i) #prints i atleast once no matter what 175 | i += 1 176 | while (i < 10): 177 | print(i) 178 | i += 1 179 | 180 | 181 | #To generalize this: 182 | 183 | #do stuff 184 | #condition - true to continue 185 | #do stuff 186 | 187 | #This structure is useful for sentinel / indefinate loops 188 | 189 | 190 | ########## Indefinate / Sentinel loops ########## 191 | 192 | #an Indefinate loop is a loop that we do not decide how long it will run ahead of time 193 | #The loop can be stopped, however. This makes it different than an infinate loop. 194 | #An example may be displaying a menu numerous times 195 | 196 | 197 | print("Do you want to continue? Y/N: ") 198 | response = input() 199 | while response == "Y" or response == "y": 200 | print("Do you want to continue? Y/N: ") 201 | response = input() 202 | #a logical name for the variable would be 'continue' or 'in' 203 | #however these are keyword. don't try it. 204 | 205 | #not super common vocab but good to know... 206 | #A sentinel value is a value used to stop a loop. In this case it is anything besides "Y" or "y" 207 | #for programs a sentinel value is often 'q' 208 | 209 | 210 | ########## UPPER AND LOWER ########## 211 | 212 | 213 | #We can also write our code like so 214 | print("Do you want to continue AGAIN? Y/N: ") 215 | response = input() 216 | while response.lower() == "y": 217 | print("Do you want to continue? Y/N: ") 218 | response = input() 219 | 220 | #This is important to understand as "Y" and "y" are not the same thing 221 | #Overlooking this can introduce logical bugs in our software 222 | 223 | #There is also an upper. 224 | #We can also invoke it on constant strings 225 | print("am i screaming?".upper()) 226 | 227 | ########## checking if a string is uppercase or lowercase ########## 228 | 229 | name = "Caleb" 230 | if name.isupper(): 231 | print("Upper") 232 | elif name.islower(): 233 | print("Lower") 234 | else: 235 | print("Mixed") 236 | 237 | #not sure when you might need this but still good to know. -------------------------------------------------------------------------------- /beginner_python/08-nested-if-for.py: -------------------------------------------------------------------------------- 1 | #The only form of nesting we've encountered so far was an if statement within a loop. 2 | languages = ["Python", "C++", "Java", "Perl", "C#"] 3 | 4 | for language in languages: 5 | if language == "C#": 6 | print(language + " found") 7 | break 8 | 9 | #proper nesting is vital inside of python. Unlike many other languages, 10 | #python is indentation sensitive. The position of the code is important 11 | 12 | for language in languages: 13 | if language == "C#": 14 | print(language + " found") 15 | break 16 | 17 | #^^ This loop does something completely different. 18 | #Syntactically, the only difference is the position of the break keyword. 19 | #It will break at the end of the first iteration no matter what 20 | 21 | ########## NESTED IF ########## 22 | 23 | logging = True 24 | logging_in = True 25 | name = "Caleb" 26 | 27 | if logging_in: 28 | if logging: 29 | print(name + " is logging in.") #log console, file, or db. 30 | print("Welcome, " + name) 31 | 32 | ########## CONVERTING COMPLEX CONDITIONAL TO NESTED IF ########### 33 | 34 | #It is common in more complex code to see nested if statements 35 | #This can often replace complex expressions that use numerous logical operators 36 | #Either way is not better, just whatever is clearer to you 37 | 38 | age = 20 39 | fun = False 40 | likes_to_dance = True 41 | 42 | if (age < 30 or fun) and likes_to_dance: 43 | print("You're invited to the party!") 44 | else: 45 | print("get lost freakbag") #most general 46 | 47 | #This could alternatively be represented with nested if statements 48 | #and can allow more specific responses 49 | 50 | if age < 30 or fun: 51 | if likes_to_dance: 52 | print("You're invited to the party!") 53 | else: 54 | print("How could you not like to dance?") #Specific to dancing 55 | else: 56 | print("You're either too old or not fun enough to be in my party") 57 | #Note how we can't easily say which. We say OR. 58 | 59 | 60 | ########## INTRO TO NESTED FOR ########## 61 | 62 | #If you are fairly new, nested loops can be confusing. Pay attention! 63 | #Stop texting and looking at memes...CODE! 64 | #We can loop a loop using a nested loop. 65 | #The inner loop will run each iteration of the outer loop. 66 | 67 | for i in range(4): 68 | for j in range(5): 69 | print(j, end=" ") 70 | print() #go to next line 71 | 72 | #The result? The inner loop prints 0 - 4. We then do this 4 times 73 | #After each complete 0-4 print, we go to the next line with print() 74 | #This puts the next loop on the next line of output -------------------------------------------------------------------------------- /beginner_python/09-nested-loops.py: -------------------------------------------------------------------------------- 1 | ########## NESTED FOR LOOP PT2 ########### 2 | 3 | 4 | #The previous section had this loop. 5 | #The only thing we did was print j and a new line. 6 | for i in range(4): 7 | for j in range(5): 8 | print(j, end=" ") 9 | print() #go to next line 10 | 11 | #Review this and make sure you understand what is going on. 12 | 13 | #We could also say what iteration of the outer loop we are on 14 | for i in range(4): 15 | print("iteration " + str(i), end=": ") 16 | for j in range(5): 17 | print(j, end=" ") 18 | print() #go to next line 19 | 20 | #We could also do a more complicated loop to work with the numbers. 21 | for i in range(4): 22 | print("Count by " + str(i), end=": ") 23 | for j in range(5): 24 | print(j*i, end=" ") 25 | print("...") #go to next line 26 | 27 | #What's going on here? 28 | #We are taking the outer iteration variable and multiplying to by the inner 29 | #in other words, we are counting to 5 each time 30 | #but we are multiplying the result by 0, 1, 2, 3 31 | 32 | ########## OUTER LOOP VARIABLES IN INNER range() - TRIANGLES ######### 33 | 34 | #I had no idea what to call this section. Whatever. 35 | 36 | #We can always use the outer loop iteration variable within the inner loop. 37 | #What if we wanted to count to 9 for each iteration, 38 | #but start with a higher number each time? 39 | 40 | for i in range(10): 41 | for j in range(i, 10): 42 | print(j, end=" ") 43 | print() 44 | 45 | #The first iteration i will be 0, so we get: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 46 | #The second iteration i will be 1, so we get 1, 2, 3, 4, 5, 6, 7, 8, 9 47 | #etc. 48 | 49 | 50 | ########## NESTED WHILE ########## 51 | 52 | 53 | #We now have to worry bout the initialization and increment. 54 | 55 | #print 0-4, 4 times: 56 | i = 0 57 | while i < 4: 58 | j = 0 59 | while j < 5: 60 | print(j, end=" ") 61 | j += 1 62 | print() 63 | i += 1 64 | 65 | #not as clean...initialization and inrement has to be correct 66 | #pay close attention 67 | 68 | #This won't work as expected: 69 | 70 | print("Let's try this again:") 71 | i = 0 72 | j = 0 73 | while i < 4: 74 | while j < 5: 75 | print(j, end=" ") 76 | j += 1 77 | print() 78 | i += 1 79 | 80 | print("What happened?") #j is never reset back to zero 81 | 82 | 83 | ########## LOOP TO SUM ALL NUMBERS ########## 84 | 85 | 86 | #I want to calculate the sum of numbers 0-10: 10+9+8+7+6+5+4+3+2+1 87 | 88 | sum = 0 89 | j = 10 90 | while j > 0: 91 | sum += j 92 | j -= 1 93 | print(sum) #55 94 | 95 | #But now I want to get the sum of 9-0, 8-0, 7-0, 6-0, etc... 96 | #Here will be the structure: 97 | 98 | i = 10 99 | while (i > -1): #include zero. Could also do >= 0 100 | #print sum from i to zero. 101 | i -= 1 102 | 103 | 104 | #We just coded how to sum to zero...so copy/paste that there.... 105 | #change to j = i (dynamic from 10 to 0) 106 | print("All the sums:") 107 | i = 10 108 | while (i > -1): 109 | sum = 0 110 | j = i 111 | while j > 0: 112 | sum += j 113 | j -= 1 114 | print(sum) 115 | i -= 1 116 | 117 | #We can now customize the output to be more readable: 118 | print("All the sums with output:") 119 | i = 10 120 | print("Getting sums up to", i) 121 | while (i > -1): 122 | sum = 0 123 | j = i 124 | while j > 0: 125 | if j > 1: 126 | print(j, "+", end=" ") 127 | else: 128 | print(j, "=", end=" ") 129 | sum += j 130 | j -= 1 131 | print(sum) 132 | i -= 1 -------------------------------------------------------------------------------- /beginner_python/10-functions.py: -------------------------------------------------------------------------------- 1 | #We are going to wrap back around to lists and loops 2 | #but first functions 3 | #functions are the only way to build scalable code 4 | 5 | 6 | ########## HOW TO CREATE A FUNCTION ########## 7 | 8 | 9 | #This one is simple, but we go on. 10 | def greet(): 11 | print("hello") 12 | print("Welcome, Caleb") 13 | 14 | #invoke 15 | greet() 16 | #Can invoke numerous times: 17 | greet() 18 | greet() 19 | 20 | #Benefits: We can save lines of code if function is large 21 | #One source of truth. No repeat of code. Need changes? 22 | #update one spot 23 | #Can improve code readability 24 | 25 | 26 | ########## Arguments and Parameters ########## 27 | 28 | 29 | #parameter is a variable used within a function 30 | def greet(name): #name is a parameter 31 | print("hello") 32 | print("Welcome, " + name) 33 | 34 | greet("Sabrina") #Sabrina is an argument (value passed in to parameter variable) 35 | 36 | #We can also use variables as arguments 37 | 38 | new_guy = "Carl" 39 | greet(new_guy) 40 | 41 | #This gives the value "Carl" to the name parameter 42 | 43 | 44 | ########## RETURN ########## 45 | 46 | 47 | #We can return (exit) from a function in certain situations 48 | def greet(name): 49 | if name == "Claire": 50 | return 51 | else: 52 | print("hello") 53 | print("Welcome " + name) 54 | 55 | greet("Claire") #NOPE! 56 | greet("Clarice") #YES! 57 | 58 | #This code can be simplified by removing the else: 59 | 60 | def greet(name): 61 | if name == "Claire": 62 | return 63 | print("hello") 64 | print("Welcome " + name) 65 | 66 | #The concern without an else is that the line after the if is announced regardless of name 67 | #This works, however, because there is never a case where name == "Claire" that is not returned 68 | #We only need else if we are not returning! 69 | 70 | 71 | ########## RETURN VALUES ########## 72 | 73 | 74 | #instead of printing inside the function, we can use the function to generate a message 75 | #We can print outside of the function on the caller side 76 | #caller side --> Where we invoke the function 77 | 78 | def greet(name): 79 | if name == "Claire": 80 | return "Go away" 81 | return "Hello " + name + "! Welcome to my app." 82 | 83 | returned = greet("Sal") 84 | print(returned) 85 | 86 | #We can use the returned value directly... 87 | print(greet("Claire")) 88 | 89 | 90 | ########## DEFAULT ARGUMENTS ########## 91 | 92 | 93 | #We may want to create a method that does not require an input 94 | def greet(name="User"): 95 | if name == "Claire": 96 | return "Go away" 97 | return "Hello " + name + "! Welcome to my app." 98 | 99 | print(greet()) #No name? Default to User 100 | 101 | 102 | ########## MULTIPLE ARGUMENTS / PARAMETERS ########## 103 | 104 | 105 | def greet(name="User", be_nice=False): 106 | if be_nice: 107 | return "Hello " + name + "! Welcome to my app." 108 | return "Go away " + name 109 | 110 | print(greet("Caleb", True)) 111 | print(greet("Caleb")) 112 | 113 | 114 | ########## KEYWORD ARGUMENTS ########### 115 | 116 | #This will showcase how to skip any particular parameter 117 | 118 | def greet(name="User", be_nice=False): 119 | if be_nice: 120 | return "Hello " + name + "! Welcome to my app." 121 | return "Go away " + name 122 | 123 | print(greet(be_nice=True)) 124 | 125 | #NOTE if a parameter does not have a default value, you must specify it 126 | #Either in order without a name, or assigning by name 127 | 128 | 129 | ########## POSITIONAL OR KEYWORD ARGUMENTS ########## 130 | 131 | 132 | #With the function we have defined, we can pass arguments by position or by keyword 133 | 134 | def greet(name, be_nice): 135 | if be_nice: 136 | return "Hello " + name + "! Welcome to my app." 137 | return "Go away " + name 138 | 139 | 140 | print(greet("Positional", True)) #Positional 141 | print(greet(be_nice=True, name="Keyword")) #Keyword (NOTICE ORDER!) 142 | 143 | #Positional arguments must follow keyword arguments 144 | #ERROR: 145 | #print(greet(be_nice=True, "Keyword")) 146 | 147 | #NOTE that we can invoke by position or keyword. We can restrict to either though. 148 | #If we want our method to have to be invoked using position, we can do that 149 | #We can also restrict to keyword only as well. 150 | 151 | 152 | ########## POSITIONAL-ONLY ARGUMENTS ########## 153 | 154 | 155 | def greet(name, be_nice, /): #Anything before the / must be positional 156 | if be_nice: 157 | return "Hello " + name + "! Welcome to my app." 158 | return "Go away " + name 159 | 160 | 161 | print(greet("positional", False)) 162 | #ERROR because invoking with keyword: 163 | #print(greet("Positional", be_nice=True)) 164 | 165 | #We can also put the / between arguments 166 | def greet(name, /, be_nice): 167 | if be_nice: 168 | return "Hello " + name + "! Welcome to my app." 169 | return "Go away " + name 170 | 171 | print(greet("Positional", be_nice=True)) #This works now. 172 | print(greet("Positional", True)) #This works too. 173 | 174 | #We can invoke with be_nice being named or positional 175 | #Doesn't add a lot of value but nice when we have lots of arguments 176 | 177 | #ERROR because invoking name by keyword: 178 | #print(greet(name="Keyword", be_nice=True)) 179 | 180 | 181 | ########## KEYWORD-ONLY ARGUMENTS ########## 182 | 183 | #Place a *, before any arguments that are keyword-only 184 | def greet(name, /, *, be_nice ): #be_nice is keyword only 185 | if be_nice: 186 | return "Hello " + name + "! Welcome to my app." 187 | return "Go away " + name 188 | 189 | print(greet("Positional", be_nice=True)) #be_nice= is required 190 | 191 | #ERROR because positional 192 | #print(greet("Positional", True)) 193 | 194 | 195 | ########## SPECIAL PARAMETER SUMMARY ########## 196 | 197 | #We've learned about positional-only arguments, and keyword-only arguments 198 | #And of course the arguments that can be either. 199 | #Here is full (but contrived) example 200 | 201 | def do_nothing(pos1, pos2, pos3, /, either1, either2, *, keyword1, keyword2, keyword3): 202 | print("pos1", pos1) 203 | print("pos2", pos2) 204 | print("pos3", pos3) 205 | print("either1", either1) 206 | print("either2", either2) 207 | print("keyword1", keyword1) 208 | print("keyword2", keyword2) 209 | print("keyword3", keyword3) 210 | 211 | do_nothing(1, 2, 3, 4, either2=5, keyword3=6, keyword1=7, keyword2=8) 212 | 213 | #A very helpful rule to remember the positioning of this junk 214 | #You must always invoke a method passing positional first 215 | #Because if you passed them later, the position would be janked up 216 | #The either parameters must be in the middle because they can also be positional 217 | #The keyword are always last because you can mix their order 218 | 219 | 220 | ########## LIST PARAMETERS / FUNCTION TO ITERATE LIST ######### 221 | 222 | 223 | def greet_all(people): 224 | for person in people: 225 | print("Hello " + person) 226 | 227 | people = ["Caleb", "Josh", "Austin"] 228 | 229 | greet_all(people) 230 | 231 | 232 | ########## UNLIMITTED ARGUMENTS / PACKING ########## 233 | 234 | 235 | #What if you are working with individual pieces of data? 236 | #We can modify the function to "pack" the data with * 237 | 238 | def greet_all(*people): 239 | for person in people: 240 | print("Hello " + person) 241 | 242 | 243 | greet_all("Caleb", "Josh", "Austin") 244 | 245 | 246 | ########## UNPACKING ########## 247 | 248 | 249 | def print_info(name, age, email): 250 | print(name + " is " + str(age) + ". Reached at " + email) 251 | 252 | info = ["Caleb", 12, "email@email.com"] 253 | print_info(*info) 254 | 255 | 256 | ########## FUNCTIONS CALLING FUNCTIONS ########## 257 | 258 | #Let's say we have this method and no way to edit it 259 | def greet(name, be_nice=True): 260 | if be_nice: 261 | return "Hello " + name + "! Welcome to my app." 262 | return "Go away " + name 263 | 264 | #We can utilize it. 265 | def greet_all(people): 266 | for person in people: 267 | print(greet(person)) #because it returns string 268 | 269 | people_to_greet = ["Johnny", "Jimmy", "Jacob"] 270 | greet_all(people_to_greet) -------------------------------------------------------------------------------- /python/01-intro.py: -------------------------------------------------------------------------------- 1 | #Welcome. We are going to be working through python 2 | #It should be pretty easy to follow along with but if you struggle 3 | #I have a beginner series as well 4 | 5 | 6 | ########## APPEND TO LIST ######### 7 | 8 | 9 | healthy = ["pizza", "frozen custard"] 10 | 11 | healthy.append("apple crisp") 12 | 13 | print(healthy) 14 | 15 | 16 | ########## CHECKING IF ELEMENT IN LIST ######### 17 | 18 | 19 | #Obviously on our health adventures we want to know if something is healthy. 20 | 21 | print("chicken pot pie" in healthy) 22 | 23 | #This returns True / False. Can use in keyword within if 24 | 25 | backpack = ["pizza", "chicken pot pie", "kale chips"] 26 | 27 | if("pizza" in healthy): 28 | print("eating it") 29 | 30 | #We can make this more dynamic. Let's remove pizza from list. 31 | 32 | 33 | ########## REMOVING FROM LIST ########## 34 | 35 | 36 | healthy = ["pizza", "frozen custard"] 37 | backpack = ["pizza", "chicken pot pie", "kale chips"] 38 | 39 | if("pizza" in healthy): 40 | backpack.remove("pizza") 41 | 42 | print(backpack) 43 | 44 | 45 | ########## LIST COMPREHENSION ########## 46 | 47 | 48 | healthy = ["kale chips", "broccoli"] 49 | backpack = ["pizza", "frozen custard", "apple crisp", "kale chips"] 50 | 51 | backpack[:] = [item for item in backpack if item in healthy] 52 | #slice --> [:] keeps same object id 53 | print(backpack) 54 | 55 | #similar to this (except thi one creates new var): 56 | healthy_backpack = [] 57 | 58 | for item in backpack: 59 | if item in healthy: 60 | healthy_backpack.append(item.upper()) 61 | 62 | print(healthy_backpack) 63 | 64 | 65 | ########## LIST COMPREHENSION ESSENTIALS ########## 66 | 67 | 68 | squares = [i**2 for i in range(10) if i % 2 == 0] 69 | print(squares) 70 | 71 | 72 | ########## COUNTING ELEMENTS IN LIST ########## 73 | 74 | healthy = ["pizza", "frozen custard"] 75 | backpack = ["pizza", "chicken pot pie", "kale chips"] 76 | 77 | print(len(healthy), len(backpack)) 78 | 79 | #You may think of something like healthy.size() or healthy.length() or even healthy.count() 80 | #This is not quite what we are looking for. 81 | #count is used to count a particular element in a list. Up next! 82 | 83 | 84 | ########## COUNT / CHECK IF ELEMENT EXISTS ########## 85 | 86 | 87 | print(backpack.count("pizza")) #number of pizza in list 88 | 89 | backpack = ["pizza slice", "pizza slice", "pizza slice"] 90 | 91 | print(backpack.count("pizza slice")) #3 92 | 93 | #This can be used to prevent too many items: 94 | if(backpack.count("pizza slice") < 3): 95 | backpack.append("pizza slice") 96 | print("You put a piece of pizza in your backpack") 97 | else: 98 | print("How about you go to the gym?") 99 | 100 | 101 | ########## INTRO TO SETS ########## 102 | 103 | 104 | #Don't care about order 105 | #Just need to know yes or no? 106 | #Sets... 107 | 108 | backpack2 = {"sword", "rubber duck", "sice a pizza", "parachute", "sword"} 109 | print("sword" in backpack2) 110 | 111 | 112 | ########## COUNTING WITH LIST COMPREHENSION ########## 113 | 114 | 115 | backpack = ["sword", "rubber duck", "slice of pizza", "parachute", 116 | "sword", "rubber duck", "slice of pizza", "parachute", 117 | "sword", "rubber duck", "slice of pizza", "parachute", 118 | "sword", "rubber duck", "slice of pizza", "parachute", 119 | "cannon", "laser cannon", "Canon 90D", "can of soup"] 120 | 121 | counts = [[backpack.count(item), item] for item in set(backpack)] 122 | 123 | print(counts) 124 | 125 | 126 | ########## COUNTING ELEMENTS WITH COUNTER ########## 127 | 128 | from collections import Counter 129 | print(Counter(backpack)) 130 | -------------------------------------------------------------------------------- /python/02-lists.py: -------------------------------------------------------------------------------- 1 | ########## INSERT INTO MIDDLE OF LIST ########## 2 | 3 | #Lists are ordered, and this order may matter to you. 4 | 5 | work_days = ["Monday", "Tuesday", "Thursday", "Friday", "Saturday"] 6 | 7 | #OVERTIME! 8 | work_days.insert(2, "Wednesday") #index, "data" 9 | 10 | print(work_days) 11 | 12 | #What if we want to do the opposite and take a day out? 13 | 14 | 15 | ########## REMOVE ELEMENT FROM LIST BY VALUE OR INDEX ########## 16 | 17 | 18 | #We learned how to remove by value: 19 | 20 | work_days = ["Monday", "Tuesday", "Thursday", "Friday", "Saturday"] 21 | 22 | #VACATION DAY! 23 | work_days.remove("Saturday") 24 | print(work_days) 25 | 26 | #However, removing by index is also useful: 27 | work_days = ["Monday", "Tuesday", "Thursday", "Friday", "Saturday"] 28 | 29 | del work_days[0] 30 | print(work_days) 31 | 32 | 33 | ########## REMOVE ELEMENT WITH POP ########## 34 | 35 | 36 | #The benefit here is the method returns the element 37 | work_days = ["Monday", "Tuesday", "Thursday", "Friday", "Saturday"] 38 | popped = work_days.pop(1) 39 | 40 | print("You removed " + popped) 41 | print(work_days) 42 | 43 | 44 | ########## REMOVE ELEMENT FROM LIST USING DEL AND SLICE ########## 45 | 46 | 47 | work_days = ["Monday", "Tuesday", "Thursday", "Friday", "Saturday"] 48 | 49 | del work_days[0:2] #remove first 2 50 | print(work_days) 51 | 52 | del work_days[-2:] #remove last 2 (start 2 from right and go to end) 53 | print(work_days) 54 | 55 | 56 | ########## REMOVING ALL OCCURANCES IN LIST ########## 57 | 58 | backpack = ["pizza slice", "button", "pizza slice", "fishing pole", 59 | "pizza slice", "nunchucks", "pizza slice", "sandwich from mcdonalds"] 60 | 61 | backpack.remove("pizza slice") 62 | print(backpack) #SO MUCH PIZZA! 63 | 64 | while("pizza slice" in backpack): 65 | backpack.remove("pizza slice") 66 | 67 | print(backpack) 68 | 69 | #This may not be the most optimized solution as each removal requires 70 | #an iteration from backpack.count. 71 | #You should also avoid modifying a list while iterating, so a for-in loop is bad 72 | 73 | #for item in backpack: 74 | # if(item == "pizza slice"): 75 | # backpack.remove(item) 76 | 77 | #The original solution is fine for removing data from reasonably sized lists 78 | 79 | #Here is a better solution: 80 | backpack = ["pizza slice", "button", "pizza slice", "fishing pole", 81 | "pizza slice", "nunchucks", "pizza slice", "pizza slice", "sandwich from mcdonalds"] 82 | 83 | for item in backpack[:]: #uses copy to keep index 84 | if item == "pizza slice": 85 | backpack.remove(item) 86 | 87 | print(backpack) 88 | 89 | #Here is a list comprehension version: 90 | backpack = ["pizza slice", "button", "pizza slice", "fishing pole", 91 | "pizza slice", "nunchucks", "pizza slice", "pizza slice", "sandwich from mcdonalds"] 92 | 93 | backpack[:] = [item for item in backpack if item != "pizza slice"] 94 | 95 | print(backpack) 96 | 97 | ########## REVERSE LIST ########## 98 | 99 | 100 | backpack = ["pizza slice", "button", "pizza slice", "fishing pole", 101 | "pizza slice", "nunchicks", "pizza slice", "sandwich from mcdonalds"] 102 | 103 | print(backpack) 104 | backpack.reverse() 105 | print(backpack) 106 | 107 | 108 | ########## SWAP AND REVERSE ALGORITHMS ########## 109 | 110 | data = ["a", "b", "c", "d", "e", "f", "g", "h"] 111 | 112 | for index in range(len(data) // 2): 113 | data[index], data[-index-1] = data[-index-1], data[index] 114 | 115 | print(data) 116 | 117 | 118 | ########## REVERSED ITERATOR ########## 119 | 120 | 121 | data = ["a", "b", "c", "d", "e", "f", "g", "h"] 122 | 123 | data_reversed = [] 124 | 125 | for item in reversed(data): 126 | data_reversed.append(item) 127 | 128 | print(data) 129 | print(data_reversed) 130 | 131 | 132 | ########## REVERSE USING SLICING ########## 133 | 134 | data = ["a", "b", "c", "d", "e", "f", "g", "h"] 135 | data[:] = data[::-1] 136 | print(data) -------------------------------------------------------------------------------- /python/03-sorting.py: -------------------------------------------------------------------------------- 1 | ########## SORT METHOD ########## 2 | 3 | 4 | #This is using python built in method and not custom built 5 | #You can easily sort a list: 6 | work_days = ["Monday", "Tuesday", "Thursday", "Friday", "Saturday"] 7 | 8 | work_days.sort() 9 | 10 | print(work_days) 11 | #Remember...no return. Modifies list 12 | 13 | numbers = [1, 11, 115, 13, 1305, 43] 14 | print(numbers) 15 | #This is not possible because no return. 16 | # print(numbers.sort()) 17 | 18 | 19 | numbers.sort() 20 | print(numbers) 21 | 22 | #What if you want to sort without messing up original? 23 | #We can copy. 24 | 25 | 26 | ########## SORTED - COPY A LIST FOR SORT ########## 27 | 28 | numbers = [1, 11, 115, 13, 1305, 43] 29 | numbers_sorted = sorted(numbers) 30 | 31 | #This returns a NEW list. so original is unaffected! 32 | 33 | print(numbers) #original list 34 | print(numbers_sorted) 35 | 36 | #This also allows us to assign a sorted listed immediately. 37 | 38 | numbers = sorted([1, 11, 115, 13, 1305, 43]) 39 | print(numbers) 40 | 41 | 42 | ########## SORT IN REVERSE ########## 43 | 44 | 45 | #You can easily get a reverse sorted list. 46 | numbers = sorted([1, 11, 115, 13, 1305, 43]) 47 | numbers.reverse() 48 | 49 | print(numbers) 50 | 51 | #However, sorted has an optional/default parameter 52 | #We can pass a value to it 53 | 54 | print(sorted(numbers, reverse=True)) 55 | 56 | 57 | 58 | ########## CASE INSENSITIVE SORT ########## 59 | 60 | #When working with strings, 'a' and 'A' are different. 61 | 62 | letters = ['a', 'A', 'abc', 'ABC', 'aBc', 'aBC', 'Abc'] 63 | 64 | print(sorted(letters)) #Capital is considered first 65 | print(sorted(letters, key=str.lower)) 66 | 67 | 68 | ########## SORT BY STRING LENGTH ########## 69 | 70 | 71 | random = ["a", "A", "aa", "AAA", "HELLO", "b", "c", "a"] 72 | print(sorted(random, key=len)) 73 | #no () on function! len refers to function. len() invokes function 74 | 75 | 76 | ########## SORT NUMBERS WITH LEXICOGRAPHICAL SORTING ########## 77 | 78 | 79 | #We can sort numbers similar to strings 1, 11, 111, 2, 22, 222 80 | numbers = [1, 54, 76, 12, 111, 4343, 6, 8888, 3, 222, 1, 0, 222, -1, -122, 5, -30] 81 | print(sorted(numbers, key=str)) 82 | 83 | #Basically, when we are working with strings, 84 | #"111" < "12" because we compare by character left to right 85 | #So we can cast each to a str using the str constructor 86 | 87 | 88 | ########## COMPARE NUMERICALLY ########## 89 | 90 | 91 | #Just like we compared using strings in the previous section, we can do it with numbers 92 | #Talse is 0 93 | #True is 1 94 | #expression evaluates to true and maintains that value 95 | #No data is converted to a float in list. Strings are still strings. #bools are bools. 96 | 97 | 98 | age = 5 99 | stuff = [True, False, 0, -1, "0", "1", "10", age < 30, "20", "2", "5", "9001", "5.5", "6.0", 6] 100 | print(sorted(stuff, key=float)) -------------------------------------------------------------------------------- /python/04-basic-io.py: -------------------------------------------------------------------------------- 1 | ########## SPLIT ########## 2 | 3 | msg = "Pay attention to each word that I say..." 4 | words = msg.split() #returns list 5 | print(words) 6 | 7 | msg = "this,is,important,data" #How to parse CSV 8 | print(msg.split(",")) 9 | 10 | 11 | ########## SPLIT STRING BY LINE ########## 12 | 13 | 14 | #This may have came from a file, for example. 15 | msg = """\ 16 | Hey there. 17 | My name is Caleb! 18 | What's your name? 19 | You're name is NERD? Weird... 20 | Bye for now!""" 21 | 22 | print(msg) #to see how it is stored... 23 | 24 | print(msg.split('\n')) 25 | 26 | ########## INPUT USING SPLIT ########## 27 | 28 | print("List your favorite foods separated by ', '") 29 | print("Example input: ") 30 | print("Kale, bok choy, brussel sprouts") 31 | 32 | foods = input().split(', ') 33 | 34 | for food in foods: 35 | print("You said " + food) 36 | 37 | #an obvious downfall is that this is very touchy. 38 | #instead, we could ask one food per line 39 | 40 | ########## LOOPING TO GET USER INPUT ########## 41 | 42 | fav_foods = [] 43 | while True: 44 | print("Enter a food. q to quit: ", end="") 45 | fav = input() 46 | if str.lower(fav) == 'q': 47 | break 48 | fav_foods.append(fav) 49 | 50 | print("all foods:", fav_foods) 51 | 52 | 53 | ########## LIST AS STACK ########## 54 | 55 | #Consider a stack of plates. 56 | #The last one you add is the first to be removed. 57 | 58 | #The data structure depends on adding to the end of a list: 59 | stack = [] 60 | stack.append("added") 61 | #and removing from the end of the list 62 | stack.pop() 63 | 64 | fav_foods = [] 65 | while True: 66 | print("Enter a food. q to quit, r to remove: ", end="") 67 | fav = input() 68 | if str.lower(fav) == 'q': 69 | break 70 | if str.lower(fav) == 'r': 71 | popped = fav_foods.pop() 72 | print("removed " + popped) 73 | print("all foods:", fav_foods) 74 | continue 75 | fav_foods.append(fav) 76 | print("all foods:", fav_foods) 77 | 78 | print("final foods:", fav_foods) 79 | 80 | 81 | ########## QUEUE VARIATION ########## 82 | 83 | 84 | #The difference with a queue is that the first added is the first removed 85 | #consider a line to a roller coaster 86 | #first in line rides ride first. 87 | 88 | #The data structure depends on adding to the end of a list: 89 | stack = [] 90 | stack.append("added") 91 | #and removing from the FRONT of the list 92 | stack.pop(0) #remove index 0 93 | 94 | fav_foods = [] 95 | while True: 96 | print("(QUEUE) Enter a food. q to quit, eat to remove: ", end="") 97 | fav = input() 98 | if str.lower(fav) == 'q': 99 | break 100 | if str.lower(fav) == 'eat': 101 | popped = fav_foods.pop(0) 102 | print("removed " + popped) 103 | print("all foods:", fav_foods) 104 | continue 105 | fav_foods.append(fav) 106 | print("all foods:", fav_foods) 107 | 108 | print("final foods:", fav_foods) -------------------------------------------------------------------------------- /python/05-2d-lists.py: -------------------------------------------------------------------------------- 1 | ########## WORKING WITH 2D LISTS ########## 2 | 3 | grades = [[6, 3, 5], [60, 43, 4, 23], [205]] 4 | 5 | #This may be review 6 | #First list in grades: 7 | print(grades[0]) 8 | print(type(grades[0])) #list 9 | 10 | #Second element of first list in grades: 11 | print(grades[0][1]) 12 | print(type(grades[0][1])) #int 13 | 14 | #Lists are dynamic 15 | grades.append([4]) #add an element, increasing len 16 | grades.pop(1) #indexes rearranged 17 | print(grades) 18 | #grades.clear() #remove all. 19 | print(len(grades)) 20 | print(len(grades[0])) 21 | #Python keeps it simple in that there's not a static array type. 22 | #Other languages often have an array and then list. 23 | 24 | #iterate through 2D list 25 | for inner_list in grades: 26 | for grade in inner_list: 27 | print(grade, end=" ") 28 | print() 29 | 30 | #This will break if one element is not in a list. You COULD check, if you want. 31 | 32 | #checking if list: 33 | grades = [[6, 3, 5], [60, 43, 4, 23], 5, 3, [205]] 34 | 35 | for inner in grades: 36 | if isinstance(inner, list): 37 | for grade in inner: 38 | print(grade, end=" ") 39 | print() 40 | else: 41 | print(inner) 42 | 43 | #You can also iterate using range 44 | 45 | grades = [[1, 2, 3], [4, 5, 6, 7, 8], [9]] 46 | 47 | for i in range(len(grades)): 48 | for j in range(len(grades[i])): 49 | print(grades[i][j], end=" ") 50 | print() 51 | 52 | ######### FUNCTION TO PRINT LIST ########## 53 | 54 | def print_2d(passed_in): 55 | for inner in passed_in: 56 | if isinstance(inner, list): 57 | for data in inner: 58 | print(data, end=" ") 59 | print() 60 | else: 61 | print(inner) 62 | 63 | print_2d(["chickity", "china", "chinese", "chicken", [1, 3, 3], [4]]) 64 | 65 | 66 | ########## JOIN ########## 67 | 68 | 69 | data = ["01001100", "01001111", "01001100"] 70 | 71 | print(".".join(data)) 72 | print("-".join(data)) 73 | 74 | data = [1, 0, 1, "2", "505"] 75 | print(" ".join(str(x) for x in data)) 76 | #100% original idea stolen from this guy 77 | #https://stackoverflow.com/questions/3590165/join-a-list-of-items-with-different-types-as-string-in-python 78 | 79 | 80 | ########## SORTING 2D LIST ########## 81 | 82 | data = [[10, 2, 3],[10, 20], [4, 5000, 6], [7, 8, 9], [10]] 83 | 84 | print(sorted(data)) 85 | 86 | #behind the scenes a comparison is done. Here's some more practice 87 | print([10] < [11]) #True 88 | print([1, 10] < [1, 2]) #False 89 | 90 | #What about this? 91 | print([5] < [5, -1]) #True 92 | #the shorter is considered less 93 | 94 | 95 | ########## Sorting by sum of list ######### 96 | 97 | 98 | #We can also sort using a different function to determine which comes first: 99 | 100 | print(sorted(data, key=sum)) 101 | 102 | #You can also reverse the order: 103 | print(sorted(data, key=sum, reverse=True)) #each list stays same, just order of list is flipped 104 | 105 | 106 | ########## CUSTOM KEY FUNCTION ########## 107 | 108 | 109 | #Any fuction you could use on a list to manipulate the data should do the trick 110 | #Here's another example: 111 | 112 | def avg(data): 113 | avg = sum(data) / len(data) 114 | print(data, "average is", avg) #for our sake to see 115 | return avg 116 | 117 | data = [[5, 5, 5], [3, 4, 5], [3, -3, 0], [1,1,1,79], [1, 10, 1, 20]] 118 | print(sorted(data, key=avg)) -------------------------------------------------------------------------------- /python/06-modules.py: -------------------------------------------------------------------------------- 1 | ########## Intro to modules ########## 2 | 3 | #A module is just a fancy name for a python file 4 | #By convention, they are often imported at the top of a file 5 | #but you can do it anywhere 6 | import math 7 | import pickle 8 | import queue 9 | import heapq 10 | import json 11 | import random 12 | 13 | print(pickle) 14 | #You will get a path like so (I'm on a mac) 15 | #/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/pickle.py 16 | #Explore this folder to see some other options. 17 | #Or, check out this: https://docs.python.org/3/py-modindex.html 18 | 19 | #We use the module with dot notation to access the functions or variables 20 | #an object of type module 21 | print(math.pi) 22 | print(type(math)) 23 | 24 | #Here is another example 25 | #Pseudorandom number 0-100 (inclusive) 26 | print(random.randint(0, 100)) 27 | 28 | #You can see how this works by opening random.py 29 | #from random.py line 244: 30 | #def randint(self, a, b): 31 | # """Return random integer in range [a, b], including both end points. 32 | # """ 33 | # return self.randrange(a, b+1) 34 | 35 | 36 | """ 37 | This is a side note that we may get into in more detail later 38 | When you create a file to be imported, 39 | you can expose certain pieces as seen in random.py 40 | 41 | line 786... 42 | _inst = Random() 43 | seed = _inst.seed 44 | random = _inst.random 45 | ... 46 | randrange = _inst.randrange 47 | 48 | Then when we import random, we prefix with that module name: 49 | random.randrange 50 | 51 | This will access .random on an instantiated Random object 52 | Which is then exposed through __all__ 53 | 54 | "...is easier for the casual user than making them 55 | # instantiate their own Random() instance." 56 | 57 | As opposed to something like this: 58 | 59 | test = random.Random() 60 | print(test.randint(5,10)) 61 | """ 62 | 63 | 64 | ########## From module import Something ########## 65 | 66 | 67 | #in the previous section we showed how to import something. 68 | import random 69 | 70 | print(type(random)) 71 | #Doing this requires us to access the module using the dot operator 72 | 73 | #As an alternative, we can import one specific thing from the module 74 | 75 | from random import randint, seed 76 | print("from random import randit:", randint(5,5)) #always 5 lol 77 | 78 | #This replaces anything locally called randint: 79 | randint = "SUPER IMPORTANT DATA DON'T DELETE!!!!" 80 | from random import randint 81 | 82 | print("RIP data:", randint) 83 | 84 | 85 | ########## Alias an import ########## 86 | 87 | 88 | import random as r 89 | 90 | print("r.randint:", r.randint(6,6)) 91 | 92 | #This can be used to preserve data locally: 93 | 94 | randint = "SUPER IMPORTANT DATA DON'T DELETE!!!!" 95 | from random import randint as ri 96 | 97 | print("ri:", ri(7,7)) 98 | print("NOT LOST!", randint) 99 | 100 | ########## import * ########## 101 | 102 | #We now we can bring one specific item from a module using 103 | from random import randint 104 | #This puts it directly in our symbol table replacing anything called randint 105 | #You will see sometimes importing everything, even though it's not recommended 106 | #100% guarentee 30% of the time to yeet out something important: 107 | 108 | seed = "watermelon" 109 | from random import * 110 | 111 | print("Today we are going to plant", seed, "seeds! Yay!") #Not what we wanted. 112 | 113 | #We can get a better picture of this by printing the output of dir() 114 | #which shows the identifiers in scope 115 | 116 | a, b, c, e, f, g = 0, 0, 0, 0, 0, 0 #find these: 117 | print(dir()) 118 | 119 | ########## Creating a Module ########## 120 | 121 | 122 | #We can easily create our own module by just creating a python file 123 | #Any variables or functions will be imported 124 | #See utils.py 125 | import utils 126 | print("Range (high-low):", utils.stats_range([5, 3, 5, 1, 10])) 127 | 128 | 129 | ########## sys path ########## 130 | 131 | 132 | #When we created the utils module, it came from the same directory. 133 | #This is part of the default search path 134 | #You can see the places modules are searched for by importing a special module 135 | #https://docs.python.org/3/tutorial/modules.html#standard-modules 136 | 137 | import sys 138 | 139 | #always available, work directly with interpreter 140 | #unlike some other modules. 141 | #import winreg doesn't work for me (im on mac...maybe on windows) 142 | #docs give this example: 143 | sys.ps1 = 'C> ' #(Try it in interactive mode if needed) 144 | 145 | print(sys.path) 146 | 147 | #path prints locations searched for modules. 148 | 149 | #We could move utils up a directory (or anywhere we want) 150 | #and import it like so: 151 | sys.path.append("/Users/calebcurry/Python") 152 | 153 | #There are ways you can do this more dynamically 154 | #https://stackoverflow.com/questions/30218802/get-parent-of-current-directory-from-python-script/39618108 155 | from os.path import dirname, abspath 156 | d = dirname(dirname(abspath(__file__))) 157 | sys.path.append(d) -------------------------------------------------------------------------------- /python/07-dictionaries-sets.py: -------------------------------------------------------------------------------- 1 | ######### INTRO TO DICTIONARIES ######### 2 | 3 | #dictionary stores key-value pairs 4 | #The equiv of an associative array/hash table 5 | emails = { 6 | "Caleb":"caleb@email.com", 7 | "Gal":"g@example.com" 8 | } 9 | 10 | print(emails) 11 | #in this case, the key is the name, email is the value. 12 | #Data type doesn't matter at all for the value. 13 | #Key must be a hashable --> What does this mean? 14 | #Classes have a function __hash__ invoked when used as the key 15 | print(hash("hello")) 16 | 17 | #I'm not sure of exact internals on how the hash is used, but imagine it like so: 18 | #You have an area of memory with 8 spots, and you need to store the value at some spot... 19 | print(hash("hello") % 8) 20 | 21 | #Almost always immutable type (should be, anyway) 22 | #a tuple will work, list will not. a number will work 23 | 24 | #Why use a hashtable? Extremely fast to add or look up data 25 | #O(1) --> constant time. More elements does not mean slower unlike a sort or something 26 | #https://en.wikipedia.org/wiki/Hash_table 27 | #Hashtables often used for memoization 28 | 29 | #Next up we gonna talk about retrieving data from a dictionary 30 | 31 | 32 | ######### RETRIEVE DATA FROM DICTIONARY ########## 33 | 34 | 35 | print(list(emails)) 36 | print(sorted(emails)) 37 | #print(emails[0]) # NOPE! 38 | print(emails["Caleb"]) 39 | 40 | #Since data is not nicely sequenced 41 | #we may want to check before we try grabbing stuff 42 | 43 | if("Caleb" in emails): 44 | print("Emailing", emails["Caleb"]) 45 | 46 | #This may seem bad because we first check to see if its in 47 | #Then we do another line to get the value 48 | #but this is different than a list where we iterate to find the element 49 | #The key is goes through hash to calculate index. Either there or not 50 | #This is O(1) 51 | 52 | #You may still not like the casing and in that situation there is a method 53 | 54 | print(emails.get("Ryan")) #Returns none if not found 55 | print(emails.get("Ryan", "Not found")) #optional return arg if not found 56 | 57 | 58 | ######### ADD DATA TO DICTIONARY ######### 59 | 60 | 61 | #How to add data (3 ways here): 62 | #indexing 63 | emails["josh"] = "josh@j.com" 64 | print(emails) 65 | 66 | #update function 67 | emails.update( {"josh": "evennewer@email.com"}) 68 | print(emails) 69 | 70 | #Weird variation 71 | emails.update(josh = "new@email.com") 72 | print(emails) 73 | 74 | #Key must be hashable 75 | emails[5] = "test" 76 | emails[(1, 2)] = "yep" 77 | #emails[[5, 3]] = "nope" #list is not hashable (mainly cuz mutable) 78 | 79 | 80 | ######### LOOPING THROUGH KEYS ######### 81 | 82 | 83 | #dictionary is an iterable (implements __iter__) 84 | 85 | emails = { 86 | "Caleb":"caleb@email.com", 87 | "Gal":"g@example.com", 88 | "Ted": "talk@gmail.com" 89 | } 90 | 91 | #k is a variable but k by convention for key 92 | for k in emails: 93 | print(k) 94 | 95 | #You can use the key to get the element 96 | #Not ideal. 97 | #One reason being the key has to be hashed to get the value associated with it. 98 | #(but will show better way in next section) 99 | for k in emails: 100 | print("index", k, "is", emails[k]) 101 | 102 | 103 | ######### LOOPING THROUGH KEY-VALUE PAIRS ######### 104 | 105 | 106 | #In the prev section we used the index with []. 107 | #Although it works, you can do this: 108 | 109 | for k, elem in emails.items(): 110 | print(k, elem) 111 | 112 | #Each iteration k will be the key and elem will be the item found at this key. 113 | 114 | #As an example of what a hashtable can be used for, you can keep track of occurances: 115 | 116 | conjunctions = {"but": 0, "or": 0, "so": 0, "and": 0, "yet": 0, "for": 0, "nor": 0} #fanboys 117 | 118 | completely_original_poem = """I still hear your voice when you sleep next to me 119 | I still feel your touch in my dreams 120 | Forgive me my weakness, but I don't know why 121 | Without you it's hard to survive 122 | 'Cause every time we touch, I get this feeling 123 | And every time we kiss I swear I could fly 124 | Can't you feel my heart beat fast, I want this to last 125 | Need you by my side""" 126 | 127 | words = completely_original_poem.split() 128 | 129 | for word in words: 130 | if str.lower(word) in conjunctions: 131 | conjunctions[str.lower(word)] += 1 132 | 133 | print(conjunctions) 134 | 135 | #This could easily be wrapped in a function to take a msg and words to look for, returning a dict 136 | #concept can be used to analyze documents to quantify how vulgar they are, search for phrases, etc 137 | #dictionaries can be used to keep track of values that are hard to calculate (memoization) 138 | 139 | 140 | ######### SETS EXPLAINED ######### 141 | 142 | 143 | #Sets are similar to dictionaries in that the data is hashed and it is unordered. 144 | #Sets are similar to lists in that they just contain the data and not a key-value pair 145 | #Sets are different than lists in that you cannot have duplicates 146 | 147 | stuff = {"sword", "rubber duck", "sice a pizza"} 148 | print("sword" in stuff) 149 | print(stuff) 150 | stuff.add("sword") 151 | print(stuff) 152 | #Notice only one occurance of sword even though already added 153 | 154 | #How is a set different than a dictionary? 155 | #For a set, each element is only one piece of data 156 | #for a dictionary, it is a key-value pair. 157 | 158 | #Behind the scenes, they both use hashing. The hashing is used to determine where to store the data. 159 | #For dictionaries, the KEY is hashed 160 | #for sets, we do not have a key, so the data itself is hashed. 161 | #This means we cannot store something in sets that is not hashable. 162 | 163 | #stuff.add(["trying to add a list"]) 164 | 165 | #It's important to understand the purpose of a set... 166 | #Easily check if element in set 167 | #such as to easily check to see if something has been tagged 168 | #To do various set operations (coming soon) 169 | 170 | #An example would be to see if a word is ever used in a phrase. Not counted (that wold be a dictionary) 171 | 172 | conjunctions = {"but", "or", "so", "and", "yet", "for", "nor"} #fanboys 173 | seen = set() #THERE'S NOT AN EMPTY SET LITERAL!! #learn something new every day 174 | completely_original_poem = """I still hear your voice when you sleep next to me 175 | I still feel your touch in my dreams 176 | Forgive me my weakness, but I don't know why 177 | Without you it's hard to survive 178 | 'Cause every time we touch, I get this feeling 179 | And every time we kiss I swear I could fly 180 | Can't you feel my heart beat fast, I want this to last 181 | Need you by my side""" 182 | 183 | words = completely_original_poem.split() 184 | 185 | for word in words: 186 | if str.lower(word) in conjunctions: 187 | seen.add(str.lower(word)) 188 | 189 | print(seen) 190 | 191 | 192 | ######### REMOVE DUPLICATES FROM LIST / CREATE SET FROM LIST ########## 193 | 194 | #You can remove duplicate elements from a list by converting it to a set and back. 195 | 196 | colors = ["red", "red", "green", "green", "blue", "blue", "blue"] 197 | 198 | print(id(colors), colors) 199 | 200 | colors[:] = list(set(colors)) 201 | 202 | print(id(colors), colors) 203 | 204 | 205 | #Earlier on in our life I showed some code to count each type of element in a list. 206 | 207 | colors = ["red", "red", "green", "green", "blue", "blue", "blue"] 208 | 209 | counts = [[colors.count(item), item] for item in set(colors)] 210 | 211 | print(counts) 212 | 213 | #This works because is iterates through the set {"red", "green", "blue"} counting each in colors 214 | 215 | 216 | ######### UNION AND INTERSECTION ######### 217 | 218 | my_fav = {"red", "green", "black", "blue", "purple"} 219 | her_fav= {"blue", "orange", "purple", "green"} 220 | 221 | #union 222 | all_favs = my_fav | her_fav 223 | print(all_favs) #no repetition 224 | #You may see + to combine lists, in which there are repeats. 225 | #But we are not working with lists...so i'll try to focus here. 226 | 227 | #intersection (elements shared between both) 228 | wedding_colors = my_fav & her_fav 229 | print(wedding_colors) 230 | #this is like the inside section of a venn diagram 231 | 232 | #There are also method versions: 233 | all_favs = my_fav.union(her_fav) 234 | print(all_favs) 235 | 236 | wedding_colors = my_fav.intersection(her_fav) 237 | print(wedding_colors) 238 | 239 | 240 | ######### DIFFERENCE AND SYMMETRIC DIFFERENCE ######### 241 | 242 | 243 | my_fav = {"red", "green", "black", "blue", "purple"} 244 | her_fav= {"blue", "orange", "purple", "green"} 245 | 246 | #Difference 247 | only_my_colors = my_fav - her_fav 248 | print(only_my_colors) #elements in left getting rid of all in right. 249 | #Could go other way too: 250 | only_her_colors = her_fav - my_fav 251 | print(only_her_colors) 252 | 253 | #symmetric difference is like if you took colors only I liked union with colors only she liked and put em together: 254 | 255 | symmetric = my_fav ^ her_fav 256 | print(symmetric) 257 | 258 | #This is like: 259 | symmetric = only_my_colors | only_her_colors 260 | print(symmetric) 261 | 262 | #like union and intersection, there are method versions that return. --> .difference and .symmetric_difference -------------------------------------------------------------------------------- /python/08-oop-basics.py: -------------------------------------------------------------------------------- 1 | 2 | ########## Create a Class and __init__ ########## 3 | 4 | 5 | #This section is designed to be a simple introduction to object oriented programming 6 | #We are in no way covering everything... 7 | #Probably will do OOP or intermediate Python series dedicated to this stuff 8 | 9 | class Book(): 10 | pass 11 | 12 | book = Book() 13 | print(book) 14 | 15 | #When we say Book() we are instantiating a new object 16 | #This object iws assigned to the book variable 17 | #Printing it gives us the type and memory location 18 | #You can also get the type: 19 | 20 | print(type(book)) 21 | 22 | #We can check type like so: 23 | 24 | if isinstance(book, Book): 25 | print("It is indeed book. Read it") 26 | else: 27 | print("nope, not a book") 28 | 29 | #We can use the class to make numerous books: 30 | book2 = Book() 31 | #Consider the class as the cookie cutter to make numerous cookies. 32 | 33 | #We can add attributes to any object dynamically like so: 34 | book.title = "Goodnight Moon" 35 | print(book.title) 36 | 37 | #This is cool and all but every book has a title, so we can make it part of the structure 38 | #This requires a bit more syntax... 39 | #also notice that you can override any class as we go. 40 | class Book(): 41 | def __init__(self, title): 42 | self.title = title 43 | 44 | #consider this the constructor, or the function that is invoked when we create a book. 45 | #self refers to the book being created and we don't have to worry about passing that, it's implicit 46 | #Title is passed in as an argument, and assigned to self.title (the title of the book) 47 | #We will explore this in more detail in a video soon. 48 | 49 | #We then pass a title to the Book as we create it: 50 | book = Book("Goodnight Moon Again") 51 | book2 = Book("Are You My Mother") 52 | print(book.title) 53 | print(book2.title) 54 | 55 | #This will now fail as title is required :) 56 | #book3 = Book() 57 | 58 | #If you want the title to be optional you can give it a default (either a value or None): 59 | 60 | class Book(): 61 | def __init__(self, title=None): 62 | self.title = title 63 | 64 | book = Book() 65 | print(book.title) #Still exists just no value. 66 | 67 | #This fails as .test doesn't exist. 68 | #print(book.test) 69 | 70 | #Next up we are going to create methods in our class. 71 | 72 | 73 | ########## Methods ########## 74 | 75 | 76 | #A method is just a function on an object. 77 | #We can define any functions to be attached to our objects by putting em in our class 78 | #We just have to have the implicit parameter self 79 | 80 | class Book(): 81 | def __init__(self, title, pages): 82 | self.title = title 83 | self.pages = pages 84 | 85 | def log(self): 86 | print(f"{self.title} is {self.pages} pages long") 87 | 88 | def is_short(self): 89 | if self.pages < 100: 90 | return True 91 | 92 | book = Book("Are You My Mother?", 72) 93 | book.log() #no need to pass anything to self parameter. 94 | 95 | #A note on __init__ 96 | #__init__ is also a method, but it's special in that it is invoked automatically 97 | #When we create an object. 98 | #There are a lot of methods with a similar naming structure we are going to see. 99 | #__eq__, __hash__, __str__, etc. 100 | 101 | if book.is_short(): 102 | #do something 103 | print("read book") 104 | else: 105 | print("Aint got time for that") 106 | 107 | #Next up I want to explain this self parameter we've been seeing 108 | 109 | #Without methods, we would have to create functions like this: 110 | 111 | def book_is_short(book): 112 | if book.pages < 100: 113 | return True 114 | 115 | if book_is_short(book): 116 | #do something 117 | print("read book") 118 | else: 119 | print("Aint got time for that") 120 | 121 | #Which would work but not ideal as we'd easily be overwhelemed with so many functions 122 | #And no organization. It's ideally attached to the object as it's related to the object. 123 | 124 | 125 | ########## Class Level Variables ########## 126 | 127 | 128 | #We're going to talk about class variables. 129 | #Coming from another language, this would be the closest thing to "static" members 130 | #First, we need to understand self. 131 | 132 | #self refers to the object things are being invoked on, 133 | #When we create an object. __init__ assigns stuff to self 134 | #That allows each object to have attributes. 135 | 136 | #Any time we create a method, we have self as a parameter. 137 | #This means the method is attached to each object. 138 | 139 | #if we leave off self, we are creating it at the class level, which is shared for all objects 140 | 141 | 142 | class Book(): 143 | favs = [] #class 144 | 145 | def __init__(self, title, pages): 146 | self.title = title 147 | self.pages = pages 148 | 149 | def log(self): 150 | print(f"{self.title} is {self.pages} pages long") 151 | 152 | def is_short(self): 153 | if self.pages < 100: 154 | return True 155 | 156 | 157 | book = Book("Are You My Mother?", 72) 158 | book2 = Book("The Digging-est Dog", 72) 159 | 160 | Book.favs.append(book) 161 | Book.favs.append(book2) 162 | 163 | print(Book.favs) #Favs is related to books, but not tied to one individual book 164 | #We use self as a parameter if it's unique to each object :) 165 | 166 | 167 | ########## __str__ ########## 168 | ########## __eq__ ########## 169 | ########## __hash__ and Collections ########## 170 | 171 | 172 | #To save save space we are combing the code for all three of these sections. 173 | 174 | class Book(): 175 | favs = [] #class 176 | 177 | def __init__(self, title, pages): 178 | self.title = title 179 | self.pages = pages 180 | 181 | def is_short(self): 182 | return self.pages < 100 183 | 184 | #What happens when you pass object to print? 185 | def __str__(self): 186 | return f"{self.title}, {self.pages} pages long" 187 | 188 | #What happens when you use ==? 189 | def __eq__(self, other): 190 | return self.title == other.title and self.pages == other.pages 191 | 192 | #It's approriate to give something for __hash__ when you override __eq__ 193 | # #This is the recommended way if mutable (like it is here): 194 | __hash__ = None 195 | 196 | #If should immutable, you could do something like this. 197 | #This replaces __hash__ = None 198 | # def __hash__(self): 199 | # return hash(self.title) ^ hash(self.pages) #xor with hash of attributes 200 | # #from Mastering Object-Oriented Python 201 | 202 | book = Book("Are You My Mother", 72) 203 | equal_book = Book("Are You My Mother", 72) 204 | print("Are they considered equal?", book == equal_book) #yep 205 | print("Are they the same object?", book is equal_book) #nope 206 | book2 = Book("The Digging-est Dog", 72) 207 | 208 | print(hash(book), hash(book2)) -------------------------------------------------------------------------------- /python/09-objects-io.py: -------------------------------------------------------------------------------- 1 | class Book(): 2 | favs = [] #class 3 | 4 | def __init__(self, title, pages): 5 | self.title = title 6 | self.pages = pages 7 | 8 | def is_short(self): 9 | return self.pages < 100 10 | 11 | #What happens when you pass object to print? 12 | def __str__(self): 13 | return f"{self.title}, {self.pages} pages long" 14 | 15 | #What happens when you use ==? 16 | def __eq__(self, other): 17 | return self.title == other.title and self.pages == other.pages 18 | 19 | #It's approriate to give something for __hash__ when you override __eq__ 20 | # #This is the recommended way if mutable (like it is here): 21 | __hash__ = None 22 | 23 | 24 | ########## Passing by Object Reference ########## 25 | 26 | 27 | book = Book("Where Is My Mother?", 100) 28 | print(book) 29 | 30 | def modify(book): 31 | book.title = "Changed noob" 32 | 33 | modify(book) 34 | print(book) 35 | 36 | #What is we print id to follow? 37 | 38 | def modify(book): 39 | print(id(book)) 40 | book.title = "Changed noob" 41 | print(id(book)) 42 | 43 | print(id(book)) 44 | modify(book) 45 | print(id(book)) 46 | 47 | #We get the same number for everything 48 | 49 | book = Book("Are You My Mother?", 100) 50 | print("let's reassign") 51 | def modify(book): 52 | print(id(book)) 53 | book = Book("Changed noob", 100) 54 | print(id(book)) #This is a different id. 55 | #The original is unchanged. Reassigning 56 | 57 | print(id(book)) 58 | modify(book) 59 | print(id(book)) 60 | print(book) #Stayed the same! 61 | 62 | 63 | ########## Reading from a file ########## 64 | 65 | file = open("input.txt", "a") #append. Creates if not there 66 | file = open("input.txt", "w") #overwrites 67 | #file = open("input.txt", "r+") #Read and write. Throws exception if not there 68 | #not as easy to work with on r/w in my oppinion 69 | 70 | #\t to sep title from page count 71 | file.write("Are You My Mother?\t72\n") 72 | file.write("The Digging-est Dog\t72") 73 | file.close() #close when done 74 | 75 | file = open("input.txt", "r") 76 | 77 | #for line in file: 78 | # print(line, end="") #end="" as \n is kept in line 79 | #print() 80 | 81 | #Numerous ways to read into list. Here is one. 82 | data = file.read().split('\n') 83 | print(data) 84 | #https://stackoverflow.com/questions/3277503/how-to-read-a-file-line-by-line-into-a-list 85 | 86 | file.close() 87 | 88 | #Each line is title\tpages so we split it. 89 | book1_data = data[0].split('\t') 90 | book = Book(book1_data[0], book1_data[1]) 91 | 92 | book2_data = data[1].split('\t') 93 | book2 = Book(book2_data[0], book2_data[1]) 94 | 95 | print(book) 96 | print(book2) 97 | 98 | 99 | ########## Intro to Exception handling ########## 100 | 101 | 102 | #When working with files (or doing anything in programming), 103 | #Exceptions can be thrown 104 | 105 | #file = open("doesntexist.csv", "r") #get wrecked son 106 | 107 | try: 108 | file = open("doesntexist.csv", "r") 109 | except Exception as e: 110 | print(type(e)) 111 | print(e) 112 | 113 | try: 114 | file = open("input.txt", "r") #Make sure it exists 115 | data = int(file.read()) #This should fail 116 | except FileNotFoundError as e: #subclass of OSError 117 | print("This file is not found") 118 | except OSError as e: 119 | print("Couldn't open file") 120 | except PermissionError as e: 121 | print("file is locked") 122 | except ValueError as e: 123 | print("Cannot parse data. Check file") 124 | except Exception as e: 125 | print(type(e)) 126 | print(e) 127 | finally: 128 | file.close() 129 | print("Always runs") 130 | 131 | 132 | ########## with keyword ########## 133 | 134 | #shorthand for opening file and automatically closed outside indent 135 | with open("input.txt", "r") as file: #Make sure it exists 136 | 137 | try: 138 | int(file.read()) 139 | except: #example of using thin except here 140 | print("parse error...etc...") 141 | #do whatever 142 | 143 | print(file.closed) #closed 144 | 145 | #opening can still throw an exception...Maybe do it like so: 146 | try: 147 | with open("no", "r") as file: 148 | int(file.read()) 149 | except Exception as e: 150 | print(e) 151 | 152 | #I think this could be written like so but may require another try inside else: 153 | try: 154 | file = open('nope') 155 | except OSError as e: 156 | print(e) 157 | else: 158 | with file: 159 | #try: 160 | file.read() 161 | #except Exception as e: 162 | # print(e) 163 | 164 | #https://stackoverflow.com/questions/40640956/python-with-open-except-filenotfounderror/40641103 165 | #https://stackoverflow.com/questions/28633555/how-to-handle-filenotfounderror-when-try-except-ioerror-does-not-catch-it -------------------------------------------------------------------------------- /python/10-consume-sdk.py: -------------------------------------------------------------------------------- 1 | def print_menu(): 2 | print("""Choose a number: 3 | 1. Print all books 4 | 2. Add a book 5 | 3. Delete a book 6 | 4. Update a book 7 | 0. QUIT""") 8 | 9 | """ 10 | print("Hello, Welcome to your reading list.") 11 | while(True): 12 | print_menu() 13 | response = int(input()) 14 | if response == 1: 15 | print("Here are all of your books") 16 | elif response == 2: 17 | print("adding a book") 18 | elif response == 3: 19 | print("Deleting a book") 20 | elif response == 4: 21 | print("Updating a book") 22 | else: 23 | print("Good luck reading!") 24 | break 25 | """ 26 | 27 | ########### CONUMSING SDK ########## 28 | 29 | 30 | #This brought up some questions on SDK design 31 | #Should deleting/updating a book require book object or just title? ID? So many options 32 | #Not very easy to maintain object as you might easily do with a UI. 33 | 34 | import booksSDK 35 | from book import Book 36 | 37 | print("Hello, Welcome to your reading list.") 38 | while(True): 39 | print_menu() 40 | response = int(input()) 41 | if response == 1: 42 | print("Here are all of your books:") 43 | for book in booksSDK.get_books(): 44 | print(book) 45 | elif response == 2: 46 | print("Title?") 47 | title = input() 48 | print("Pages?") 49 | pages = input() 50 | booksSDK.add_book(Book(title, pages)) 51 | elif response == 3: 52 | print("Title?") 53 | title = input() 54 | print("Pages?") 55 | pages = input() 56 | booksSDK.delete_book(Book(title, pages)) 57 | elif response == 4: 58 | print("Current title?") 59 | current_title = input() 60 | print("Current pages?") 61 | current_pages = input() 62 | print("New title (s for same)") 63 | new_title = input() 64 | if str.lower(new_title) == 's': 65 | new_title = current_title 66 | print("New pages? (s for same)") 67 | new_pages = input() 68 | if str.lower(new_pages) == 's': 69 | new_pages = current_pages 70 | booksSDK.update_book(Book(current_title, current_pages), new_title, new_pages) 71 | else: 72 | print("Good luck reading!") 73 | break -------------------------------------------------------------------------------- /python/10-sql.py: -------------------------------------------------------------------------------- 1 | ########## Intro to SQLite and Creating a Database ########## 2 | 3 | import sqlite3 #included with Python 4 | 5 | conn = sqlite3.connect(":memory:") 6 | 7 | #creating this goes off of the cwd. CD in terminal changes cwd 8 | #so either cd to correct folder or figure out how to do a more concrete path: 9 | #import os.path 10 | #conn = sqlite3.connect(os.path.realpath('./books.db')) 11 | 12 | 13 | #we use a cusror object to work with the database 14 | c = conn.cursor() 15 | #https://stackoverflow.com/questions/6318126/why-do-you-need-to-create-a-cursor-when-querying-a-sqlite-database 16 | 17 | 18 | ########## Create a Table with Python ########## 19 | 20 | # Create table 21 | c.execute('''CREATE TABLE books 22 | (title TEXT, pages INTEGER)''') 23 | 24 | 25 | ########## Insert Data with Python ########## 26 | 27 | 28 | # Insert a row of data 29 | c.execute("INSERT INTO books VALUES ('Are You My Mother?', 72)") 30 | 31 | # Save (commit) the changes 32 | conn.commit() 33 | 34 | 35 | ########## Retrieve Data in Python ########## 36 | 37 | c.execute('SELECT * FROM books WHERE title=?', ('Are You My Mother?',)) 38 | print(c.fetchone()) 39 | 40 | books = [ 41 | ('The Digging-est Dog', 72), 42 | ('Goodnight Moon', 31), 43 | ('The Giving Tree', 66) 44 | ] 45 | 46 | c.executemany('INSERT INTO books VALUES (?,?)', books) 47 | conn.commit() 48 | 49 | c.execute('SELECT * FROM books') 50 | data = c.fetchall() 51 | print(data) 52 | 53 | 54 | ########## Delete SQLite data in Python ########## 55 | 56 | c.execute('SELECT * FROM books WHERE title=?', ('Are You My Mother?',)) 57 | print(c.fetchone()) 58 | c.execute('DELETE FROM books WHERE title=?', ('Are You My Mother?',)) #don't forget where lol 59 | c.execute('SELECT * FROM books WHERE title=?', ('Are You My Mother?',)) 60 | print(c.fetchone()) 61 | 62 | 63 | ########## Update SQLite Data in Python ########## 64 | 65 | c.execute('SELECT * FROM books WHERE title=?', ('Goodnight Moon',)) 66 | print(c.fetchone()) 67 | c.execute('UPDATE books SET pages="30" WHERE title="Goodnight Moon"') 68 | c.execute('SELECT * FROM books WHERE title=?', ('Goodnight Moon',)) 69 | print(c.fetchone()) 70 | conn.commit 71 | c.close() 72 | 73 | ########## Create an SDK ########## 74 | 75 | 76 | import booksSDK 77 | from book import Book 78 | 79 | book = Book("Are You My Mother?", 1000) 80 | print("Added book id:", booksSDK.add_book(book)) 81 | print("Get book by title:", booksSDK.get_book_by_title(book.title)) 82 | print("Not a valid book:", booksSDK.get_book_by_title("yeet")) 83 | 84 | booksSDK.add_book(Book('The Digging-est Dog', 76)) 85 | print("get books:", booksSDK.get_books()) 86 | 87 | book = booksSDK.update_book(book, book.title, 76) 88 | print("Updated book:", book) 89 | print("Deleted:", booksSDK.delete_book(book)) 90 | print("After delete:", booksSDK.get_book_by_title("Are You My Mother?")) 91 | 92 | print("All books:", booksSDK.get_books()) 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /python/11-tk-guessing.py: -------------------------------------------------------------------------------- 1 | ########## Intro to GUI App Development ########## 2 | 3 | 4 | #There are numerous "frameworks" you can use to build a user interface with Python 5 | #This is to build desktop applications. 6 | #Although there may be some debate on which is best, 7 | #you can probably get the job done with any 8 | #tkinter is build it. So that's what we are going to learn first. 9 | 10 | #Seperation between functionality and UI is ideal 11 | #Because of this, we try to keep logic in the UI code minimal 12 | #We can make this easier by creating an SDK to work with the Db (as we did) 13 | #Long term goal is to actually create an API we can consume... 14 | #We'll get into this, but essentially we can have the same backend for: 15 | # Desktop app 16 | # CLI 17 | # Web App 18 | # Mobile App 19 | # Etc... 20 | 21 | #For now we are going to use the SDK, build out a UI, and then later an API 22 | 23 | """ 24 | #Getting started 25 | #Because tkinter is built in, we don't have to download or install anything. 26 | #We just import it: 27 | import tkinter 28 | tk = tkinter.Tk() #This is the start up code just to get a window 29 | #We can modify the window title like so: 30 | tk.title("This is a Title") 31 | tk.mainloop() #This will "start" the application. 32 | print("This will wait") 33 | """ 34 | 35 | #Let's build a small application: 36 | 37 | from random import randint 38 | import tkinter 39 | from tkinter import messagebox 40 | 41 | low = 0 42 | high = 20 43 | rand = randint(low, high) 44 | def check(guess): 45 | print(guess) 46 | if guess < rand: 47 | #tkinter.messagebox.showinfo("No", "You guessed " + str(guess)).pack 48 | tkinter.Label(tk, text=f"{guess} is low").pack() 49 | elif guess > rand: 50 | tkinter.Label(tk, text=f"{guess} is high").pack() 51 | else: 52 | tkinter.messagebox.showinfo("You win!", f"{guess} is correct!") 53 | 54 | tk = tkinter.Tk() 55 | tk.title("Guessing Game") 56 | guess_goal = tkinter.Label(tk, text=f"Guess a number {low} to {high} (inclusive)") 57 | guess_goal.pack() 58 | entry = tkinter.Entry(tk) 59 | entry.pack() 60 | button = tkinter.Button(tk, text="Take a guess", command=lambda: check(int(entry.get()))) 61 | button.pack() 62 | tk.mainloop() 63 | 64 | ########## Tkinter basics ########## 65 | ########## Displaying a List of Data with Tkinter ########## 66 | ########## Removing List Items in Tkinter ########## 67 | ########## Working with SQLlite in Tkinter ########## 68 | 69 | 70 | 71 | 72 | """ 73 | frame = tkinter.Frame(tk, relief=RIDGE, borderwidth=2) 74 | frame.pack(fill=BOTH,expand=1) 75 | label = tkinter.Label(frame, text="Hello, World") 76 | label.pack(fill=X, expand=1) 77 | button = tkinter.Button(frame,text="Exit",command=tk.destroy) 78 | button.pack(side=BOTTOM) 79 | tk.mainloop() 80 | """ -------------------------------------------------------------------------------- /python/11-tk-list.py: -------------------------------------------------------------------------------- 1 | 2 | import tkinter 3 | from book import Book 4 | import booksSDK 5 | 6 | tk = tkinter.Tk() 7 | books = [] 8 | 9 | def add_to_list(): 10 | 11 | if title.get() == "" or pages.get() == "": 12 | return 13 | 14 | book = Book(title.get(), int(pages.get())) 15 | print(book) 16 | if(booksSDK.add_book(book)): 17 | books.append(book) 18 | lb.insert(tkinter.END, book) 19 | title.delete(0, tkinter.END) 20 | pages.delete(0, tkinter.END) 21 | 22 | def delete_from_list(): 23 | index_tuple = lb.curselection() 24 | if booksSDK.delete_book(books.pop(index_tuple[0])): 25 | lb.delete((index_tuple)) 26 | 27 | lb = tkinter.Listbox(tk) 28 | 29 | for book in booksSDK.get_books(): 30 | books.append(book) 31 | lb.insert(tkinter.END, book) 32 | 33 | lb.pack() 34 | 35 | add = tkinter.Button(tk, text="Add Book", command=add_to_list) 36 | add.pack() 37 | 38 | delete = tkinter.Button(tk, text="Delete Book", command=delete_from_list) 39 | delete.pack() 40 | 41 | tkinter.Label(tk, text="Title:").pack() 42 | title = tkinter.Entry(tk, text="Title to Add:") 43 | title.pack() 44 | 45 | tkinter.Label(tk, text="Pages:").pack() 46 | pages = tkinter.Entry(tk, text="Number of pages:") 47 | pages.pack() 48 | 49 | tk.mainloop() 50 | -------------------------------------------------------------------------------- /python/book.py: -------------------------------------------------------------------------------- 1 | class Book(): 2 | favs = [] 3 | 4 | def __init__(self, title, pages): 5 | self.title = title 6 | self.pages = pages 7 | 8 | def is_short(self): 9 | return self.pages < 100 10 | 11 | def __str__(self): 12 | return f"{self.title}, {self.pages} pages long" 13 | 14 | def __eq__(self, other): 15 | return self.title == other.title and self.pages == other.pages 16 | 17 | 18 | __hash__ = None 19 | 20 | def __repr__(self): #added to make list of items invoke str 21 | return self.__str__() 22 | -------------------------------------------------------------------------------- /python/booksSDK.py: -------------------------------------------------------------------------------- 1 | 2 | from book import Book 3 | import sqlite3 4 | import os.path 5 | 6 | l = os.path.realpath( 7 | os.path.join(os.getcwd(), os.path.dirname(__file__))) 8 | 9 | conn = sqlite3.connect(os.path.join(l, 'books.db')) 10 | 11 | c = conn.cursor() 12 | # Create table 13 | c.execute('''CREATE TABLE IF NOT EXISTS books 14 | (title TEXT, pages INTEGER)''') 15 | 16 | def cursor(): 17 | #https://stackoverflow.com/questions/14511337/efficiency-of-reopening-sqlite-database-after-each-query/14520670 18 | 19 | l = os.path.realpath( 20 | os.path.join(os.getcwd(), os.path.dirname(__file__))) 21 | return sqlite3.connect(os.path.join(l, 'books.db')).cursor() 22 | 23 | def add_book(book): 24 | c = cursor() 25 | with c.connection: 26 | c.execute("INSERT INTO books VALUES (?, ?)", (book.title, book.pages)) 27 | c.connection.close() 28 | return c.lastrowid 29 | 30 | def get_book_by_title(title): 31 | c = cursor() 32 | c.execute('SELECT * FROM books WHERE title=?', (title,)) 33 | data = c.fetchone() 34 | c.connection.close() 35 | 36 | if not data: 37 | return None 38 | 39 | return Book(data[0], data[1]) 40 | 41 | def get_books(): 42 | c = cursor() 43 | books = [] 44 | for row in c.execute('SELECT * FROM books'): 45 | books.append(Book(row[0], row[1])) 46 | c.connection.close() 47 | return books 48 | 49 | def update_book(book, new_title, new_pages): 50 | c = cursor() 51 | with c.connection: #don't forget this part. 52 | c.execute('UPDATE books SET title=?, pages=? WHERE title=? AND pages=?', 53 | (new_title, new_pages, book.title, book.pages)) 54 | book = get_book_by_title(book.title) #after commit 55 | c.connection.close() 56 | return book 57 | 58 | def delete_book(book): 59 | c = cursor() 60 | with c.connection: 61 | c.execute('DELETE FROM books WHERE title=? AND pages=?', (book.title, book.pages)) 62 | rows = c.rowcount 63 | c.connection.close() 64 | return rows -------------------------------------------------------------------------------- /python/utils.py: -------------------------------------------------------------------------------- 1 | def stats_range(data): 2 | sorted_data = sorted(data) 3 | return sorted_data[-1] - sorted_data[0] -------------------------------------------------------------------------------- /python/webdev/books/books/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CalebCurry/python/c34766df18e59b1c48f5fcef0ba75a97c2605fc3/python/webdev/books/books/__init__.py -------------------------------------------------------------------------------- /python/webdev/books/books/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for books project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'books.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /python/webdev/books/books/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for books project. 3 | 4 | Generated by 'django-admin startproject' using Django 3.0.5. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.0/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/3.0/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = 'f@fa&3!dzq*60q7+&r=l%bf!l*5rfr31f9kx-te)9)+3d60$8m' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = [] 29 | 30 | 31 | # Application definition 32 | 33 | INSTALLED_APPS = [ 34 | 'django.contrib.admin', 35 | 'django.contrib.auth', 36 | 'django.contrib.contenttypes', 37 | 'django.contrib.sessions', 38 | 'django.contrib.messages', 39 | 'django.contrib.staticfiles', 40 | 'reading.apps.ReadingConfig' 41 | ] 42 | 43 | MIDDLEWARE = [ 44 | 'django.middleware.security.SecurityMiddleware', 45 | 'django.contrib.sessions.middleware.SessionMiddleware', 46 | 'django.middleware.common.CommonMiddleware', 47 | 'django.middleware.csrf.CsrfViewMiddleware', 48 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 49 | 'django.contrib.messages.middleware.MessageMiddleware', 50 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 51 | ] 52 | 53 | ROOT_URLCONF = 'books.urls' 54 | 55 | TEMPLATES = [ 56 | { 57 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 58 | 'DIRS': [], 59 | 'APP_DIRS': True, 60 | 'OPTIONS': { 61 | 'context_processors': [ 62 | 'django.template.context_processors.debug', 63 | 'django.template.context_processors.request', 64 | 'django.contrib.auth.context_processors.auth', 65 | 'django.contrib.messages.context_processors.messages', 66 | ], 67 | }, 68 | }, 69 | ] 70 | 71 | WSGI_APPLICATION = 'books.wsgi.application' 72 | 73 | 74 | # Database 75 | # https://docs.djangoproject.com/en/3.0/ref/settings/#databases 76 | 77 | DATABASES = { 78 | 'default': { 79 | 'ENGINE': 'django.db.backends.sqlite3', 80 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 81 | } 82 | } 83 | 84 | 85 | # Password validation 86 | # https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators 87 | 88 | AUTH_PASSWORD_VALIDATORS = [ 89 | { 90 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 91 | }, 92 | { 93 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 94 | }, 95 | { 96 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 97 | }, 98 | { 99 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 100 | }, 101 | ] 102 | 103 | 104 | # Internationalization 105 | # https://docs.djangoproject.com/en/3.0/topics/i18n/ 106 | 107 | LANGUAGE_CODE = 'en-us' 108 | 109 | TIME_ZONE = 'UTC' 110 | 111 | USE_I18N = True 112 | 113 | USE_L10N = True 114 | 115 | USE_TZ = True 116 | 117 | 118 | # Static files (CSS, JavaScript, Images) 119 | # https://docs.djangoproject.com/en/3.0/howto/static-files/ 120 | 121 | STATIC_URL = '/static/' 122 | -------------------------------------------------------------------------------- /python/webdev/books/books/urls.py: -------------------------------------------------------------------------------- 1 | """books URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/3.0/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import include, path 18 | 19 | urlpatterns = [ 20 | path('reading/', include('reading.urls')), 21 | path('admin/', admin.site.urls), 22 | ] 23 | -------------------------------------------------------------------------------- /python/webdev/books/books/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for books project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.0/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'books.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /python/webdev/books/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'books.settings') 9 | try: 10 | from django.core.management import execute_from_command_line 11 | except ImportError as exc: 12 | raise ImportError( 13 | "Couldn't import Django. Are you sure it's installed and " 14 | "available on your PYTHONPATH environment variable? Did you " 15 | "forget to activate a virtual environment?" 16 | ) from exc 17 | execute_from_command_line(sys.argv) 18 | 19 | 20 | if __name__ == '__main__': 21 | main() 22 | -------------------------------------------------------------------------------- /python/webdev/books/reading/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CalebCurry/python/c34766df18e59b1c48f5fcef0ba75a97c2605fc3/python/webdev/books/reading/__init__.py -------------------------------------------------------------------------------- /python/webdev/books/reading/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /python/webdev/books/reading/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ReadingConfig(AppConfig): 5 | name = 'reading' 6 | -------------------------------------------------------------------------------- /python/webdev/books/reading/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.0.5 on 2020-04-28 12:57 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | initial = True 9 | 10 | dependencies = [ 11 | ] 12 | 13 | operations = [ 14 | migrations.CreateModel( 15 | name='Book', 16 | fields=[ 17 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 18 | ('title', models.CharField(max_length=200)), 19 | ('pages', models.IntegerField(default=0)), 20 | ], 21 | ), 22 | ] 23 | -------------------------------------------------------------------------------- /python/webdev/books/reading/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CalebCurry/python/c34766df18e59b1c48f5fcef0ba75a97c2605fc3/python/webdev/books/reading/migrations/__init__.py -------------------------------------------------------------------------------- /python/webdev/books/reading/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | class Book(models.Model): 4 | title = models.CharField(max_length=200) 5 | pages = models.IntegerField(default=0) 6 | 7 | def __str__(self): 8 | return f"{self.title}, {self.pages} pages long" 9 | -------------------------------------------------------------------------------- /python/webdev/books/reading/templates/reading/index.html: -------------------------------------------------------------------------------- 1 | {% if books %} 2 |
No books are available.
10 | {% endif %} -------------------------------------------------------------------------------- /python/webdev/books/reading/templates/reading/info.html: -------------------------------------------------------------------------------- 1 | {{ book }} -------------------------------------------------------------------------------- /python/webdev/books/reading/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /python/webdev/books/reading/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from . import views 4 | 5 | app_name = 'reading' 6 | urlpatterns = [ 7 | path('', views.index, name='index'), 8 | path('