Draft
This page is a draft
I am going to go for a Raymond Hettinger style presentation, https://www.cs.odu.edu/~tkennedy/cs330/f20/Public/languageResources/#python-programming-videos.
These materials are web-centric (i.e., do not need to be printed and are available at https://www.cs.odu.edu/~tkennedy/python-workshop).
Who am I?
I have taught various courses, including:
- CS 300T - Computers in Society
- CS 333 - Programming and Problem Solving
- CS 330 - Object Oriented Programming and Design
- CS 350 - Introduction to Software Engineering
- CS 410 - Professional Workforce Development I
- CS 411W - Professional Workforce Development II
- CS 417 - Computational Methods & Software
Most of my free time is spent writing Python 3 and Rust code, tweaking my Vim configuration, or learning a new (programming) language. My current language of interest is Rust (at the time of writing).
Referenced Courses & Materials
I am going to pull from CS 330, CS 350, CS 411W, and CS 417 lecture notes.
- CS 330 - Object Oriented Programming & Design
- CS 350 - Introduction to Software Engineering
- CS 417 - Computational Methods & Software
I will also reference a couple examples from the previous:
The Broad Strokes
This workshop is intended as discussion on how to write Rust code that makes use of:
Tentative Topics
I will focus on:
- Lambda functions, usage, syntax, and expressions
- Structuring large python codebases
- Profiling python, engineering best practices
- Advanced tutorials for modern development : Classes, Polymorphism, Interfaces, etc.
- Debugging options in python ( A language that promotes rapid development is usually hard to debug. How can we do it in python? )
- Multithreading/Concurrent python
- Documenting code
Classes and OOP will take a while (the topic is quite vast). I will also discuss testing python code (with unit testing and integration testing) and code coverage, along with tox for basic configuration management.
I will try to fit in a few of the remaining topics:
- Correct usage of the .loc and .iloc functionality
- How to use NumPy
- Python for Machine learning, Tensorflow
- Data and workflow management
- Pandas Dataframe usage
- How do we use RDD and DataFrame.
- Implementing cryptographic algorithms
I should be able to fit in some discussion of NumPy.
Object Oriented
We need to discuss the rules of a class checklist.
C++ | Java | Python 3 | Rust |
---|---|---|---|
Default Constructor | Default Constructor | __init__ |
new() or Default trait |
Copy Constructor | Clone and/or Copy Constructor | __deepcopy__ |
Clone trait |
Destructor | |||
finalize (deprecated/discouraged) | __del__ |
Drop trait |
|
Assignment Operator (=) | |||
Accessors (Getters) | Accessors (Getters) | Accessors (@property ) |
Accessors (Getters) |
Mutators (Setters) | Mutators (Setters) | Setter (@attribute.setter ) |
Mutators (setters) |
Swap | |||
Logical Equivalence Operator (==) | equals | __eq__ |
std::cmp::PartialEq trait |
Less-Than / Comes-Before Operator (<) | hashCode | __hash__ |
std::cmp::PartialOrd trait |
std::hash (actual hashing)
|
hashCode | __hash__ |
std::hash::Hash trait |
Stream Insertion Operator (<<) | toString | __str__ |
std::fmt::Display trait |
__repr__ |
std::fmt::Debug trait |
||
begin() and end()
|
iterator |
__iter__ |
iter() and iter_mut()
|
Code Documentation
These notes are based on my CS 330 (Object Oriented Programming and Design) and CS 417/517 (Computation Methods) notes, https://www.cs.odu.edu/~tkennedy/cs330/f20/Public/codeDocumentation/index.html.
Most of your code has probably had quite a fewiin-line comments. Inline comments are not the focus of this discussion. The focus of thisS discussion is documentation of classes, functions, and methods.
A Few Starting Examples
I work in few different languages. Throughout my
- C++ code you will find Doxygen style comments.
- Java code you will find Javadoc style comments.
- Python code you will find Pydoc style comments.
- Rust code you will find Rustdoc style comments.
You have definitely been told to "comment your code" in the past, but (probably) in a less formal fashion.
Let us start with a few selected documentation examples from my CS 330 and CS 417 notes.
C++
Doxygen can be used for C++. Consider the following Doxygen Example:
\bExample{C++ Doxygen Documentation}
/**
* Retrieve the value stored in three selected Cells
*
* @param cell1Id numeric id representing the 1st desired cell
* @param cell2Id numeric id representing the 2nd desired cell
* @param cell3Id numeric id representing the 3rd desired cell
*
* @return value stored in the Cell
*
* @pre (cell1Id > 0 && cell1Id < 10) &&
* (cell2Id > 0 && cell2Id < 10) &&
* (cell3Id > 0 && cell3Id < 10)
*/
CellTriple get3Cells(int cell1Id, int cell2Id, int cell3Id) const;
\eExample
Java
Javadoc can be used for Java. Consider the following Javadoc Example:
\bExample{Javadoc Documentation}
/**
* Multi-thread Coin Flip.
*
* @param numTrials # flips to simulate
* @param numThreads number of threads to use
*
* @return Completed FlipTasks
*
* @throws InterruptedException if a thread is stopped prematurely
*/
public static FlipTask[] multiThread(long numTrials, int numThreads)
throws InterruptedException
\eExample
Python
Pydoc or Sphinx can be used for Python. Consider the following Pydoc Example:
\bExample{Python 3 Pydoc Documentation}
def parse_raw_temps(original_temps: TextIO,
step_size: int=30, units: bool=True) -> Iterator[Tuple[float, List[float]] ]:
"""
Take an input file and time-step size and parse all core temps.
:param original_temps: an input file
:param step_size: time-step in seconds
:param units: True if the input file includes units and False if the file
includes only raw readings (no units)
:yields: A tuple containing the next time step and a List containing _n_
core temps as floating point values (where _n_ is the number of
CPU cores)
"""
\eExample
I prefer the Sphinx/Google style for Python.
\bExample{Python 3 Sphinx/Google Style Documentation}
def parse_raw_temps(original_temps: TextIO,
step_size: int=30, units: bool=True) -> Iterator[Tuple[float, List[float]] ]:
"""
Take an input file and time-step size and parse all core temps.
Args:
original_temps: an input file
step_size: time-step in seconds
units: True if the input file includes units and False if the file
includes only raw readings (no units)
Yields:
A tuple containing the next time step and a List containing _n_
core temps as floating point values (where _n_ is the number of
CPU cores)
"""
\eExample
Rust
\bExample{Rust Documentation}
///
/// Take a room and change the flooring
///
/// # Arguments
///
/// * `original` - House to change
///
/// # Returns
///
/// House with the updated flooring
///
fn upgrade_flooring(original: &House) -> House {
//...
}
\eExample
Rust and Python have similar documentation styles (give or take some markdown
formatting). Since we only cover small snippets of Rust in this course (for
context), we will forgo a complete
Rustdoc discussion.
Writing Good Documentation
All code should be properly and fully documented using a language appropriate comment style. All functions (including parameters and return types) must be documented.
Documentation for a New Function
Suppose we have just finished writing a quick program to simulate a trick coin (i.e., a coin where heads and tails are not equally probable).
def one_flip(p):
return True if random.random() < p else False
def main():
num_flips = 8;
for _i in range(0, num_flips):
if one_flip(0.7):
print("Heads")
else:
print("Tails")
if __name__ == "__main__":
main()
The one_flip
function needs a description.
def one_flip(p):
"""
Simulate a single coin flip.
"""
What does p
represent? Does it represent the probability of heads or tails?
def one_flip(p):
"""
Simulate a single coin flip.
Args:
p: probability of heads in the range [0, 1]
"""
Now what about the return? We know that bool
means a true
or false
. Which
one do I get for heads? Let us add an @return
.
/**
* Simulate a single coin flip.
*
* @param p probability of heads
*
* @return true if the result is heads and false if the result is tails
*/
bool one_flip(double p);
def one_flip(p):
"""
Simulate a single coin flip.
Args:
p: probability of heads in the range [0, 1]
Returns:
True if the result is heads and False if the result is tails
"""
There is no more ambiguity or guesswork. Both p
and the possible return
values are documented.
Type Hints
I am a stickler for type hints...
def one_flip(p: float) -> bool:
"""
Simulate a single coin flip.
Args:
p: probability of heads in the range [0, 1]
Returns:
True if the result is heads and False if the result is tails
"""