"Code is more often read than written" - Guido van Rossum
So: code should be written to be readable by humans.
Note: one of those humans is future you.
import this
So how do we write good code for humans?
If you design your program using separate functions for each task, avoid copying + pasting (functions and loops instead), and consider structure beforehand, you'll be set up for success
Clear names are for humans. The computer doesn't care, but you and others reading your code do.
Helpful comments and documentation take your code to the next level. The final piece in the trifecta of readable code!
Good code has good documentation - but code documentation should not be used to try and fix unclear names, or bad structure.
Rather, comments should add any additional context and information that helps explain what the code is, how it works, and why it works that way.
These will all be components of your final project grade.
What does the following code do?
def ff(jj):
oo = list(); jj = list(jj)
for ii in jj: oo.append(str(ord(ii)))
return '+'.join(oo)
ff('Hello World.')
Improvement Considerations:
def return_unicode(input_list):
string = list()
input_list = list(input_list)
for character in input_list:
string.append(str(ord(character)))
output_string = '+'.join(string)
return output_string
return_unicode('Hello World.')
Improvement Considerations:
# Let's fix this code!
def convert_to_unicode(input_string):
"""Converts an input string into a string containing the unicode code points.
Parameters
----------
input_string : string
String to convert to code points
Returns
-------
output_string : string
String containing the code points for the input string.
"""
output = list()
# Converting a string to a list, to split up the characters of the string
input_list = list(input_string)
for character in input_list:
temp = ord(character)
output.append(temp)
output_string = '+'.join(output)
return output_string
Or: How to be Pythonic
Reasons to be Pythonic:
Consistency is the goal. Rules help us achieve consistency.
Much of this will apply to other programming languages, so it's good to learn...regardless of language.
Some of these Code Style notes will be more specific to Python, however.
These are written by the people responsible for the Python Programming language.
PEP are voted on before incorporation.
Defines the style guide for Pythonistas (people who code in Python).
Use spaces to indicate indentation levels, with each level defined as 4 spaces.
Computers used to require this.
But, super long lines are hard to read at a glance.
my_long_list = [1, 2, 3, 4, 5,
6, 7, 8, 9, 10]
# Note: you can explicitly indicate a new line with '\'
my_string = 'Python is ' + \
'a pretty great language.'
# Badness
for i in [1, 2, 3]: print(i**2 + i%2)
# Goodness
for i in [1, 2, 3]:
print(i**2 + i%2)
*
imports# Badness
from numpy import *
import os, sys
# Goodness
import os
import sys
import numpy as np
Note: If you don't know how to import a local/custom module, figure that out this week in Coding Lab or office hours.
Stuff written for humans in human language to help the humans.
Comments are string literals written directly in the code, typically directed at developers - people reading and potentially writing the code.
Documentation are descriptions and guides written for code users.
Code comments should use #
, and be written at the same indentation level of the code it describes.
How to use comments:
# This is a loop that iterates over elements in a list
for element in list_of_elements:
pass
# Because of X, we will use approach Y to do Z
for element in list_of_elements:
# comment for code block
pass
Out-of-date comments are worse than no comments at all.
Keep your comments up-to-date.
# Badness
import random
def week_9():
# help try to destress students by picking one thing from the following list using random
statements = ["You've totally got this!","You're so close!","You're going to do great!","Remember to take breaks!","Sleep, water, and food are really important!"]
out = random.choice(statements)
return out
week_9()
# Goodness
def week_9():
# Randomly pick from list of de-stressing statements
# to help students as they finish the quarter.
statements = ["You've totally got this!",
"You're so close!",
"You're going to do great!",
"Remember to take breaks!",
"Sleep, water, and food are really important!"]
out = random.choice(statements)
return out
week_9()
# Badness
week_9()#words of encouragement
# Goodness
week_9() # words of encouragement
Numpy style docs are a particular specification for docstrings.
def add(num1, num2):
"""Add two numbers together.
Parameters
----------
num1 : int or float
The first number, to be added.
num2 : int or float
The second number, to be added.
Returns
-------
answer : float
The result of the addition.
"""
answer = num1 + num2
return answer
Docstrings
"""
Docstrings are available to you outside of the source code.
Note: ChatGPT is pretty good at generating docstrings...
add?
# The `help` function prints out the `docstring`
# of an object (module, function, class)
help(add)
__doc__
¶# Docstrings get stored as the `__doc__` attribute
# can also be accessed from there
print(add.__doc__)
What should be included in a docstring?
def
lineDo all of my functions need numpy
documentation?
numpy
docstrings (required)Documentation Files:
README
is a file that provides an overview of the project to potential users and developersLICENSE
file specifies the license under which the code is available (the terms of use)API Reference
is a collection of the docstrings, listing public interfaces, parameters and return valuesnumpy.array
:
https://docs.scipy.org/doc/numpy/reference/generated/numpy.array.html
scikit learn (sklearn
) : https://scikit-learn.org/stable/index.html
pylint
is available from Anaconda to check this for you. (Not available on datahub.)
# to install on datahub
!pip install --user pylint
How many PEP8 violations can you find in this code?
def MyFunction(input_num):
my_list = [0,1,2,3]
if 1 in my_list: ind = 1
else:
ind = 0
qq = []
for i in my_list [ind:]:
qq.append(input_num/i)
return qq
# Let's fix this code
# check using pylint
!pylint linter_example.py
When you make changes to the software you've released into the world, you have to change the version of that software to let people know changes have occurred.
<MAJOR>
- increase by 1 w/ incompatible API changes<MINOR>
- increase by 1 w/ added functionality in a backwards-compatible manner<MAINTENANCE>
- (aka patch) increase by 1 w/ backwards-compatible bug fixes.# see version information
import pandas as pd
pd.__version__
In Python package development... when <MAJOR>
== 0, suggests a package in development
# see version information
!pip show pandas
Name: pandas Version: 2.1.4 Summary: Powerful data structures for data analysis, time series, and statistics Home-page: https://pandas.pydata.org Author: Author-email: The Pandas Development Team <pandas-dev@python.org> License: BSD 3-Clause License Copyright (c) 2008-2011, AQR Capital Management, LLC, Lambda Foundry, Inc. and PyData Development Team All rights reserved. Copyright (c) 2011-2023, Open source contributors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Location: /opt/anaconda3/envs/cogs18/lib/python3.11/site-packages Requires: numpy, python-dateutil, pytz, tzdata Required-by: seaborn