diff --git a/pretext/AdditionalTopics/BigO.ptx b/pretext/AdditionalTopics/BigO.ptx new file mode 100644 index 000000000..314e274f6 --- /dev/null +++ b/pretext/AdditionalTopics/BigO.ptx @@ -0,0 +1,202 @@ + +
+ Big O Analysis + +

A common question that comes up when programming is: "How long will my program take to run?". Even if a program provides the correct output, if it takes + too long to finish then it is unacceptable. There is a problem here though, it's impossible to reliably say exactly how long a program will take to run. + It depends on too many things. The capabilities of the computer running the code, what else is running on the computer, and the size of the input are just + some of the things that would need to be considered. +

+ +

To simplify this issue, we'll give up trying to estimate exactly how long a program will run, and instead look at the biggest factor that affect + existing code: the size of the input. If we wrote a program that ran for 60 seconds on 100 megabytes of input data, how should we expect the program to + react to 200 megabytes of input data? Maybe it would run in 120 seconds (twice the data for twice the run time)? Maybe it would still run in 60 seconds, + assuming that extra data isn't used. Or maybe the program would run for far longer. The issue is that we don't know what the relationship is between the size + of the input data and the behavior of the program.

+ +

This is where Big O Analysis comes in. Big O is a notation computer scientists use to describe the relationship between the size + of the input data and the behavior of the program. These terms are written like a mathematical function using the variable n. n as a variable represents the + size of the input data provided to the program. The Big O function tells us how n affects the time the program will take to complete.

+ +

Consider the example we had before. We have a program that takes 60 seconds to run on 100 megabytes of input data, we'd like to know (roughly) + how long the program might take to run on 200 megabytes of input data. If we know the run time of the program is the function f(n) = n^2, with n being + the size of the data, now we have enough information to make a guess. If n is doubled, then the time the program runs for will quadruple! (2*n)^2 = 4 * n^2.

+ +

The formal mathematical notation for Big O is denoted with a capital O (a big o!) followed by parentheses. + Inside of the O() is most commonly some term of n. In our previous example, we would say the program has O(n^2) behavior.

+ +

Different functions of n have different magnitudes, which helps us to quantify how quick or slow an algorithm is relative to the input size n. + From left to right, left being the quickest time and right being the slowest time, we typically see these complexities:

+ +

O(1), O(logn), O(n), O(nlogn), O(n^2), O(n^3), O(2^n), O(n!).

+ +

Big O is like a limit in that only the most significant terms matter as n gets bigger and bigger. We typically expect n to be very, VERY large because + small inputs aren't as strongly affected by time limits. If a program takes 0.001 seconds to run with most normal data, is it really a big deal if it takes 0.004 + seconds on occasion? What if we were dealing with a program that had to run for a month though? Now that factor of four starts to hurt a lot more.

+ +

There is another important aspect that we have ignored up to this point: programs can often have wildly different behavior depending on their input. + Consider a contrived example:

+ + +var = input() +if 'a' in var: + while True: + print("run forever!") +else: + print("done") + + + +

In this program, the size of the input doesn't matter as much as whether the input string contains a letter "a" or not. If it does, the program runs forever. + If it doesn't, the program ends almost immediately. How do we reconcile this with our Big O notation? The answer is to be a pessimist. We adopt the assumption that + everything that can happen to slow down our program will happen. In the code above, we assume that the input ALWAYS will contain an "a". This assumption is broadly + known as the "worst case". Big O notation uses this assumption in every instance you will see it (at least in this class).

+ +

Let's look at some more examples:

+ + +sum = 1 + 1 +print(sum) + + +

This code has a Big O of O(1), also referred to as constant time. This is because the program does nothing with its input. In fact, it doesn't + even take input! Constant time operations are typically things in code which do not loop. A constant time program suggests it will always finish in a + consistent amount of time, no matter what happens.

+ +

Now, let's check out an example with a loop:

+ + +def example_func(n): + for i in range(n): + print(i) + + +

As you can see, this function simply prints 0 to n. Each print takes a little time, so a larger n means a longer program run time. + We denote the complexity of example_func as O(n), + because whether n = 100 or n = 10000000, as the complexity trends to infinity, it remains O(n).

+ +

In the last code example, O(n) was the complexity for all cases, because the loop always goes to n.

+ + Big O Complexity Graph + +

This figure shows complexities as a graph and which ones are considered "desirable" or at least "acceptable". Context mostly determines if these are "good" terms or not, + but do strive to never write something worse than O(n^3)!

+ +

It may be difficult to appreciate the implications of these terms when first seeing them. Let's say we have an algorithm with the following complexities, but they + all run with the same time (1 milliseconds) for n = 10. This table shows what will happen if we increase the size of the input:

+ + + + + + n + + + O(log(n)) + + + O(n) + + + O(n^3) + + + O(2^n) + + + + + 10 + + + 1 ms + + + 1 ms + + + 1 ms + + + 1 ms + + + + + 11 + + + 1 ms + + + 1.1 ms + + + ~1.3 ms + + + 2 ms + + + + + 20 + + + 1.3 ms + + + 2 ms + + + 8 ms + + + 1 s + + + + + 100 + + + 2 ms + + + 10 ms + + + 1 s + + + 10^16 years + + + + + 100000 + + + 5 ms + + + 10 s + + + 31 years + + + :) + + + +
+ +

As you can see, what started off as a negligible difference exploded into a totally unacceptable time for larger input sizes applied to larger Big O terms. Examples like these are precisely why + computer scientists are so fixated on Big O. 100000 data points is not a lot of data. Large tech companies are often running code on billions or + trillions of data points, and anything less the most efficient code won't be able to run at-scale.

+ +

We will end this section with a disclaimer. We have only covered the bare basic concepts of Big O here today. If you continue to study computer science, + you'll have more opportunities to explore it in much more detail, including seeing the formal definition of Big O as well as learning how to determine the Big O of your own code. + For this specific class, we only ask you to be familiar with the notation of Big O and have a basic intuition behind what it communicates.

+
diff --git a/pretext/AdditionalTopics/BinaryRepresentations.ptx b/pretext/AdditionalTopics/BinaryRepresentations.ptx new file mode 100644 index 000000000..c17467216 --- /dev/null +++ b/pretext/AdditionalTopics/BinaryRepresentations.ptx @@ -0,0 +1,53 @@ + +
+ Binary Representations + +

Have you ever seen all of the "hacker" 01010110101010s in the movies? As you might + know, this is called binary. While it's not actually how hacking works, binary is still the base of all computing. + Every word that you are reading right now was transmitted to your computer as a series of 1's and 0's. Although you won't + be typing 0's and 1's at a keyboard all day, binary is still useful to know.

+ +

Quick background: binary is a numbering system, just like decimal (the numbering system we normally use). + Decimal uses the digits 0-9, but binary only uses the digits 0 and 1, which are called bits. + In other words, binary is just a different way of counting.

+ +

Believe it or not, this is indirectly how you've been counting your entire life. For instance, in decimal numbering (base 10):

+ +

1023 (base 10) = (1 * 10^3) + (0 * 10^2) + (2 * 10^1) + (3 * 10^0)

+ +

There are even more numbering systems, like hexadecimal and octal, but you only need to understand binary for this course.

+ +

Binary deals with powers of two (hence the name), reading from right to left and starting at 0. + If the bit is 0, it is "off" and the position is multiplied by 0; if the bit is 1, it is "on" and its + position in the number is the exponent with 2 as the base. Binary numbering is also called base 2 + because of that. For instance:

+ +

1000 (base 2) = (1 * 2^3) + (0 * 2^2) + (0 * 2^1) + (0 * 2^0) = 8

+ +

Converting decimal to binary: A quick way to convert decimal to binary is to find the largest + factor of 2 that will go into the number, and concatenate 1 if it goes into the number; concatenate 0 if not. Subtract + the number from the running total and repeat until we hit 0. For instance:

+ +

Example: Convert 78 to binary

+

1. If we think about all of our powers of 2, 2^7 = 128 is too large (128 > 78), so we know 2^6 is where we'll start our number, and we need a 1 in that position. We now have: 1xxxxxx.

+

2. 78 - 64 = 14, which is our remainder from the last digit. 2^5 = 32 > 14, so we know 2^5 is a 0. We now have: 10xxxxx.

+

3. 78 - 64 = 14, which is our remainder from the last digit. 2^4 = 16 > 14, so we know 2^4 is a 0. We now have: 100xxxx.

+

4. 78 - 64 = 14, which is our remainder from the last digit. 2^3 = 8 < 14, so we know 2^3 is a 1 because it fits in! We now have: 1001xxx.

+

5. 78 - 64 - 8 = 6, which is our remainder from the last digit. 2^2 = 4 < 6, so we know 2^2 is a 1 because it fits in! We now have: 10011xx.

+

6. 78 - 64 - 8 - 4 = 2, which is our remainder from the last digit. 2^1 = 2 < 4, so we know 2^1 is a 1 because it fits in! We now have: 100111x.

+

7. 78 - 64 - 8 - 4 - 2 = 0, so we are done and can fill any remainders with a 0 bit.

+

Our final answer is: 1001110 (base 2)

+ + + Typically when we write binary, we'll see our bits in groups of 4, because our binary sequences are normally + some multiple of 4, like 8, 16, or 32. Because of this, we would add a leading zero and + write our previous answer as: 0100 1110 (base 2). + + +

Converting binary to decimal: As mentioned above, you can simply look at each bit, + and add 2 to the power of its position if the bit is 1.

+ +

Like usual in math, there are a few different ways to arrive at one conclusion. These are not + the only ways to do conversions. If these explanations don't make sense to you, ask your instructor + or Google for their explanation.

+
diff --git a/pretext/AdditionalTopics/DataScience.ptx b/pretext/AdditionalTopics/DataScience.ptx new file mode 100644 index 000000000..99569ff9f --- /dev/null +++ b/pretext/AdditionalTopics/DataScience.ptx @@ -0,0 +1,53 @@ + +
+ Data Science + +

Data science is a multidisciplinary field which combines computer science, + math, and other domains to answer questions using data.

+ +

As the world moves more and more towards storing and analyzing large amounts of data, + data science is a vital skill for you to be familiar with, whether you're a computer science major or not. It is also + a very common and useful application of programming, which is why we're discussing it in this class.

+ +

Data science is perhaps best defined by describing what data science looks like. The data science process consists of four steps:

+ +
    +
  1. Obtaining data
  2. +
  3. Cleaning the data
  4. +
  5. Exploring the data
  6. +
  7. Predicting unknowns
  8. +
+ +

Obtaining the data: We live in a time where data is more abundant then ever before. Getting a hold of data can involve gathering it yourself, + purchasing it, or taking advantage of the many, many sites online now which have a plethora of data + available for free (and sometimes paid) use. if you are getting your data from some 3rd party, it will likely come in a .csv, .json, or SQL database format.

+ +

Cleaning the data: This can vary, but ultimately you need to prepare your data + in a way that makes it easily usable in the next steps. Often data starts out "noisy" or contains errors. In this step you may + fix things in the data, change missing data, or correct wrong data.

+ +

Cleaning is regularly considered the longest step in this process! Data can come in all sorts of different + formats now, with anomalies, with blanks, and so much more. It often depends on context and you own goals + what "fixing" data even means.

+ +

Exploring the data: Now that the data is prepared, we can do some analysis on it! As the term suggests, exploring the data is about coming to better + understand it. You often don't know what is interesting or useful about data when you first encounter it. You may need to do some sort of statistical + analysis to uncover the interesting aspects, or you may want to graph values and look for relationships and trends visually.

+ +

Predicting unknowns: Having come to understand the data better, you can now use it to create new knowledge. These days, this step typically involves + using machine learning models. These techniques can generally be split into three groups:

+ +
    +
  1. Supervised Learning: With supervised learning, we try to construct a model that describes the relationship between inputs and outputs (regularly + referred to as "labels"). Knowing what labels we want in advance is what makes a method "supervised". For example, we could create a model to guess when an email + is spam or not based on its contents; the label here is "spam" or "not spam". Or we could try to guess what the stock price will be for our favorite company based + on how it has performed in the last few weeks. The label here would be the predicted stock price.
  2. +
  3. Unsupervised Learning: Contrasting with supervised learning, with unsupervised learning we don't know the labels in advance. An example here could be + using social media data to automatically identify friend groups. We don't know in advance how many groups we'll find or what their nature will be. Because of this, it + can be harder to guess what kind of results unsupervised learning will produce.
  4. +
  5. Semi-Supervised Learning: Semi-supervised learning is an attempt to capture the best aspects of both supervised and unsupervised learning. With these + approaches we start with some data that has labels and also some data that doesn't. To use a previous example, we could take a collection of emails, only some of + which have been labeled as spam or not, and still try to construct a reliable method for identifying new emails as spam. If it goes well, then we've saved ourselves + a lot of time that would have otherwise been spent labeling emails.
  6. +
+
diff --git a/pretext/AdditionalTopics/Glossary.ptx b/pretext/AdditionalTopics/Glossary.ptx index e6a39e402..a0e7daa8a 100644 --- a/pretext/AdditionalTopics/Glossary.ptx +++ b/pretext/AdditionalTopics/Glossary.ptx @@ -2,11 +2,24 @@
Glossary + + Binary search +

A searching algorithm where you look through a sorted list in halves; an improvement upon linear search.

+
+ + Big O Notation +

A notation computer scientists use to describe the relationship between the size + of the input data and the behavior of the program, denoted with O() and some factor inside of the parenthesis.

+
+ + constant time +

A Big O time complexity of O(1).

+
comprehension

A specific Python construction that allows collection types to be created and filled with a single line of code.

- + dictionary

A collection of key-value pairs that maps from keys to values. The keys can be any immutable type, and the values can be any type.

@@ -21,6 +34,10 @@

One of the pairs of items in a dictionary. Values are looked up in a dictionary by key.

+ + Linear search +

A searching algorithm where you look through in a linear order (directly from start to end).

+
mapping type

A mapping type is a data type comprised of a collection of keys and diff --git a/pretext/AdditionalTopics/More-BigO.ptx b/pretext/AdditionalTopics/More-BigO.ptx new file mode 100644 index 000000000..e8b108fb7 --- /dev/null +++ b/pretext/AdditionalTopics/More-BigO.ptx @@ -0,0 +1,161 @@ + +

+ Big O Simplification and Practice + +

One more important topic in Big O Analysis is simplification. We won't get too deep into the math, but here are a few general rules:

+ +

Constant time operations always simplify to O(1). For instance, O(3) and O(1000000) both simplify to O(1).

+ +

Added constants are ignored when a larger factor is around. For instance, O(n + 1) is just O(n).

+ +

Multiplication by a constant factor simplifies to the factor, such as O(3n) becoming O(n).

+ +

Added polynomials are ignored when a larger factor is around. For instance, O(n! + n) is just O(n!), or O(n^2 + n) is just O(n^2).

+ +

With nested loops, any inner loop factors are multiplied by the outer loop factor.

+ + + +

Example 1: Find the time complexity of this program. Be careful of the nested loop.

+ + + def example_func(n): + for i in range(n): + for j in range(n): + print(i * j) + + +
+ + + +

O(1)

+
+ + Incorrect; we have two nested loops here. + +
+ + +

O(logn)

+
+ + Not quite. You typically see O(logn) more often in search/sort algorithms. + +
+ + +

O(n)

+
+ + Incorrect; both loops (one of which is nested) depend on n. + +
+ + +

O(n^2)

+
+ + Correct! Both loops depend on n, and one loop is nested, which multiplies it by the parent factor. + +
+
+
+ + + +

Example 2: Find the time complexity of this program.

+ + +def example_func(n): + for i in range(n): + for j in range(10000): + print(j) + + +
+ + + +

O(1)

+
+ + Not quite; we one loop going to n and one loop going to a constant time. + +
+ + +

O(logn)

+
+ + Not quite. You typically see O(logn) more often in search/sort algorithms. + +
+ + +

O(n)

+
+ + Correct! O(10000n) simplifies to O(n). + +
+ + +

O(n^2)

+
+ + Incorrect. We only have one loop going to n, the inner loop is going to a constant. + +
+
+
+ + + +

Example 3: Find the time complexity of this program. Apply the same rules that you do for a for loop.

+ + +n = input() +i = 0 +while i < n: + print(i) + i += 1 + + +
+ + + +

O(1)

+
+ + Not quite, since n is an arbitrary user inputted value. + +
+ + +

O(logn)

+
+ + Not quite. You typically see O(logn) more often in search/sort algorithms. + +
+ + +

O(n)

+
+ + Correct! We're going to n in this loop. + +
+ + +

O(n^2)

+
+ + Incorrect. We only have one loop going to n. + +
+
+
+
diff --git a/pretext/AdditionalTopics/SearchSortAlgorithms.ptx b/pretext/AdditionalTopics/SearchSortAlgorithms.ptx new file mode 100644 index 000000000..5f8dbfb4d --- /dev/null +++ b/pretext/AdditionalTopics/SearchSortAlgorithms.ptx @@ -0,0 +1,50 @@ + +
+ Search and Sort Algorithms + +

A major part of computer science is studying algorithms. There are two types of algorithms + that are spoken about very often: search and sort. Not only are they great + for learning about Big O and algorithms, but they're very applicable in the real world.

+ +

As the internet grows and the data we store grows, companies have to wrestle with the large amounts of data + they have. Imagine if you're Google and you're looking for one user out of one billion. + Now imagine you need to do that a thousand times a minute, with people doing it at the same time. + The code you write and the algorithms you use become massively important to how quickly + these operations can be done.

+ +

Linear search is the most basic searching algorithm, and the most intuitive. + Quite simply, you look through whatever you're considering in a linear order; from first to last. + This could be a stack of papers, or it could be a list in Python.

+ + + +# a program which finds 10 in my list, linearly +my_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +for element in my_list: + if element == 10: + print('found 10!') + break + + + +

Linear search has a best case complexity of O(1), average case of O(n), and worst case of O(n). + Remember from the Big O section: in the best case, the element we're looking for is the first element. But in the + average and worst cases, we will have to look through some n elements.

+ +

Binary search is an improvement upon linear search. Binary search splits the searched list in half, + and if the number we're searching for is less than that number, we know it must be in the left half of the list; + if it's greater, we know it must be in the right half of the list, and we can repeat this process on smaller portions of the list until we find the number.

+ +

Binary search has a best case complexity of O(1), average case of O(logn), and worst case of O(logn).

+ +

However, there's a catch: for binary search to work, the list must be sorted! This is where sorting algorithms can come in. Sorting will not be covered in + this class, but we will describe one sorting algorithm for those that are curious.

+ +

Selection sort is a simple sorting algorithm. The idea is that we take the smallest element and swap it with the leftmost element, + and then the leftmost element becomes the sorted list. We repeat this process, and the sorted portion of the list grows in size each time, so we're only + adding elements from the nonsorted portion of the list to the end of the sorted part of the list.

+ +

The time complexity of selection sort is O(n^2) in every case.

+ +

Some other common sorting algorithms include Bubble Sort and Insertion Sort, but we will leave those for another class.

+
diff --git a/pretext/AdditionalTopics/toctree.ptx b/pretext/AdditionalTopics/toctree.ptx index 512f7bfd5..665f794d3 100644 --- a/pretext/AdditionalTopics/toctree.ptx +++ b/pretext/AdditionalTopics/toctree.ptx @@ -1,11 +1,16 @@ 4Additional Topics -4 +4 +4 +4 +4 +4 4 4 4 4 +4 4 4 4 diff --git a/pretext/Figures/ExtraTopics/Figures/complexity.png b/pretext/Figures/ExtraTopics/Figures/complexity.png new file mode 100644 index 000000000..5914ca96d Binary files /dev/null and b/pretext/Figures/ExtraTopics/Figures/complexity.png differ diff --git a/pretext/Lists/None.ptx b/pretext/Lists/None.ptx new file mode 100644 index 000000000..6a331270e --- /dev/null +++ b/pretext/Lists/None.ptx @@ -0,0 +1,86 @@ + +
+ None + +

None, or the NoneType, is a type which represents the absence of a value. + But let's take a step back and think: why is this useful?

+ +

In Python, sometimes we don't want to return anything from a function. However, when we don't + explicitly return anything from a function, Python will implicitly return None. + You could also explicitly return None from a function or return a value, + and then you would have to check if the function returned something or not.

+ +

For the purposes of this class, you should just understand when None appears and why.

+ +

Most commonly when students are learning about strings and lists, us educators see a similar issue, which links back + to sections on mutability. Strings are immutable and lists are mutable, remember?

+ +

When we want to modify a string, we must reassign it, because it's immutable:

+ + +my_string = 'Hello, world!' +new_string = my_string[0:5] +print(new_string) + + + +

Your natural instinct may be to write the same thing with lists:

+ + +my_list = [] +my_list = my_list.append(0) +print(my_list[0]) + + + +

By doing so, you will incur this error:

+ + +print(my_list[0]) +~~~~~~~^^^ +TypeError: 'NoneType' object is not subscriptable + + + +

Frustratingly, your code actually did exactly what you told it to. List functions modify the list directly, because + lists are mutable. Therefore, their functions (such as .append(element)) don't return anything.

+ +

But now we know why: append is actually implicitly returning None. This means that in the previous example, we reassigned my_list + to None, and then we tried to list access element 0 of None, which caused the 'not subscriptable' error, because None isn't a list + and can't have list access done to it.

+ +

The solution is simple: don't reassign the list when calling list functions.

+ + +my_list = [] +my_list.append(0) +print(my_list[0]) + + + +

If you remember nothing else, remember: strings get reassigned, lists don't. This is because + strings are immutable; lists are mutable and their functions don't return anything (they implicitly return None!).

+ + You may be wondering how to tell the difference between functions that return something or not. Sometimes + the name of the method can be a hint (e.g. if it has "set" in the name, it probably won't return, whereas "get" will). + If that doesn't help or you're still curious, you should reference the documentation (whether it's official Python + documentation or for a library). No shame in looking it up! + +

You won't be tested on the information below, but read on for some interesting thoughts on this.

+ +

If you've been around any other programming languages, you may have heard of equivalent ideas like + null, NULL, nullptr, nil, and more. This is such a universal concept + in programming and is hugely frustrating to many programmers as it often represents something that went wrong.

+ +

Fun (or depressing) fact -- the inventor of null actually regrets his invention:

+ +
+ I call it my billion-dollar mistake... At that time, I was designing the first comprehensive type system for references in an object-oriented language. My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years. +
+ +
+ - Tony Hoare +
+ +

Despite this, None, null, and nil don't seem to be going anywhere anytime soon. :)

+
diff --git a/pretext/Lists/toctree.ptx b/pretext/Lists/toctree.ptx index 96b9c0a70..ef9892fee 100644 --- a/pretext/Lists/toctree.ptx +++ b/pretext/Lists/toctree.ptx @@ -14,6 +14,7 @@ 4 4 4 +4 4 4
diff --git a/pretext/PythonModules/Packages.ptx b/pretext/PythonModules/Packages.ptx new file mode 100644 index 000000000..804312967 --- /dev/null +++ b/pretext/PythonModules/Packages.ptx @@ -0,0 +1,44 @@ + +
+ Packages and Dependencies + + You won't ever need to deal with dependencies in this course unless you are adding modules to your final project. Nonetheless, using packages + (a package is just a collection of Python modules) is a common practice in Python programming that you should at least be aware of. + +

One key tenant of computer science (or anything, for that matter) is that we don't want to reinvent + the wheel if we don't have to. A lot of very smart people have made very useful code, so why not use it?

+ +

The is a website that maintains packages, or code that other people + have written for our use. You might also hear the term dependencies, which describes essentially the same thing: code + that our code depends on.

+ +

PyPI can be accessed with pip, which is the command that you will use when installing dependencies. Pip should come + preinstalled with most Python installations on Mac and Windows.

+ +

Some common packages include: pytest (for testing your code), python-dateutil (for working with dates), flask (for making websites), and more.

+ +

Some common packages for data science include numpy, matplotlib, scipy, pandas and more.

+ +

But this is all sounding like a lot to keep track of, right? How can we ensure consistency between + versions installed on different people's computers?

+ +

requirements.txt is a file we can specify for others to be able install the dependencies + (which is needed to run our code), since others may not have our dependencies installed.

+ +

The following code represents a requirements.txt file that specifies numpy as a dependency:

+ + +numpy==1.26.2 + + + +

Note that dependencies are not installed immediately. For someone to install the requirements which you specify, + they would run the command: pip install -r requirements.txt.

+ +

If you're unsure what version of a dependency you have installed, you can run the command: pip show DEPENDENCY, like pip show numpy. + Somewhat ironically, there are also packages that can autogenerate a requirements.txt file for you.

+ + One additional tip worth mentioning is to always specify the bare minimum requirements your code needs to work. + Dependencies normally have dependencies of their own, so we want to minimize the install time and space taken up + when someone is installing your program's requirements. +
diff --git a/pretext/PythonModules/toctree.ptx b/pretext/PythonModules/toctree.ptx index 77275913f..896c0c70a 100644 --- a/pretext/PythonModules/toctree.ptx +++ b/pretext/PythonModules/toctree.ptx @@ -5,6 +5,7 @@ 4 4 4 +4 4 4 diff --git a/pretext/Selection/Glossary.ptx b/pretext/Selection/Glossary.ptx index 45f9621a2..1c0683c58 100644 --- a/pretext/Selection/Glossary.ptx +++ b/pretext/Selection/Glossary.ptx @@ -69,5 +69,10 @@

One program structure within another, such as a conditional statement inside a branch of another conditional statement.

+ + Pseudocode +

A mix of English and code (in our case, Python) that + programmers use to plan out their programs.

+
diff --git a/pretext/Selection/Pseudocode.ptx b/pretext/Selection/Pseudocode.ptx new file mode 100644 index 000000000..c5ea43ae0 --- /dev/null +++ b/pretext/Selection/Pseudocode.ptx @@ -0,0 +1,102 @@ + +
+ Pseudocode + +

With the introduction of conditionals and branching, our programs are about to become more complex on average. This is a good time to introduce a technique + that will help you plan and structure your programs before you start writing the more complex code. That technique is to use pseudocode.

+ +

Pseudocode is a mix of English and code (in our case, Python) that + programmers use to plan out their programs.

+ +

Writing pseudocode can be helpful for reasons such as:

+ + +

There isn't necessarily a right or wrong syntax for pseudocode (except wrong would be if you just wrote the program!). + Your pseudocode and language will probably look different from this, but should be along the same lines.

+ +

Take the following prompt for a problem:

+ +
+ Write a program that takes in a fraction in the format NUMERATOR/DENOMINATOR + from the user and outputs the quotient and the remainder. + If the denominator is 0, print out an error message; if the denominator is anything else, + let the user run the program normally. +
+ +

We can approach this problem first by writing the following pseudocode:

+ + +take user input for fraction +split the user input by "/" +make a variable for numerator, type convert to int +make a variable for denominator, type convert to int +if the denominator is 0, + print an error message +otherwise + make a variable for the numerator divided by denominator + make a variable for the numerator mod denominator + print out both variables + + + +

As you can see, this is basically just a high level outline of your program. It may help you + better see the control flow of your program, or even remind you to do the small things, like + converting your string input to an integer if necessary.

+ +

This pseudocode can then be more readily converted to Python:

+ + + +fraction = input().split('/') +numerator = int(fraction[0]) +denominator = int(fraction[1]) +if denominator == 0: + print("Error, your denominator is 0!") +else: + result = numerator / denominator + remainder = numerator % denominator + print("Division:", result) + print("Remainder:", remainder) + + + +

..and we're done! That's the pseudocode process.

+ +

This won't be something you see often, but let's reverse engineer and see what + existing Python code might look like in pseudocode.

+ + + +character = input() +if character == "Yoda": + print("No! Try not. Do. Or do not. There is no try.") +elif character == "Han Solo": + print("Never tell me the odds!") +elif character == "Obi Wan Kenobi": + print("Use the Force, Luke.") +else: + print("Character not found!") + + + +

We could write the following pseudocode for this program:

+ + +take user input for a Star Wars character +if the character is Yoda, print "No! Try not. Do. Or do not. There is no try." +if the character is Han Solo, print "Never tell me the odds!" +if the character is Obi Wan Kenobi, print "Use the Force, Luke." +in all other cases, print that the character wasn't found + + + +

As you may start to notice, Python is so close to the English language that pseudocode can often + be quickly translated into code.

+ +

Feel free to use pseudocode on exams (for planning before writing code) and in your actual programs.

+
diff --git a/pretext/Selection/toctree.ptx b/pretext/Selection/toctree.ptx index 5a7ff7e66..f39344864 100644 --- a/pretext/Selection/toctree.ptx +++ b/pretext/Selection/toctree.ptx @@ -12,6 +12,7 @@ 4 4 4 +4 4 4 diff --git a/pretext/thinkcspy.ptx b/pretext/thinkcspy.ptx index ffbb4e2c1..b992e2002 100644 --- a/pretext/thinkcspy.ptx +++ b/pretext/thinkcspy.ptx @@ -33,6 +33,8 @@ + +