CIS 1100 Style Guide

Just like human languages, programming languages have a particular syntax and grammar. If you make a mistake, you end up with a program that is invalid, or “gibberish.” And just as publishers and periodicals have “house styles” that govern how to indent paragraphs, how many spaces to put after a period, which abbreviations to use or avoid, etc., companies and programming projects also adopt style guidelines.

imagine reading a text where nothing was capitalized,therewasnospacebetweenwordsandaroundpunctuationmarks,andparagraphswereseparatedbyonlyatinyblankspace. The text would preserve its meaning, but be nearly impossible to read. Furthermore, if every article (or every paragraph) in a magazine adhered to a completely different style, it would be almost as confusing. Programming is no different, except that it is far easier to make a syntactically correct program unreadable by using poor or inconsistent style. Good style is essential to programming, and a substantial portion of your homework grade will be based on style.

Programming style generally encompasses how you indent your code, when you put spaces around operators, how you name variables, functions, and classes, and how you document your code. There are many opinions about what constitutes the best style, and most companies and projects adopt their own guidelines to ensure consistency. In CIS 1100, we generally follow the style guidelines described on this page. These are typical of the rules you are likely to encounter elsewhere, but represent a particular set of choices among many possibilities.


Checkstyle Errors

We run an automated style checker on your homework submissions that identifies up some (but not all!) style errors such as missing commas or spaces, extra long lines (over 79 characters), and unnecessary parentheses.

Here is an example of a checkstyle error:

/autograder/source/src/personality_quiz.py:3:9: W291 trailing whitespace

This error says that in the personality_quiz.py file, there is an error on line 3 at character 9. Specifically, there is empty “whitespace” (spacebar or tab characters) left at the end of a line.

There is no excuse for having checkstyle errors in your code. If you submit code with checkstyle errors, you will receive a large point deduction. Note that there are style conventions that are not identified by the automated checker. It your responsibility to ensure your code does not contain these errors.


Blocks of Code and Indentation

A block is any section of code all indented at the same level. The indendation can be done using tabs or spaces, but it is imperative that you remain consistent. We recommend using tabs that consist of four spaces. Codio is set up to do this for you by default.

Each block of code must be indented 4 spaces to the right of its parent block. In the example below, note how we have three blocks of code. The first is not indented at all, the second is indented by four spaces/one tab, and the third is indented by eight spaces/two tabs.

for x in numbers:
    if x > 8:
        print("x is big!")

Indentation has specific semantic meaning in Python: not only is it important for making your code readable, proper indentation is vital for having your code run at all. If Codio automatically indents your code in a way you don’t expect, you have a bug. Usually you are missing a colon or parenthesis somewhere.

We DO NOT ACCEPT blocks of code where both blocks are present on the same line:

# WRONG!
if name == "nosferatu": print("AHH!!")

# Correct.
if name == "nosferatu":
    print("AHH!!")

Variable and Class Names

Variable names and function/method names should follow the snake_case convention. Names should start with a lower-case letter. If the name is a composite of multiple words, each word should be separated by an underscore (_). For example, var is an acceptable name for a variable, and this_is_a_variable_name is also an acceptable name for a variable. The names “thisisallonename” and “thisNameHere” are not acceptable for variables in CIS 1100.

As an exception to the above rule, constant variable names should be all upper-case. Constant variables are variables whose value never changes. Alternatively, think of these as symbolic names for particular values. The canonical example is a variable whose value is 3.14159… This variable would be named PI rather than pi. This convention is also widely accepted.

Variable and function names should be descriptive. Try to name your variables and functions in a way that reflects what they do. Here is an example of both good and bad variable naming.

# Good
department = "cis";
class_number = 1100;
is_programming_fun = True;

# Bad
d = "cis";
xx = 1100;
r = True;

Class names should begin with a capital letter. If the name is made up of multiple words, each word should begin with a capital letter.


Spacing

Use a single space on either side of mathematical operators (+, -, *, /). For example, write x + y, not x+y.

Do not put a space before the square brackets for a list. For example, write [4, 10, 100], not [ 4, 10, 100].

Do not put a space between the colon and the condition or iterable when using if/elif/else, for, or while:

if this < that:

for fruit in basket:

while now is not later:

The spacing around parentheses corresponds to how you would use them in English and math:

  • Put spaces outside the parentheses, but not inside them, when they are used to group mathematical computations. For example, write a + (b + c), not a +(b + c) or a + ( b + c ).
  • Do not put spaces around parentheses when they are part of a function call. For example, write print("hello, world."), not print ("Hello, world.") or print( "Hello, world." ).
  • Use blank lines to separate blocks of code that perform different functionality. There is no hard rule on how to do this; you can break it up as you please. Don’t use uncessary blank space - 1 or 2 empty lines between blocks should suffice.
  • Be consistent in your spacing. Don’t use 1 blank line in some places and 3 in others.

File Headers

Every .py file you submit must start with a file header comparable to the one below. Often times we will provide you a template, but you can also cut and paste from another file or from the example below. Your comment does not have to be formatted identically to this one, but it must start with your name and PennKey (not PennID!), followed by instructions for how to run your program, and a description of what the program does.

"""
Name:  Harry Smith
PennKey: sharry

Execution: python hello_world.py

Prints "Hello, World". By tradition, this is everyone's first program.
"""

Commenting

Please document your code with comments. Comment should be used to quickly and concisely explain what your code is doing to an external reader. There is no hard rule on how many comments should be included. In general you should comment blocks of code, explaining what each block does and also add comments explaining anything complex or confusing.

Please do not comment excessively. Do not put comments where comments are not required. A piece of code like print("cis1100") does not require any explanation. Do not comment for the sake of commenting.

Comments should go above the code they reference. If it doesn’t cause the line to be too long, short comments can go inline with the code they’re referencing. Comments should never be below the code they reference.

# This is a single line comment

Comments can also be left with strings using docstrings.

"""This is a docstring.
Normally they are used at the start of files & functions
to describe the purpose of that file/function.
It's OK to use it as a multiline comment if you want."""

Any TODO comments (including those provided in skeleton code) should be removed before submission.

Please provide function header comments for all of your functions. This allows a reader to understand what the function is supposed to do. A function header comment should describe any inputs to or outputs of the function and provide a short description of what the function does. When describing inputs & outputs, you should specify what types they will have and what the values are supposed to represent. You can use the following template:

"""
Description:

Input:

Output:
"""

For example:

def add_two_numbers(x, y):
    """
    Description: Performs addition of two inputs

    Input:
        x, a number
        y, a number

    Output:
        x + y, a number
    """

Code Efficiency

In general, we don’t worry too much about how efficient your programs are in CIS 1100. It’s more important to have a correctly working program. That said, there are some style requirements related to efficiency:

  1. Avoid obvious code inefficiencies. For example, if you need to look a single element at a known position in a list, don’t use a loop to do it! Just index right to it.

  2. Avoid overly complicated logic; aim to make your code as simple as possible. This includes simplifying boolean expressions and simplifying operations.


Avoiding Bad Patterns

When writing conditionals, never compare the value of a boolean variable or expression to True or False. You can just reference the boolean expression or its negation directly. For example:

my_boolean = True
# GOOD STYLE
if my_boolean:
    ...

if not my_boolean:
    ...

# BAD STYLE
if my_boolean == true:
    ...

if my_boolean == false:
    ...

Where possible, aim to use a for loop instead of a while loop. This is because it’s much easier accidentially introduce a bug when using a while loop.

Do not duplicate code. Instead, write a helper function that contains that code and call the helper function when necessary. If you ever find yourself copying and pasting blocks of code from one part of a program to another, chances are you should be writing a helper function.

Avoid writing redundant code, such as functions you never use.

Any print statements used to debug your code should be commented out or removed when you submit.


Example Code

Below is an example of a short class written with good style.

"""
Name: Harry Smith
PennKey: sharry

Execution: python bouncing_ball.py

Animate a ball bouncing within the boundaries of the PennDraw canvas.
"""

import penndraw as pd
from random import random
pd.set_canvas_size(500, 500)

# Position Variables
ball_pos_x = 0.5
ball_pos_y = 0.5

# Velocity Variables
ball_vel_x = 0.01
ball_vel_y = -0.01
ball_radius = 0.1

while True:
    pd.clear()
    pd.set_pen_color(pd.BLUE)
    pd.filled_rectangle(0.5, 0.25, 0.5, 0.25)
    pd.set_pen_color(pd.RED)
    pd.filled_circle(ball_pos_x, ball_pos_y, ball_radius)

    # Update position using velocity components
    ball_pos_x = ball_pos_x + ball_vel_x
    ball_pos_y = ball_pos_y + ball_vel_y

    """
    Check the ball's position relative to the screen's bounds.
    If it's close enough to the edges, flip the ball's X or Y
    velocity depending on if it's by a vertical or horizontal wall.
    """

    bouncing_bottom = ball_pos_y - ball_radius <= 0 and ball_vel_y <  0
    bouncing_top = ball_pos_y + ball_radius >= 1 and ball_vel_y > 0
    if bouncing_bottom or bouncing_top:
        ball_vel_y *= -1 + (random() - 0.5) * 0.001
    
    bouncing_left = ball_pos_x - ball_radius <= 0 and ball_vel_x <  0
    bouncing_right = ball_pos_x + ball_radius >= 1 and ball_vel_x > 0
    if bouncing_left or bouncing_right:
        ball_vel_x *= -1 + (random() - 0.5) * 0.001

    pd.advance()