generated from PovertyAction/ipa-python-template
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy path18-style.qmd
More file actions
262 lines (199 loc) · 8.6 KB
/
18-style.qmd
File metadata and controls
262 lines (199 loc) · 8.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
---
title: "Programming Style"
abstract: |
Provide sound justifications for basic rules of coding style. Refactor one-page programs to make them more readable and justify the changes. Use Python community coding standards (PEP-8).
date: last-modified
format:
html: default
# Authors
authors-ipa:
- "[Author Name](https://poverty-action.org/people/author_name)"
# Contributors
contributors:
- "[Contributor Name](https://poverty-action.org/people/contributor_name)"
keywords: ["Python", "Programming", "Tutorial", "Data Science", "Jupyter"]
license: "CC BY 4.0"
---
::: {.callout-note}
## Learning Objectives
- Provide sound justifications for basic rules of coding style.
- Refactor one-page programs to make them more readable and justify the changes.
- Use Python community coding standards (PEP-8).
::: {.callout-tip}
## Key Questions
- How can I make my programs more readable?
- How do most programmers format their code?
- How can programs check their own operation?
## Coding style
A consistent coding style helps others (including our future selves) read and understand code more easily. Code is read much more often than it is written, and as the [Zen of Python](https://www.python.org/dev/peps/pep-0020) states, "Readability counts".
Python proposed a standard style through one of its first Python Enhancement Proposals (PEP), [PEP8](https://www.python.org/dev/peps/pep-0008).
Some points worth highlighting:
- document your code and ensure that assumptions, internal algorithms, expected inputs, expected outputs, etc., are clear
- use clear, semantically meaningful variable names
- use white-space, *not* tabs, to indent lines (tabs can cause problems across different text editors, operating systems, and version control systems)
## Follow standard Python style in your code
- [PEP8](https://www.python.org/dev/peps/pep-0008):
a style guide for Python that discusses topics such as how to name variables,
how to indent your code,
how to structure your `import` statements,
etc.
Adhering to PEP8 makes it easier for other Python developers to read and understand your code, and to understand what their contributions should look like.
- To check your code for compliance with PEP8, you can use the [pycodestyle application](https://pypi.org/project/pycodestyle/) and tools like the [black code formatter](https://github.com/psf/black) can automatically format your code to conform to PEP8 and pycodestyle (a Jupyter notebook formatter also exists [nb\_black](https://github.com/dnanhkhoa/nb_black)).
- Some groups and organizations follow different style guidelines besides PEP8. For example, the [Google style guide on Python](https://google.github.io/styleguide/pyguide.html) makes slightly different recommendations. Google wrote an application that can help you format your code in either their style or PEP8 called [yapf](https://github.com/google/yapf/).
- With respect to coding style, the key is *consistency*. Choose a style for your project be it PEP8, the Google style, or something else and do your best to ensure that you and anyone else you are collaborating with sticks to it. Consistency within a project is often more impactful than the particular style used. A consistent style will make your software easier to read and understand for others and for your future self.
## Use assertions to check for internal errors
Assertions are a simple but powerful method for making sure that the context in which your code is executing is as you expect.
```python
def calc_bulk_density(mass, volume):
'''Return dry bulk density = powder mass / powder volume.'''
assert volume > 0
return mass / volume
```
If the assertion is `False`, the Python interpreter raises an `AssertionError` runtime exception. The source code for the expression that failed will be displayed as part of the error message. To ignore assertions in your code run the interpreter with the '-O' (optimize) switch. Assertions should contain only simple checks and never change the state of the program. For example, an assertion should never contain an assignment.
## Use docstrings to provide builtin help
If the first thing in a function is a character string that is not assigned directly to a variable, Python attaches it to the function, accessible via the builtin help function. This string that provides documentation is also known as a *docstring*.
```python
def average(values):
"Return average of values, or None if no values are supplied."
if len(values) == 0:
return None
return sum(values) / len(values)
help(average)
```
```output
Help on function average in module __main__:
average(values)
Return average of values, or None if no values are supplied.
```
::: {.callout-note}
## Multiline Strings
Often use *multiline strings* for documentation.
These start and end with three quote characters (either single or double)
and end with three matching characters.
```python
"""This string spans
multiple lines.
Blank lines are allowed."""
```
::: {.callout-note}
## Exercise: What Will Be Shown?
Highlight the lines in the code below that will be available as online help.
Are there lines that should be made available, but won't be?
Will any lines produce a syntax error or a runtime error?
```python
"Find maximum edit distance between multiple sequences."
# This finds the maximum distance between all sequences.
def overall_max(sequences):
'''Determine overall maximum edit distance.'''
highest = 0
for left in sequences:
for right in sequences:
'''Avoid checking sequence against itself.'''
if left != right:
this = edit_distance(left, right)
highest = max(highest, this)
# Report.
return highest
```
::: {.callout-note}
## Exercise: Document This
Use comments to describe and help others understand potentially unintuitive
sections or individual lines of code. They are especially useful to whoever
may need to understand and edit your code in the future, including yourself.
Use docstrings to document the acceptable inputs and expected outputs of a method
or class, its purpose, assumptions and intended behavior. Docstrings are displayed
when a user invokes the builtin `help` method on your method or class.
Turn the comment in the following function into a docstring
and check that `help` displays it properly.
```python
def middle(a, b, c):
# Return the middle value of three.
# Assumes the values can actually be compared.
values = [a, b, c]
values.sort()
return values[1]
```
::: {.callout-tip collapse="true"}
## Solution
## Solution
```python
def middle(a, b, c):
'''Return the middle value of three.
Assumes the values can actually be compared.'''
values = [a, b, c]
values.sort()
return values[1]
```
::: {.callout-note}
## Exercise: Clean Up This Code
1. Read this short program and try to predict what it does.
2. Run it: how accurate was your prediction?
3. Refactor the program to make it more readable.
Remember to run it after each change to ensure its behavior hasn't changed.
4. Compare your rewrite with your neighbor's.
What did you do the same?
What did you do differently, and why?
```python
n = 10
s = 'et cetera'
print(s)
i = 0
while i < n:
# print('at', j)
new = ''
for j in range(len(s)):
left = j-1
right = (j+1)%len(s)
if s[left]==s[right]: new = new + '-'
else: new = new + '*'
s=''.join(new)
print(s)
i += 1
```
::: {.callout-tip collapse="true"}
## Solution
## Solution
Here's one solution.
```python
def string_machine(input_string, iterations):
"""
Takes input_string and generates a new string with -'s and *'s
corresponding to characters that have identical adjacent characters
or not, respectively. Iterates through this procedure with the resultant
strings for the supplied number of iterations.
"""
print(input_string)
input_string_length = len(input_string)
old = input_string
for i in range(iterations):
new = ''
# iterate through characters in previous string
for j in range(input_string_length):
left = j-1
right = (j+1) % input_string_length # ensure right index wraps around
if old[left] == old[right]:
new = new + '-'
else:
new = new + '*'
print(new)
# store new string as old
old = new
string_machine('et cetera', 10)
```
```output
et cetera
*****-***
----*-*--
---*---*-
--*-*-*-*
**-------
***-----*
--**---**
*****-***
----*-*--
---*---*-
```
::: {.callout-important}
## Key Points
- Follow standard Python style in your code.
- Use docstrings to provide builtin help.