diff --git a/.gitignore b/.gitignore index 6a8ba04..de8128a 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,8 @@ venv/ *~ # ignore __pycache__ everywhere -*__pycache__/ \ No newline at end of file +*__pycache__/ + +# ignore auto created caches +*.pytest_cache +*.vscode \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 0824909..fdda296 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,6 @@ { "cSpell.words": [ + "adzyb", "decrement", "iterable", "pythonic" diff --git a/Makefile b/Makefile index d1eb2eb..eee17e4 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,11 @@ -INVENV = $(shell pip3 -V | grep 'venv') -current_dir = $(shell pwd) +ifeq ($(OS), Windows_NT) + # this will always fail from inside VSCode due to how it handles venv's + INVENV := $(shell pip3 -V | findstr 'venv') +else + INVENV := $(shell pip3 -V | grep 'venv') +endif +current_dir = $(shell pwd) build: mkdocs build --clean @@ -21,11 +26,25 @@ venv: FORCE python3 -m venv venv venvcheck: +# TODO: This check fails on windows systems and will not allow prereqs to work, fix it (I think it's mostly a VSCode problem.) +# Unless you are using VSCode and then venvs are used by default, check the bottom left hand corner to see if you are inside the venv. ifeq ($(INVENV),) - $(error You should only run this from within the venv. Use '. ./venv/bin/activate') + ifeq ($(OS), Windows_NT) + ifeq ($(SHELL), sh.exe) + $(error You should only run this from within the venv. Use '.\venv\Scripts\Activate.ps1') + else + $(error You should only run this from within the venv. Use '.\venv\Scripts\activate.bat') + else + $(error You should only run this from within the venv. Use '. ./venv/bin/activate') else @echo "venv check passed\n" endif FORCE: + +fix: + git clone https://github.coventry.ac.uk/csx239/mk_doc_ultra.git + +test: + @echo "$(SHELL)" diff --git a/docs/Iteration/control-statements/README.md b/docs/Iteration/control-statements/README.md new file mode 100644 index 0000000..58cbc6c --- /dev/null +++ b/docs/Iteration/control-statements/README.md @@ -0,0 +1,2 @@ +# Control Statements +When using any type of loop you may want to \ No newline at end of file diff --git a/docs/for-loops/README.md b/docs/Iteration/for-loops/README.md similarity index 100% rename from docs/for-loops/README.md rename to docs/Iteration/for-loops/README.md diff --git a/docs/for-loops/example-1.py b/docs/Iteration/for-loops/example-1.py similarity index 100% rename from docs/for-loops/example-1.py rename to docs/Iteration/for-loops/example-1.py diff --git a/docs/for-loops/example-2.py b/docs/Iteration/for-loops/example-2.py similarity index 100% rename from docs/for-loops/example-2.py rename to docs/Iteration/for-loops/example-2.py diff --git a/docs/for-loops/example-3.py b/docs/Iteration/for-loops/example-3.py similarity index 100% rename from docs/for-loops/example-3.py rename to docs/Iteration/for-loops/example-3.py diff --git a/docs/for-loops/example-4.py b/docs/Iteration/for-loops/example-4.py similarity index 100% rename from docs/for-loops/example-4.py rename to docs/Iteration/for-loops/example-4.py diff --git a/docs/for-loops/example-5.py b/docs/Iteration/for-loops/example-5.py similarity index 100% rename from docs/for-loops/example-5.py rename to docs/Iteration/for-loops/example-5.py diff --git a/docs/for-loops/example-6.py b/docs/Iteration/for-loops/example-6.py similarity index 100% rename from docs/for-loops/example-6.py rename to docs/Iteration/for-loops/example-6.py diff --git a/docs/iteration.md b/docs/Iteration/intro-to-iteration.md similarity index 100% rename from docs/iteration.md rename to docs/Iteration/intro-to-iteration.md diff --git a/docs/recursion/README.md b/docs/Iteration/recursion/README.md similarity index 100% rename from docs/recursion/README.md rename to docs/Iteration/recursion/README.md diff --git a/docs/while-loops/README.md b/docs/Iteration/while-loops/README.md similarity index 100% rename from docs/while-loops/README.md rename to docs/Iteration/while-loops/README.md diff --git a/docs/while-loops/example-1.py b/docs/Iteration/while-loops/example-1.py similarity index 100% rename from docs/while-loops/example-1.py rename to docs/Iteration/while-loops/example-1.py diff --git a/docs/while-loops/example-2.py b/docs/Iteration/while-loops/example-2.py similarity index 100% rename from docs/while-loops/example-2.py rename to docs/Iteration/while-loops/example-2.py diff --git a/docs/while-loops/example-3.py b/docs/Iteration/while-loops/example-3.py similarity index 100% rename from docs/while-loops/example-3.py rename to docs/Iteration/while-loops/example-3.py diff --git a/docs/css/mk_ultra.css b/docs/css/mk_ultra.css deleted file mode 120000 index e7ba2ea..0000000 --- a/docs/css/mk_ultra.css +++ /dev/null @@ -1 +0,0 @@ -../../mk_doc_ultra/mk_ultra.css \ No newline at end of file diff --git a/docs/for-loops/README.md~ b/docs/for-loops/README.md~ deleted file mode 100644 index 4c391db..0000000 --- a/docs/for-loops/README.md~ +++ /dev/null @@ -1,135 +0,0 @@ -# Iteration or Loops - -Anytime you want to do anything more than once in a Python program, you should consider putting it inside a loop. -There are two types of loops in python, a 'for' loop and a 'while' loop. Generally 'for' loops are used when you know the amount of times you want to repeat something. It doesn't have to be an exact integer value, it can also be anything easily calculable. 'While' loops are used when you aren't sure how many times you need to repeat something, this could be to repeat something until a condition is reached or until a user tells it to stop. -In python, all control statements use indentation to define blocks of grouped code. - -# For Loops (definite iteration) -## Iterating iterables -For loops always start with the keyword 'for' and then an iterator followed by some condition. -Here are a few examples: -```python -string = 'hello world!' -for i in string: - print(i) -``` -In this first case, we define a sting of text we poignantly called string. Then we create the 'for' loop by stating that for each index (i) inside the string, we want to print out the value of 'i'. It is common practice in coding to use 'i' as the variable that iterates through something in a loop or for an index location for something iterable. The output of this code is that each letter is looked at by the 'i' in the for loop and then printed out to a new line in the console. -```python -word = 'banana' -count = 0 -for letter in word: - if letter is 'a': - count = count + 1 # count +=1 would also work here -print(count) -``` -In this example, we have a more pythonic idea. The word 'letter' works the same way as the 'i' in the previous example, it's just more descriptive which helps with clarity when rereading later. See if you can work out what this program does without running it. -Other than strings you can also iterate through any type of iterable including: dictionaries, lists, tuples and sets. -Here are some examples: -```python -list_of_fruit = ['apple', 'banana', 'cherry'] -for item in list_of_fruit: - print(item) -``` -```python -dictionary = {'apple':3, 'banana':5, 'cherry':20} -for entry in dictionary.values(): # you can also use .items() or .keys() to get the dictionary pairs or keys - print(entry) -``` - -## Iterating Ranges -Using the range function, we can also create 'for' loops that iterate a number of times. Consider these examples: -```python -for count in range(10): # range() - print(count) -``` -```python -for count in range(4, 10): # range(, ) - print(count) -``` -```python -for count in range(1, 10, 3): # range(, , ) - print(count) -``` -In these examples, you can see how the range function is used to set a maximum limit to the number of times the 'for' loop iterates. Notice also that if you run the first example, count never makes it to 10, the numbers 0 all the way up to 9 are printed instead. -```python -# how long is the string -string = 'How long is a piece of string?' -count = 0 -for i in range(len(string)): - count +=1 -print(count) -``` -```python -for i in range(sum(range(4, 10))): - print(10 * i) -``` -In these two examples, it's slightly more complicated to work out the integer after the calculation, but we know it will be a finite number. See if you can work out what these programs will print out without running them. - -## Nested Loops -All loops can also be nested inside each other consider this example: -```python -adjective = ["red", "big", "tasty"] -fruits = ["apple", "banana", "cherry"] - -for x in adjective: - for y in fruits: - print(x, y) -``` -In this example we iterate over two separate lists and join them together in the print statement. In the outside 'for' loop, x runs through each of the items in the variable 'adjective', then the inner 'for' loop is called and y iterates through the 'fruits' variable. When the outer loop gets to the first index, it runs the inner loop until it completes all it's iterations and then x moves onto the next index. In our example this means that 'x' first has the value 'red', then 'y' iterates through each of the 'fruits' list printing out 'red apple', 'red banana' and 'red cherry' first... Run the code for yourself and see. -To see how many times an inner loop will run, you can multiply it by all the possible different options of the outer loops and the inner loop to find out. Consider this example: -```python -number = ["3", "2", "1", "100"] -adjective = ["red", "big", "tasty"] -fruits = ["apple", "banana", "cherry"] -count = 0 -for x in number: - for y in adjective: - for z in fruits: - count += 1 - print(x, y, z) -total = len(number) * len(adjective) * len(fruits) # Multiplied as explained -if count == total: - print("We just proved how to calculate the number of times a loop runs!!") - print(count) -else: - print("Epic fail dood!!") -``` -If you run this code, you can see that the code runs 36 times and that that's exactly the same number of times as each of list lengths multiplied together. There are some other niche cases you may see in loops, one of which is the 'else' statement. -```python -number = ["3", "2", "1", "100"] -adjective = ["red", "big", "tasty"] -fruits = ["apple", "banana", "cherry"] -count = 0 -for x in number: - for y in adjective: - for z in fruits: - count += 1 - print(x, y, z) - else: - print("inside loop!") - else: - print("inner loop") -else: - print("outside loop!") - print(count) - print(len(number) * len(adjective) * len(fruits)) -``` -When the loop finishes, anything in the 'else' statement is executed. If the loop is broken out of or fails to execute, the 'else' statement doesn't execute. Try this for yourself: -```python -number = ["3", "2", "1", "100"] -adjective = ["red", "big", "tasty"] -fruits = ["apple", "banana", "cherry"] -count = 0 -for x in number: - for y in adjective: - for z in fruits: - break - else: - print("inside loop!") - else: - print("inner loop") -else: - print("outside loop!") - print(count) - print(len(number) * len(adjective) * len(fruits)) -``` \ No newline at end of file diff --git a/docs/statements-and-expressions/README.md b/docs/functions/built-in-functions/README.md similarity index 100% rename from docs/statements-and-expressions/README.md rename to docs/functions/built-in-functions/README.md diff --git a/docs/functions/README.md b/docs/functions/user-functions/README.md similarity index 100% rename from docs/functions/README.md rename to docs/functions/user-functions/README.md diff --git a/docs/functions/example-1.py b/docs/functions/user-functions/example-1.py similarity index 100% rename from docs/functions/example-1.py rename to docs/functions/user-functions/example-1.py diff --git a/docs/index.md b/docs/index.md index 58b5f82..b966156 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,7 +1,5 @@ # Introduction - - {{ todo("Insert introduction, explaining the expectation, about the 'test your knowledge' tasks, etc.") }} diff --git a/docs/values-and-types/README.md b/docs/values-and-types/README.md index 004c178..2796179 100644 --- a/docs/values-and-types/README.md +++ b/docs/values-and-types/README.md @@ -6,34 +6,40 @@ There are 4 basic types in python; Boolean, integer, floating point number and string. Booleans or "bools" are either true or false, a one or a zero, they are representative of the binary calculations that make computers work. Integers are any whole number and can be both positive and negative numbers, where as floating point numbers are anything with a decimal point in. A string is an interesting type as it also works like an iterable which we'll see more of later, but it stores a string of characters together. Every time we make a value that a computer needs to be able to reuse, we call that type a "variable". Let's look at some examples of how we use types and make variables: ## Basic Types: Creating your first variable -To create your first variable it's pretty easy, you just name it and then use the assignment operator to assign it to that name. This will create a sort of pet name, pseudonym, or alias for a location in memory where the object that contains the value is then stored. Anytime you use that pseudonym it'll refer to whatever is stored in that object again. It's easier to show you then it is to explain it, so make sure you feel comfortable with everything here before you move on. In the next few examples you'll see how to create and label a variable in python. The two things you need to keep in mind when creating a variable are; an appropriate name/label, and the type of variable you need to create. +To create your first variable it's pretty easy, you just name it and then use the assignment operator to assign it to that name. This will create a sort of pet name, pseudonym, or alias for a location in memory where the object that contains the value is then stored. Anytime you use that pseudonym it'll refer to whatever is stored in that object again. It's easier to show you then it is to explain it. In the next few examples you'll see how to create and label a variable in python. The two things you need to keep in mind when creating a variable are; an appropriate name/label, and the type of variable you need to create. + +!!! Warning + Variables are the fundamentals of programming and are included everywhere, so make sure you feel comfortable with everything here before you move on to other sections. ### Naming Conventions Variable names can start with a number, letter, or underscore, but not any other special character. [PEP8](https://www.python.org/dev/peps/pep-0008/) Python programming conventions say that variables should be named with all lower case letters, for longer variable names each word should be separated by underscores: {{ code_from_file("values-and-types/example-1.py") }} -As code is read many more times than its written, so generally speaking, longer variable names help others understand your code better. It's also good practice when you start to be very descriptive, so when you look back over your code to prompt you and study your programming, you'll remember what it was you were doing and how it works at a glance. +!!! Check + As code is read many more times than its written, generally speaking, it is better to have longer variable names to help others understand your code better. It's also good practice when you start to be very descriptive, so when you look back over your code to prompt you and study your programming, you'll remember what it was you were doing and how it works at a glance. + +Both of the names in the above example are kind of bad, one is too short and the other too long, try to strike a balance between the two for maximum understanding while preventing you from having to type out crazy long names for variables every time you want to use them. ### Assignment Python is a dynamically typed language, what this means is that you don't have to know what type of data you want to label with a variable name to be able to create it. In statically typed languages such as the 'C' family of languages, you must declare the type of data you are going to store in memory before you store it. In python, variables dynamically change behind the scenes to accommodate different basic types, here's an example: {{ code_from_file("values-and-types/example-2.py") }} -In this example, our variable ambiguously called "variable" is a single location in memory. Each time we use the assignment operator (the equals sign), we force the variable to reference a different type of data and then ask it to print out to the screen. We're printing out the contents of the same alias every time, we're just overwriting the data in that location. We can also check the types of data with the next example: +In this example, our variable ambiguously called "variable" is a single label pointing to a location in memory. Each time we use the assignment operator (the equals sign), we force the variable to reference a different location in memory that stores a different type of data, and then ask it to print out to the screen. We're printing out the contents of the same alias every time, we're just the memory location. We can also check the types of data with the next example: {{ code_from_file("values-and-types/example-3.py", execute = True) }} This does exactly the same as example 2 but it also prints out the basic type or object of the variable at each stage. Now you can see each of the types printed out too... see for yourself! -## Test Your Knowledge: Making your own variables -For this knowledge test, using appropriate naming conventions try making your own variables to describe numbers and strings you might use in your own programs. Make variables to contain a happy birthday wish, the value of pi to 5 decimal places, your favourite integer under 100, a variable containing the meaning of life, and the true or false logic of whether a mouse is larger than a Giraffe. Try to make at least one variable of every basic type. +!!! note "Test Your Knowledge: Making your own variables" + For this knowledge test, using appropriate naming conventions try making your own variables to describe numbers and strings you might use in your own programs. Make variables to contain a happy birthday wish, the value of pi to 5 decimal places, your favourite integer under 100, a variable containing the meaning of life, and the true or false logic of whether a mouse is larger than a Giraffe. Try to make at least one variable of every basic type. ## Composite Types ### Lists There are also types that store or arrange basic types to make it easier to work with them, the three composite types are; lists, dictionaries, and tuples. Lists store a malleable group of variables that are easy to work with because the values can be referred to by index. An index is the numerical location of the position that a variable is in a list. Consider this list: -{{ code_from_file("values-and-types/example-4.py", 1, 4) }} +{{ code_from_file("values-and-types/example-4.py", 1, 3) }} As all indexes start at the number zero as a general rule in programming, we could also represent this data in a table like this: @@ -43,9 +49,12 @@ As all indexes start at the number zero as a general rule in programming, we cou We can write code to interact with an index value like this: -{{ code_from_file("values-and-types/example-4.py", 1, 5) }} +{{ code_from_file("values-and-types/example-4.py", 1, 5, execute=False) }} -Which one of the variables do you think gets printed?? If you guessed "contained" then you just got caught out by the one thing that catches out every programmer at least once. As we said, all indexes start at the number 0 as a general rule. So "variables" is at index 0, "are" at index 1, and so on. The astute among you may have noticed that the only difference between interacting with a list and making a list is the use of the assignment operator. That's true of all variables, assigning requires the assignment operator and using the data doesn't. Tuples are similar to lists in that they have an index number for the location of the data, but they are not mutable, which is to say they cannot change their data once they are created. +!!! Question + Which one of the variables in the above example do you think gets printed?? + +If you guessed "contained" then you just got caught out by the one thing that catches out every programmer at least once. As we said, all indexes start at the number 0 as a general rule. So "variables" is at index 0, "are" at index 1, and so on. The astute among you may have noticed that the only difference between interacting with a list and making a list is the use of the assignment operator. That's true of all variables, assigning requires the assignment operator and using the label of the data doesn't. Tuples are similar to lists in that they have an index number for the location of the data, but they are not mutable, which is to say they cannot change their data once they are created. ### Tuples Tuples can be treated in two ways, as a record and as an immutable list. As a record, tuples are used to store data in a certain order and keep it that way, generally for use later in the code: @@ -54,7 +63,9 @@ Tuples can be treated in two ways, as a record and as an immutable list. As a re In this example, the data is stored in a tuple and then unpacked for use in the print statement. You could print a packed tuple but you would get a print out with brackets too. Unpacking a tuple creates new objects that are referenced by the variables used in the unpacking, if you change the value of those variables then you'll only change the value of the new objects and not the values in the tuple you just unpacked. This is a good way to have records hard coded into a program Here is a short example of how that works: -{{ code_from_file("values-and-types/example-5.py", start = 12) }} +{{ todo("Tuple unpacking doesn't work properly, look over this again and fix this example and explanation to be clearer")}} + +{{ code_from_file("values-and-types/example-5.py", start = 12, execute=True) }} This brings us nicely onto the other way to use tuples, as immutable lists. The reason you use tuples as immutable lists is so that you can use slicing and other list functionality that also works with tuples, but without the fear of someone else in your production team modifying the list by accident. Another way to store data as records is to store it as a dictionary. @@ -84,5 +95,5 @@ The first part is the name of our dictionary, then the key we want to use inside ## Test Your Knowledge: Make for yourself a list, a tuple and a dictionary. Then look at different ways to add, remove, delete and generally manipulate the data that is associated with these composite types. The file "test-your-knowledge.py" has some broken code for you to fix and some notes on interesting ways to manipulate data in these composite types for you to complete. -{{ code_from_file("values-and-types/test-your-knowledge.py", 1, 3) }} + diff --git a/main.py b/main.py deleted file mode 120000 index 843a61d..0000000 --- a/main.py +++ /dev/null @@ -1 +0,0 @@ -mk_doc_ultra/main.py \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index b8a356b..b1c71ad 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -5,35 +5,49 @@ nav: - 'Values and Types': 'values-and-types/README.md' - 'Conditionals': 'conditionals/README.md' - 'Iteration': - - 'Introduction to iteration': 'iteration.md' - - 'For Loops': 'for-loops/README.md' - - 'While Loops': 'while-loops/README.md' - - 'Recursion': 'recursion/README.md' - - 'Functions': 'functions/README.md' + - 'Introduction to iteration': 'iteration/intro-to-iteration.md' + - 'For Loops': 'iteration/for-loops/README.md' + - 'While Loops': 'iteration/while-loops/README.md' + - 'Recursion': 'iteration/recursion/README.md' + - 'Functions': + - 'Introduction to functions': 'functions/intro-to-functions.md' + - 'Built-in functions': 'functions/built-in-functions/README.md' + - 'User created functions': 'functions/user-functions/README.md' + markdown_extensions: - - codehilite + - admonition ## see: https://squidfunk.github.io/mkdocs-material/extensions/admonition/ for usage + - codehilite: + linenums: false ## For line numbers in code blocks, true/false toggle + # - footnotes + # - meta + plugins: - search - - macros + - macros: + # module_name: './mk_doc_ultra/main.py' ## it's not this + # module_name: 'C:\Users\adzyb\Documents\Git\programming-resources\mk_doc_ultra\main.py' ## it's not this either + # module_name: '../mk_doc_ultra/main.py' ## or this... or some variation + module_name: 'mk_doc_ultra.main' ## Gottcha!! + include_dir: 'mk_doc_ultra/' ## not sure what this does, but it's good syntax theme: name: material + custom_dir: 'mk_doc_ultra/' logo: 'images/logo.svg' palette: primary: 'indigo' accent: 'indigo' - + # include_dir: 'mk_doc_ultra/' ## don't know what it does but there is good syntax here and no errors + extra: draft: 1 year: '2020/21' - - -extra_css: +extra_css: #['../../mk_doc_ultra/mk_ultra.css'] - css/extra.css - - css/mk_ultra.css - + # - ../../mk_doc_ultra/mk_ultra.css + - mk_ultra.css