Code Style

  • PEP8

  • spacing

  • line length

  • comments

Clicker Question #1

Do you have an idea of what you want to do for your project?

  • A) absolutely no idea

  • B) some idea, but not sure

  • C) sort of

  • D) fairly good idea

  • E) I know exactly what I want to do.

Example Final Projects: https://github.com/COGS18/Projects

Clicker Question #2

Your final project is a chatbot that will discuss sports with you. How would you implement this?

  • A) Jupyter Notebook only

  • B) module only

  • C) module + Jupyter Notebook

  • D) script only

  • E) script + Jupyter Notebook

Or: How to be Pythonic

Reasons to be Pythonic:

  • user friendly for humans

  • extra work up-front on the developers (pays off on the long run)

  • best to practice this early on (I promise!)

Style Guides

Coding style refers to a set of conventions for how to write good code.

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.

The Zen of Python

import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

Program Errors vs. Stylistic Issues

  • Programmatic Error: something that breaks the code

  • Stylistic Issue: something that doesn’t break the code, but is considered bad style - makes your code harder to understand

Picking a Style Guide

  • Code style is (at least partly) subjective

  • Consistency is key. It’s easier to recognize & read consistent style

Python Enhancement Proposals (PEPs)

Python PEPs are proposals for how something should be / work in the Python programming language.

These are written by the people responsible for the Python Programming language.

PEP are voted on before incorporation.

PEP8

PEP8 is an accepted proposal that outlines the style guide for Python.

Defines the style guide for Pythonistas (people who code in Python).

General Concepts

  • Be Explicit & Clear

    • Prioritize Readability over ‘Cleverness’

  • There should be specific, standard ways to do things

    • Use them

  • Coding Style are guidelines, designed to help the code

    • They are not laws

Specific Guidelines - Structure

  • blank lines

  • indentaion

  • spacing

  • length

  • imports

Blank Lines

  • Use 2 blank lines between functions & classes, and 1 between methods

  • Use 1 blank line between segments to indicate logical structure

This allows you to - at a glance - identify what pieces of code are there.

# Badness
def my_func():
    my_nums = '123'
    output = ''
    for num in my_nums:
        output += str(int(num) + 1)
    return output
my_func()
# Goodness
def my_func():
    
    my_nums = '123'
    output = ''
    
    for num in my_nums: 
        output += str(int(num) + 1)
    
    return output

Note that documentation here is missing (as are comments). This is to highlight the spacing. You’ll need documentation and comments.

I promise it’s better to comment as you go along rather than coming along after you’ve written all the code and adding comments.

Similar to writing: write comments -> write code -> review code & comments

Clicker Question #3

Which of these is best - A, B, or C?

# Option A
def squared(input_number):
    val = input_number
    power = 2    
    output = val ** power
    return output
# Option B
def squared(input_number, power=2):
    
    output = input_number ** power
    
    return output
# Option C
def squared(input_number):
    
    val = input_number
    power = 2
    
    output = val ** power
    
    return output

Indentation

Use spaces to indicate indentation levels, with each level defined as 4 spaces.

# Badness
if True:
  print('Words.')
Words.
# Goodness
if True:
    print('Words.')
Words.

Spacing

  • Put one (and only one) space between each element

  • Index and assignment don’t have a space between opening & closing ‘()’ or ‘[]’

# Badnesses
my_var=1+2==3
my_list  =  [ 1,2,3,4 ]
el = my_list [1]
# Goodnesses
my_var = 1 + 2 == 3
my_list = [1, 2, 3, 4]
el = my_list[1]

Clicker Question #4

Which of the following uses PEP-approved spacing?

  • A) my_list=[1,2,3,4,5]

  • B) my_list = [1,2,3,4,5]

  • C) my_list  =  [1, 2, 3, 4, 5]

  • D) my_list=[1, 2, 3, 4, 5]

  • E) my_list = [1, 2, 3, 4, 5]

Line Length

  • PEP8 recommends that each line be at most 79 characters long

Computers used to require this.

But, super long lines are hard to read at a glance.

One Statement Per Line

  • While you can condense multiple statements into one line, you usually shouldn’t.

# Badness
for i in [1, 2, 3]: print(i**2 + i%2)
2
4
10
# Goodness
for i in [1, 2, 3]:
    print(i**2 + i%2)

Multi-Line

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.'

Imports

  • Import one module per line

  • Avoid * imports

  • Use the import order: standard library; 3rd party packages; local / custom code

# 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.

Specific Guidelines - Naming

Valid Names

  • Use descriptive names for all modules, variables, functions and classes, that are longer than 1 character

# Badness
a = 12
b = 24
# Goodness
n_filters = 12
n_freqs = 24

Find + Replace also works better when you have specific variable names

Naming Style

  • CapWords (leading capitals, no separation) for Classes

  • snake_case (all lowercase, underscore separator) for variables, functions, and modules

# Badness
def MyFunc():
    pass
    
class my_class():
    def __init__():
        pass
# Goodness
def my_func():
    pass


class MyClass():
    def __init__():
        pass

Note: snake_case is easier to read than CapWords, so we use snake_case for the things (variables, functions) that we name more frequently.

Clicker Question #5

If you were reading code and came cross the following, which of the following would you expect to be a class?

  • A) Phillies_Game

  • B) PhilliesGame

  • C) phillies_game

  • D) philliesgame

  • E) PhIlLiEsGaMe

Clicker Question #6

If you were reading code and came cross the following, which of the following would you expect to be a function or variable name?

  • A) Phillies_Game

  • B) PhilliesGame

  • C) phillies_game

  • D) philliesgame

  • E) PhIlLiEsGaMe

Indicating Scope

  • Leading underscores indicate a ‘private’ attribute or method of the class, meaning it is an internal value, not expected to be accessed by the user.

class MyClass():
    def __init__():
        self.public = None
        self._private = None

The leading underscore indicates to the user that this attribute shouldn’t be changed/modified by the user.

import * will not import underscored attributes (private attributes).

Specific Guidelines - String Quotes

In Python, single-quoted strings and double-quoted strings are the same.

This PEP does not make a recommendation for this. Pick a rule and stick to it.

When a string contains single or double quote characters: use the other one to avoid backslashes in the string. It improves readability.

# Badness
my_string = 'Prof\'s Project'
# Goodness
my_string = "Prof's Project"

Clicker Question #7

Which of the following would not cause an error in Python and would store the string You’re so close! ?

  • A) my_string = "You're so close!"

  • B) my_string = "You"re so close!"

  • C) my_string = 'You''re so close!'

  • D) my_string = "You\\'re so close"

  • E) my_string = 'You're so close!'

#my_string = "You're so close!"
#my_string = "You"re so close!"
#my_string = 'You''re so close!'
#my_string = "You\\'re so close!"
#my_string = 'You're so close!'
#my_string

Specific Guidelines - Comments

Out-of-date comments are worse than no comments at all.

Keep your comments up-to-date.

Block comments

  • apply to some (or all) code that follows them

  • are indented to the same level as that code.

  • Each line of a block comment starts with a # and a single space

# 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()
"You're so close!"
# 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()
"You're going to do great!"

Inline comments

  • to be used sparingly

  • to be separated by at least two spaces from the statement

  • start with a # and a single space

# Badness
week_9()#words of encouragement
"You've totally got this!"
# Goodness
week_9()  # words of encouragement
'Remember to take breaks!'

Specific Guidelines - Documentation

  • Write a descriptive docstring for all functions & classes

Note: If you’re borrowing functions from an assignment, you should add documentation to these functions.

Comments within the functions you’ve borrowed noting that you’ve borrowed it as well as a general note in your project description will suffice for attribution.

If you’ve modified/edited the code from the assignment, state that you modified.

Linters

A linter is a tool that analyzes code for both programmatic errors and stylistic issues.

pylint is available from Anaconda to check this for you. (Not available on datahub.)

Clicker Question #8

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
  • A) None

  • B) 1 or 2

  • C) 3 or 4

  • D) 5 or 6

  • E) 7 or more

list here

  • not readable for humans; not sure what it’s supposed to do

  • variable naming - improve

  • function name - snake case

  • spacing within list

  • indentation - (red ind)

  • line spacing

  • general spacing overall

# Let's fix this code
def my_function(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
# check using pylint
!pylint linter_example.py
************* Module linter_example
linter_example.py:2:0: C0303: Trailing whitespace (trailing-whitespace)
linter_example.py:3:16: C0326: Exactly one space required after comma
    my_list = [0,1,2,3]
                ^ (bad-whitespace)
linter_example.py:3:18: C0326: Exactly one space required after comma
    my_list = [0,1,2,3]
                  ^ (bad-whitespace)
linter_example.py:3:20: C0326: Exactly one space required after comma
    my_list = [0,1,2,3]
                    ^ (bad-whitespace)
linter_example.py:6:0: W0311: Bad indentation. Found 6 spaces, expected 8 (bad-indentation)
linter_example.py:8:21: C0326: No space allowed before bracket
    for i in my_list [ind:]:
                     ^ (bad-whitespace)
linter_example.py:10:0: C0304: Final newline missing (missing-final-newline)
linter_example.py:1:0: C0111: Missing module docstring (missing-docstring)
linter_example.py:1:0: C0103: Function name "MyFunction" doesn't conform to snake_case naming style (invalid-name)
linter_example.py:1:0: C0111: Missing function docstring (missing-docstring)
linter_example.py:4:21: C0321: More than one statement on a single line (multiple-statements)
linter_example.py:7:4: C0103: Variable name "qq" doesn't conform to snake_case naming style (invalid-name)

------------------------------------
Your code has been rated at -3.33/10