... | @@ -84,5 +84,282 @@ T.B.W |
... | @@ -84,5 +84,282 @@ T.B.W |
|
|
|
|
|
|
|
|
|
---
|
|
---
|
|
|
|
|
|
|
|
# Topics
|
|
|
|
|
|
|
|
|
|
|
|
* A quick overview of procedural, object-oriented and functional style programming (very briefly).
|
|
|
|
* PEP 8, <https://www.python.org/dev/peps/pep-0008/> and PEP 20, <https://www.python.org/dev/peps/pep-0020/>
|
|
|
|
* Loops, context managers, and list/generator comprehensions, <https://www.cs.odu.edu/~tkennedy/cs330/f20/Public/switchingToPython/index.html>.
|
|
|
|
* ~~The basic Python data structures (List, Dictionary, and Set)~~
|
|
|
|
* Generator Expressions
|
|
|
|
* A few Python modules, including Zip, json, and argparse, <https://www.cs.odu.edu/~tkennedy/cs330/f20/Public/switchingToPython/index.html#python-includes-batteries>
|
|
|
|
* Writing Pythonic code (e.g., using enumerate), <https://www.cs.odu.edu/~tkennedy/cs330/f20/Public/whichLanguageIsIt/index.html#a-little-python>.
|
|
|
|
* Time permitting... a little unit testing.
|
|
|
|
|
|
|
|
|
|
|
|
# Procedural, Object-Oriented & Functional Programming
|
|
|
|
|
|
|
|
TBW
|
|
|
|
|
|
|
|
# Pythonic Code
|
|
|
|
|
|
|
|
TBW
|
|
|
|
|
|
|
|
# Loops, Context Managers, and List/Generator Comprehensions
|
|
|
|
|
|
|
|
This section is based on [notes from CS 330 Object Oriented Programming & Design](https://www.cs.odu.edu/~tkennedy/cs330/f20/Public/switchingToPython/index.html).
|
|
|
|
|
|
|
|
|
|
|
|
# # Data Structures
|
|
|
|
|
|
|
|
When I work in Python, I generally focus on three core (fundamental) data
|
|
|
|
structures.
|
|
|
|
|
|
|
|
- Lists: `prime_numbers = [1, 2, 3, 5, 7, 11, 13, 17, 19]`
|
|
|
|
- Dictionaries: `favourite_colors = {"Thomas": "Blue", "Jessica": "Purple"}`
|
|
|
|
- `collections.defaultdict`
|
|
|
|
- `collections.Counter`
|
|
|
|
- Sets: `some_colors = {"Blue", "Red", "Green", "Cyan", "Teal"}`
|
|
|
|
|
|
|
|
If we want to map these to (modern) C++, Java, and Rust... we end up with...
|
|
|
|
|
|
|
|
|
|
|
|
| Python | C++ | Java | Rust |
|
|
|
|
| :----- | :---- | :---- | :---- |
|
|
|
|
| `list` | `std::list` | `java.util.List` | `std::collections::LinkedList` |
|
|
|
|
| `dict` | `std::unordered_map` | `java.util.HashMap` | `std::collections::HashMap` |
|
|
|
|
| `set` | `std::unordered_set` | `java.util.HashSet` | `std::collections::HashSet` |
|
|
|
|
|
|
|
|
|
|
|
|
## Lists & List Comprehensions
|
|
|
|
|
|
|
|
The next few discussions will include [list comprehensions](https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions),
|
|
|
|
dictionary comprehensions and set comprehensions.
|
|
|
|
|
|
|
|
Suppose we have a list of programming terms and want to create a second list
|
|
|
|
containing the length of each term. We might take the usual C, C++, or Java
|
|
|
|
approach:
|
|
|
|
|
|
|
|
> **Word Count - Boring C++ Loop**
|
|
|
|
>
|
|
|
|
> ```c++
|
|
|
|
> using std::string;
|
|
|
|
> using std::vector;
|
|
|
|
>
|
|
|
|
>
|
|
|
|
> int main(int argc, char** argv)
|
|
|
|
> {
|
|
|
|
> vector<string> some_terms {"Hello", "world", "with", "for", "while", "int"};
|
|
|
|
> vector<int> term_lengths(some_terms.size(), 0);
|
|
|
|
>
|
|
|
|
> for (int i = 0; i < term_lengths.size(); i++) {
|
|
|
|
> term_lengths[i] = some_terms[i].size();
|
|
|
|
> }
|
|
|
|
>
|
|
|
|
> return 0;
|
|
|
|
> }
|
|
|
|
> ```
|
|
|
|
|
|
|
|
and translate it into Python:
|
|
|
|
|
|
|
|
> ** Word Count - Boring Python Loop**
|
|
|
|
>
|
|
|
|
> ```python
|
|
|
|
> def main():
|
|
|
|
> some_terms = ["Hello", "world", "with", "for", "while", "int"]
|
|
|
|
>
|
|
|
|
> term_lengths = []
|
|
|
|
>
|
|
|
|
> for term in some_terms:
|
|
|
|
> term_lengths.append(len(term))
|
|
|
|
>
|
|
|
|
>
|
|
|
|
> if __name__ == "__main__":
|
|
|
|
> main()
|
|
|
|
> ```
|
|
|
|
|
|
|
|
|
|
|
|
The Python version can (and should) use a list comprehension.
|
|
|
|
|
|
|
|
> **Word Count - Fun Python Loop**
|
|
|
|
>
|
|
|
|
> ```python
|
|
|
|
> def main():
|
|
|
|
> some_terms = ["Hello", "world", "with", "for", "while", "int"]
|
|
|
|
>
|
|
|
|
> term_lengths = [len(term) for term in some_terms]
|
|
|
|
>
|
|
|
|
>
|
|
|
|
> if __name__ == "__main__":
|
|
|
|
> main()
|
|
|
|
> ```
|
|
|
|
|
|
|
|
|
|
|
|
Depending on how many terms we have... a generator expression might be more
|
|
|
|
appropriate:
|
|
|
|
|
|
|
|
> **Word Count - Really Fun Python Loop**
|
|
|
|
>
|
|
|
|
> ```python
|
|
|
|
> def main():
|
|
|
|
> some_terms = ["Hello", "world", "with", "for", "while", "int"]
|
|
|
|
>
|
|
|
|
> term_lengths = (len(term) for term in some_terms)
|
|
|
|
>
|
|
|
|
>
|
|
|
|
> if __name__ == "__main__":
|
|
|
|
> main()
|
|
|
|
> ```
|
|
|
|
|
|
|
|
|
|
|
|
## Modern C++ and std::transform
|
|
|
|
|
|
|
|
|
|
|
|
Modern C++11 and newer provide the `std::transform` method. Combined with
|
|
|
|
`lambda functions` we can take the original C++ code... and rewrite it as
|
|
|
|
|
|
|
|
**Word Count - C++ `std::transform`**
|
|
|
|
|
|
|
|
> ```c++
|
|
|
|
> using std::string;
|
|
|
|
> using std::vector;
|
|
|
|
>
|
|
|
|
>
|
|
|
|
> int main(int argc, char** argv)
|
|
|
|
> {
|
|
|
|
> vector<string> some_terms {"Hello", "world", "with", "for", "while", "int"};
|
|
|
|
> vector<int> term_lengths;
|
|
|
|
>
|
|
|
|
> std::transform(some_terms.begin(), some_terms.end(), std::back_inserter(term_lengths),
|
|
|
|
> [](const string& t) -> int {
|
|
|
|
> return t.size();
|
|
|
|
> });
|
|
|
|
>
|
|
|
|
> return 0;
|
|
|
|
> }
|
|
|
|
> ```
|
|
|
|
|
|
|
|
Java has the `java.util.stream` package, which provides similar functionality
|
|
|
|
to Python comprehensions and C++ `std::transform`. However, in Java, we would
|
|
|
|
end up dealing with the `Integer` wrapper class if we wanted to use a non-array data structure.
|
|
|
|
|
|
|
|
|
|
|
|
> **Word Count - Java Streams**
|
|
|
|
>
|
|
|
|
> ```java
|
|
|
|
> import java.util.Arrays;
|
|
|
|
> import java.util.List;
|
|
|
|
>
|
|
|
|
> public class IntStreamDemo
|
|
|
|
> {
|
|
|
|
> public static void main(String... args)
|
|
|
|
> {
|
|
|
|
> List<String> some_terms = Arrays.asList("Hello", "world", "with",
|
|
|
|
> "for", "while", "int");
|
|
|
|
>
|
|
|
|
> int[] term_lengths = some_terms.stream()
|
|
|
|
> .mapToInt(s -> s.length())
|
|
|
|
> .toArray();
|
|
|
|
> }
|
|
|
|
> }
|
|
|
|
> ```
|
|
|
|
|
|
|
|
|
|
|
|
**The Python implementation is the most succinct, approachable, and readable.**
|
|
|
|
|
|
|
|
|
|
|
|
# Context Managers
|
|
|
|
|
|
|
|
Python provides the `with` statement (construct). This allows the setup and
|
|
|
|
teardown involved in using resources (e.g., files, sockets, and database
|
|
|
|
connections) to handled elsewhere.
|
|
|
|
|
|
|
|
This has two main benefits:
|
|
|
|
|
|
|
|
1. There is less boilerplate code.
|
|
|
|
2. It is impossible to forget to close/deallocate a resource.
|
|
|
|
|
|
|
|
To write to a file, one might write:
|
|
|
|
|
|
|
|
> **Python File IO - Basic**
|
|
|
|
>
|
|
|
|
> ```python
|
|
|
|
> text_file = open("some_file.txt", "w")
|
|
|
|
>
|
|
|
|
> for number in range(1, 100):
|
|
|
|
> text_file.write(f"{number}\n")
|
|
|
|
> ```
|
|
|
|
|
|
|
|
Did you notice the missing `fclose(text_file)`? With one small `with` the file
|
|
|
|
close operation will be handled automatically.
|
|
|
|
|
|
|
|
> **Python File IO - Using `with`**
|
|
|
|
>
|
|
|
|
> ```python
|
|
|
|
> with open("some_file.txt", "w") as text_file:
|
|
|
|
> for number in range(1, 100):
|
|
|
|
> text_file.write(f"{number}\n")
|
|
|
|
> ```
|
|
|
|
|
|
|
|
This also works for other types of files--including compressed files.
|
|
|
|
|
|
|
|
> **Python File IO - Using `with` and `gzip`**
|
|
|
|
>
|
|
|
|
> ```python
|
|
|
|
> import gzip
|
|
|
|
>
|
|
|
|
> with gzip.open("some_file.txt.gz", "wt") as text_file:
|
|
|
|
> for number in range(1, 100):
|
|
|
|
> text_file.write(f"{number}\n")
|
|
|
|
> ```
|
|
|
|
|
|
|
|
# Python Includes Batteries
|
|
|
|
|
|
|
|
For many languages external libraries are usually required for *common
|
|
|
|
operations*. [Python includes batteries](https://www.python.org/dev/peps/pep-0206/#id3).
|
|
|
|
|
|
|
|
| Operation | Built-in Python Module |
|
|
|
|
| :---------------------------------------- | :------------------ |
|
|
|
|
| Zip Files | `import zipfile` |
|
|
|
|
| GZipped Files | `import gzip` |
|
|
|
|
| Reading, writing, or generating JSON | `import json` |
|
|
|
|
| Converting objects to JSON | `import json` |
|
|
|
|
| Serializing objects and data structures | `import pickle` |
|
|
|
|
| Working with time | `import time` |
|
|
|
|
| Working with dates and time | `import datetime` |
|
|
|
|
| Working with SQLite | `import sqlite3` |
|
|
|
|
| Building a calendar | `import calendar` |
|
|
|
|
| Generating log files | `import logfile` |
|
|
|
|
| Advanced command line arguments | `import argparse` |
|
|
|
|
|
|
|
|
|
|
|
|
# Libraries & pip
|
|
|
|
|
|
|
|
When external libraries are required, the Python `pip` utility and a
|
|
|
|
`requirements.txt` can be used for all dependency and configuration management.
|
|
|
|
|
|
|
|
In C/C++ we hope for a Linux environment (or Docker). In Java... Gradle is a
|
|
|
|
popular build and configuration management tool.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|