The following section is not meant to be a comprehensive introduction to the Python language. With that out of the way, this page serves to show students the "gist" of Python and some of the core functionality. It is not required to read all of these sections! If you believe you are comfortable enough with Python, then simply return to the root project page begin the first assignment!
For those who have experiece with other programming languages, I will try my best to summarize everything that you should know about Python in order to easily complete this project. We start with some basic syntax in the form of loops and conditionals with the following excerpts:
As seen above, printing statements and forming logic can be fairly straightforward. The only problem that comes from this straightforwardness is that there are now more variables that are keywords and thus should not be used as variable names (Python won't stop you, however!). Secondly, note that the variables in Python are dynamically typed as opposed to C's static variable typing. Dynamic typing means that the variables themselves can contain any type of object and they can change at any point. In other words, you can do the following and no errors will be thrown:
In summary, Python aims to make rapid development possible by removing the user from memory management. Clearly, this means that the language will take some performance hits, but it is possible to implement some very generic functions with some form of safety (i.e. type hinting).
On the subject of features, Python has some built in data-structures readily available for use. These take the form of lists, tuples, and dictionaries. Lists are a mutable and ordered data type much like C arrays. However, lists have some very convenient methods implemented that allow the user to modify lists explicitly. Tuples are an immutable and ordered data type. Like lists, they also have quite a few functions for use, but these functions generally are not in-place (that means a new tuple must be created!). Finally, dictionaries are a way of storing (key,value) pairs and are not guaranteed to be ordered by key. Some examples of their usage and basic API can be seen below with some examples of list and tuple usage. Keep in mind that you will not be required to memorize the API, but knowing some basic methods of each data structure can be useful.
Finally, as seen before we can perform the equivalent of a library inclusion in C in the form of imports in Python. Modules are brought into global scope, but the methods are sub-classed under the name of the module itself. Of course, Python allows you to either bring all functions into the global scope or subclass them under a different name. More on this can be seen below (for more information about how importing functions works, consider this article on namespaces in Python):
This concludes the basic introduction to Python. There is a lot more to the language that can be said, but this summarizes the bare minimum needed in order to use Python. In case it wasn't clear by this point, Python is a space-based language. That is, the indentation level determines the depth of the code and can cause your program to not run if spaces are inconsistent (i.e. mixing tabs + spaces or inconsistent spacing). You will be sure to understand as you write more in Python. It is definitely a fantastic language for doing many things that require a fast development process.
The previous section focused on the level of Python needed to just barely get through the project without too many issues. However, there are a lot of aspects that can further your understanding of the project if you can understand more than just basic structures in Python. The following is dedicated to introducing some more Pythonic elements used in this project through the use of comprehension syntax, lambdas, functors (AKA function objects), and decorators. [Classes are not covered but can be seen in some of the resources below.]
Loops and conditionals are perfectly fine for the average user, but Python offers a slightly more Pythonic syntax of the for-each loop from before. Through the object comprehension syntax, generating lists, tuples, and dictionaries can be a single line affair with the correct structure. What follows are some examples of this object comprehension syntax:
One thing to notice is that as a result of Python being dynamically typed, you can essentially view every single variable as an object. What is meant by this is that every single one of these variables has some set of methods which are available to it by virtue of being sub-classed from the object class. While there may not be very many methods available for the primitive data types, there are many that can be available for more complex data types such as the lists we have been working with. One interesting thing about this is that even functions can be considered an object in this sense. In essence, absolutely nothing is preventing you from passing these argument-less, or unbound, functions (otherwise known as functors) into other functions! Combined with lambda functions, this is a pretty powerful construct.
Finally we reach decorators. An exhaustive interpretation of decorators can be found elsewhere, but here I will just try to cover enough to understand the Flask API and what it generally seeks to do using this construct. If we consider a function as a black box, then a decorator seeks to create a "wrapper" for this black box. As an example, we want a function foo() to also perform some task bar(). If these two tasks are independent of each other, then instead of writing a function foobar() to perform this task, we can write a decorator wrapFoo that performs the tasks in foo and then performs the tasks in bar without having to re implement foo in the process.
The last line in the code above shows how decorators actually work. They "wrap" functions by taking in the function and then using the function within it's own declaration and then returning a modified function. This modified function can then be called exactly like in the decorator execution line. This syntactical sugar makes applying decorators extremely convenient for the programmer, and it is commonly used for the standard decorators that Python offers for tasks such as function output caching.
However, the example above is naturally missing the reason we should do that if we either have access to the source code or simply only want to create a wrapper for a single function. Usually we do not like having to open up the source code, but even if we did it could potentially be a couple lines of differences, right? Consider the following scenario: you now have N functions foo1(), foo2(), ..., fooN(), each with some unique functionality. We would like to modify ALL of these functions in such that they operate in similar but different ways. Say that we want to measure the execution time of all functions without wanting to re-implement them from scratch. However, we would also like our timing decorator to give some extra information when printing the time (we would like to differentiate between all N functions, after all!). In this circumstance, the only sane option would be to implement a decorator that modifies all N functions to do the desired time execution measurement along with the minor adjustment. Naturally, we would generate unique decorators for each class with the minor adjustment. This is actually a design pattern very commonly experienced! We simply create a "factory" for decorators (or a function that returns modified decorators). This function acts as a decorator as the function is processed and thus adheres to the typical decorator usage format we encountered above. We implement this scenario in the following code segment (where N=3):
And, it turns out that this is exactly how Flask functions! The logic behind Flask is that the routing behavior is hidden behind a decorator factory that creates a decorator that modifies the server class object in such a way that it can accept certain types of requests on a specific sub-directory and then process these requests through a given function. This allows you to use any class variable typically declared in the Flask interface within the original function (your wrappers will have defined a set of variables anyway), thus opening the Flask interface to any function the user creates. This is an extremely extensible interface that is perfect for prototyping very simple web servers! No examples will be given of the Flask interface, but you are free to read up on how the interface works in the official Flask python interface documentation.
This summarizes some of the more complex syntax that is present in Python. You will be seeing quite a few of these structures as you go on with the project simply because these structures make it much easier for the developer and the user to create modules that easily interface and are generic. Hopefully you will be developing similar code too!
This is about as much as this project will cover. While there are still many more elements to Python, these elements are moreso extensions of already present features in different languages. The above covered essentially the most basic and unique elements of Python without getting too far into just being a generic programming introduction. If you feel that you still are not ready for the Python workload of this assignment, what follows are a couple resources that cover essentially what was covered here (and possibly a bit more in detail):
As per usual, always consult the API first if you don't initially understand the problem. If you still have issues understanding the API, then feel free to look at other online resources that roughly covers the same usage.